Переглянути джерело

chore: move some layout configs to the main state, `State`
-- instead of storing some configs on each layout, keep it on the main state and pass it to `view()`, so child states can use them when they need

Berke 9 місяців тому
батько
коміт
11fe61600b

+ 2 - 4
src/charts.rs

@@ -310,6 +310,7 @@ fn view_chart<'a, T: Chart, I: Indicator>(
     chart: &'a T, 
     indicators: &'a [I], 
     ticker_info: Option<TickerInfo>,
+    timezone: &'a UserTimezone,
 ) -> Element<'a, Message> {
     let chart_state = chart.get_common_data();
 
@@ -329,7 +330,7 @@ fn view_chart<'a, T: Chart, I: Indicator>(
         crosshair: chart_state.crosshair,
         timeframe: chart_state.timeframe as u32,
         cell_width: chart_state.cell_width,
-        timezone: &chart_state.timezone,
+        timezone,
         chart_bounds: chart_state.bounds,
     })
     .width(Length::Fill)
@@ -451,8 +452,6 @@ pub struct CommonChartData {
     cell_height: f32,
 
     base_range: f32,
-
-    timezone: UserTimezone,
     last_price: Option<PriceInfoLabel>,
 
     base_price_y: f32,
@@ -473,7 +472,6 @@ impl Default for CommonChartData {
             cache: Caches::default(),
             crosshair: true,
             translation: Vector::default(),
-            timezone: UserTimezone::default(),
             bounds: Rectangle::default(),
             last_price: None,
             base_range: 1.0,

+ 28 - 36
src/charts/candlestick.rs

@@ -1,3 +1,4 @@
+use std::collections::hash_map::Entry;
 use std::collections::{BTreeMap, HashMap};
 
 use iced::widget::canvas::{LineDash, Path, Stroke};
@@ -7,11 +8,11 @@ use iced::widget::{canvas::{self, Event, Geometry}, column};
 
 use crate::data_providers::TickerInfo;
 use crate::layout::SerializableChartData;
-use crate::screen::UserTimezone;
 use crate::data_providers::{
     fetcher::{FetchRange, RequestHandler},
     Kline, OpenInterest as OIData, Timeframe
 };
+use crate::screen::UserTimezone;
 
 use super::scales::PriceInfoLabel;
 use super::indicators::{self, CandlestickIndicator, Indicator};
@@ -108,7 +109,6 @@ impl CandlestickChart {
         klines_raw: Vec<Kline>,
         timeframe: Timeframe,
         tick_size: f32,
-        timezone: UserTimezone,
         enabled_indicators: &[CandlestickIndicator],
     ) -> CandlestickChart {
         let mut loading_chart = true;
@@ -146,7 +146,6 @@ impl CandlestickChart {
                 latest_x,
                 timeframe: timeframe.to_milliseconds(),
                 tick_size,
-                timezone,
                 crosshair: layout.crosshair,
                 indicators_split: layout.indicators_split,
                 decimals: count_decimals(tick_size),
@@ -182,11 +181,6 @@ impl CandlestickChart {
         self.chart.loading_chart = loading;
     }
 
-    pub fn change_timezone(&mut self, timezone: UserTimezone) {
-        let chart = self.get_common_data_mut();
-        chart.timezone = timezone;
-    }
-
     pub fn get_tick_size(&self) -> f32 {
         self.chart.tick_size
     }
@@ -299,7 +293,7 @@ impl CandlestickChart {
                 data.extend(volume_data.clone());
             };
 
-        if klines_raw.len() >= 1 {
+        if !klines_raw.is_empty() {
             self.request_handler.mark_completed(req_id);
         } else {
             self.request_handler
@@ -315,7 +309,7 @@ impl CandlestickChart {
 
     pub fn insert_open_interest(&mut self, req_id: Option<uuid::Uuid>, oi_data: Vec<OIData>) {
         if let Some(req_id) = req_id {
-            if oi_data.len() >= 1 {
+            if !oi_data.is_empty() {
                 self.request_handler.mark_completed(req_id);
                 self.fetching_oi = false; 
             } else {
@@ -391,35 +385,32 @@ impl CandlestickChart {
         self.chart.get_chart_layout()
     }
 
-    pub fn toggle_indicator(&mut self, indicator: CandlestickIndicator) {
-        if self.indicators.contains_key(&indicator) {
-            self.indicators.remove(&indicator);
-        } else {
-            match indicator {
-                CandlestickIndicator::Volume => {
-                    let volume_data = self.data_points.iter()
-                        .map(|(time, kline)| (*time, (kline.volume.0, kline.volume.1)))
-                        .collect();
-
-                    self.indicators.insert(
-                        indicator,
+    pub fn toggle_indicator(&mut self, indicator: CandlestickIndicator) {    
+        match self.indicators.entry(indicator) {
+            Entry::Occupied(entry) => {
+                entry.remove();
+            }
+            Entry::Vacant(entry) => {
+                let data = match indicator {
+                    CandlestickIndicator::Volume => {
+                        let volume_data = self.data_points.iter()
+                            .map(|(time, kline)| (*time, (kline.volume.0, kline.volume.1)))
+                            .collect();
                         IndicatorData::Volume(Caches::default(), volume_data)
-                    );
-                },
-                CandlestickIndicator::OpenInterest => {
-                    self.indicators.insert(
-                        indicator,
+                    },
+                    CandlestickIndicator::OpenInterest => {
+                        self.fetching_oi = false;
                         IndicatorData::OpenInterest(Caches::default(), BTreeMap::new())
-                    );
-                    self.fetching_oi = false;
+                    }
+                };
+                entry.insert(data);
+    
+                if self.chart.indicators_split.is_none() {
+                    self.chart.indicators_split = Some(0.8);
                 }
             }
-
-            if self.chart.indicators_split.is_none() {
-                self.chart.indicators_split = Some(0.8);
-            }
         }
-
+    
         if self.indicators.is_empty() {
             self.chart.indicators_split = None;
         }
@@ -489,9 +480,10 @@ impl CandlestickChart {
     pub fn view<'a, I: Indicator>(
         &'a self, 
         indicators: &'a [I], 
-        ticker_info: Option<TickerInfo>
+        ticker_info: Option<TickerInfo>,
+        timezone: &'a UserTimezone,
     ) -> Element<Message> {
-        view_chart(self, indicators, ticker_info)
+        view_chart(self, indicators, ticker_info, timezone)
     }
 }
 

+ 29 - 37
src/charts/footprint.rs

@@ -1,3 +1,4 @@
+use std::collections::hash_map::Entry;
 use std::collections::{BTreeMap, HashMap};
 
 use iced::widget::canvas::{LineDash, Path, Stroke};
@@ -8,11 +9,11 @@ use ordered_float::OrderedFloat;
 
 use crate::data_providers::TickerInfo;
 use crate::layout::SerializableChartData;
-use crate::screen::UserTimezone;
 use crate::data_providers::{
     fetcher::{FetchRange, RequestHandler},
     Kline, Timeframe, Trade, OpenInterest as OIData,
 };
+use crate::screen::UserTimezone;
 
 use super::scales::PriceInfoLabel;
 use super::indicators::{self, FootprintIndicator, Indicator};
@@ -113,7 +114,6 @@ impl FootprintChart {
         tick_size: f32,
         klines_raw: Vec<Kline>,
         raw_trades: Vec<Trade>,
-        timezone: UserTimezone,
         enabled_indicators: &[FootprintIndicator],
     ) -> Self {
         let mut loading_chart = true;
@@ -180,7 +180,6 @@ impl FootprintChart {
                 latest_x,
                 timeframe: timeframe.to_milliseconds(),
                 tick_size,
-                timezone,
                 decimals: count_decimals(tick_size),
                 crosshair: layout.crosshair,
                 indicators_split: layout.indicators_split,
@@ -351,11 +350,6 @@ impl FootprintChart {
         self.chart.already_fetching = false;
     }
 
-    pub fn change_timezone(&mut self, timezone: UserTimezone) {
-        let chart = self.get_common_data_mut();
-        chart.timezone = timezone;
-    }
-
     pub fn get_raw_trades(&self) -> Vec<Trade> {
         self.raw_trades.clone()
     }
@@ -535,7 +529,7 @@ impl FootprintChart {
                 data.extend(volume_data.clone());
             };
 
-        if klines_raw.len() >= 1 {
+        if !klines_raw.is_empty() {
             self.request_handler.mark_completed(req_id);
         } else {
             self.request_handler
@@ -551,7 +545,7 @@ impl FootprintChart {
 
     pub fn insert_open_interest(&mut self, req_id: Option<uuid::Uuid>, oi_data: Vec<OIData>) {
         if let Some(req_id) = req_id {
-            if oi_data.len() >= 1 {
+            if !oi_data.is_empty() {
                 self.request_handler.mark_completed(req_id);
                 self.fetching_oi = false;
             } else {
@@ -626,35 +620,32 @@ impl FootprintChart {
         });
     }
 
-    pub fn toggle_indicator(&mut self, indicator: FootprintIndicator) {
-        if self.indicators.contains_key(&indicator) {
-            self.indicators.remove(&indicator);
-        } else {
-            match indicator {
-                FootprintIndicator::Volume => {
-                    let data = self.data_points.iter()
-                        .map(|(time, (_, kline))| (*time, (kline.volume.0, kline.volume.1)))
-                        .collect();
-
-                    self.indicators.insert(
-                        indicator,
-                        IndicatorData::Volume(Caches::default(), data)
-                    );
-                },
-                FootprintIndicator::OpenInterest => {
-                    self.indicators.insert(
-                        indicator,
+    pub fn toggle_indicator(&mut self, indicator: FootprintIndicator) {    
+        match self.indicators.entry(indicator) {
+            Entry::Occupied(entry) => {
+                entry.remove();
+            }
+            Entry::Vacant(entry) => {
+                let data = match indicator {
+                    FootprintIndicator::Volume => {
+                        let volume_data = self.data_points.iter()
+                            .map(|(time, (_, kline))| (*time, (kline.volume.0, kline.volume.1)))
+                            .collect();
+                        IndicatorData::Volume(Caches::default(), volume_data)
+                    },
+                    FootprintIndicator::OpenInterest => {
+                        self.fetching_oi = false;
                         IndicatorData::OpenInterest(Caches::default(), BTreeMap::new())
-                    );
-                    self.fetching_oi = false;
+                    }
+                };
+                entry.insert(data);
+    
+                if self.chart.indicators_split.is_none() {
+                    self.chart.indicators_split = Some(0.8);
                 }
             }
-
-            if self.chart.indicators_split.is_none() {
-                self.chart.indicators_split = Some(0.8);
-            }
         }
-
+    
         if self.indicators.is_empty() {
             self.chart.indicators_split = None;
         }
@@ -722,9 +713,10 @@ impl FootprintChart {
     pub fn view<'a, I: Indicator>(
         &'a self, 
         indicators: &'a [I], 
-        ticker_info: Option<TickerInfo>
+        ticker_info: Option<TickerInfo>,
+        timezone: &'a UserTimezone,
     ) -> Element<Message> {
-        view_chart(self, indicators, ticker_info)
+        view_chart(self, indicators, ticker_info, timezone)
     }
 }
 

+ 12 - 25
src/charts/heatmap.rs

@@ -1,4 +1,4 @@
-use std::{cmp::Ordering, collections::{BTreeMap, HashMap}};
+use std::{cmp::Ordering, collections::{hash_map::Entry, BTreeMap, HashMap}};
 
 use iced::{
     mouse, theme::palette::Extended, Alignment, Color, Element, 
@@ -6,11 +6,8 @@ use iced::{
 };
 use iced::widget::canvas::{self, Event, Geometry, Path};
 
-use crate::{data_providers::TickerInfo, layout::SerializableChartData};
-use crate::{
-    data_providers::{Depth, Trade},
-    screen::UserTimezone,
-};
+use crate::{data_providers::TickerInfo, layout::SerializableChartData, screen::UserTimezone};
+use crate::data_providers::{Depth, Trade};
 
 use super::indicators::{HeatmapIndicator, Indicator};
 use super::{Chart, ChartConstants, CommonChartData, Interaction, Message};
@@ -244,7 +241,6 @@ impl HeatmapChart {
         layout: SerializableChartData, 
         tick_size: f32, 
         aggr_time: i64, 
-        timezone: UserTimezone, 
         enabled_indicators: &[HeatmapIndicator]
     ) -> Self {
         HeatmapChart {
@@ -254,7 +250,6 @@ impl HeatmapChart {
                 timeframe: aggr_time as u64,
                 tick_size,
                 decimals: count_decimals(tick_size),
-                timezone,
                 crosshair: layout.crosshair,
                 indicators_split: layout.indicators_split,
                 ..Default::default()
@@ -393,11 +388,6 @@ impl HeatmapChart {
         self.chart.get_chart_layout()
     }
 
-    pub fn change_timezone(&mut self, timezone: UserTimezone) {
-        let chart = self.get_common_data_mut();
-        chart.timezone = timezone;
-    }
-
     pub fn change_tick_size(&mut self, new_tick_size: f32) {
         let chart_state = self.get_common_data_mut();
 
@@ -412,16 +402,12 @@ impl HeatmapChart {
     }
 
     pub fn toggle_indicator(&mut self, indicator: HeatmapIndicator) {
-        if self.indicators.contains_key(&indicator) {
-            self.indicators.remove(&indicator);
-        } else {
-            match indicator {
-                HeatmapIndicator::Volume => {
-                    self.indicators.insert(
-                        indicator,
-                        IndicatorData::Volume,
-                    );
-                },
+        match self.indicators.entry(indicator) {
+            Entry::Occupied(entry) => {
+                entry.remove();
+            }
+            Entry::Vacant(entry) => {
+                entry.insert(IndicatorData::Volume);
             }
         }
     }
@@ -505,9 +491,10 @@ impl HeatmapChart {
     pub fn view<'a, I: Indicator>(
         &'a self, 
         indicators: &'a [I], 
-        ticker_info: Option<TickerInfo>
+        ticker_info: Option<TickerInfo>,
+        timezone: &'a UserTimezone,
     ) -> Element<Message> {
-        view_chart(self, indicators, ticker_info)
+        view_chart(self, indicators, ticker_info, timezone)
     }
 }
 

+ 2 - 1
src/charts/timeandsales.rs

@@ -2,6 +2,7 @@ use chrono::DateTime;
 use iced::{alignment, padding, Element, Length};
 use iced::widget::{column, container, responsive, row, text, Space};
 use crate::screen::dashboard::pane::Message;
+use crate::screen::UserTimezone;
 use crate::style::ts_table_container;
 use crate::data_providers::Trade;
 
@@ -71,7 +72,7 @@ impl TimeAndSales {
         }
     }
 
-    pub fn view(&self) -> Element<'_, Message> {
+    pub fn view(&self, _timezone: &UserTimezone) -> Element<'_, Message> {
         responsive(move |size| {
             let mut column = column![]
                 .padding(padding::top(4).left(4).right(4))

+ 1 - 1
src/data_providers/binance.rs

@@ -769,7 +769,7 @@ pub async fn fetch_ticksize(market_type: MarketType) -> Result<HashMap<Ticker, O
             .as_str()
             .ok_or_else(|| StreamError::ParseError("Missing symbol".to_string()))?;
 
-        if !re.is_match(&symbol_str) {
+        if !re.is_match(symbol_str) {
             continue;
         }
         

+ 0 - 3
src/layout.rs

@@ -401,7 +401,6 @@ pub fn load_saved_state(file_path: &str) -> SavedState {
                                         vec![],
                                         timeframe,
                                         ticker_info.min_ticksize,
-                                        UserTimezone::default(),
                                         &indicators,
                                     ),
                                     indicators,
@@ -433,7 +432,6 @@ pub fn load_saved_state(file_path: &str) -> SavedState {
                                         tick_size,
                                         vec![],
                                         vec![],
-                                        UserTimezone::default(),
                                         &indicators,
                                     ),
                                     indicators,
@@ -463,7 +461,6 @@ pub fn load_saved_state(file_path: &str) -> SavedState {
                                         layout,
                                         tick_size,
                                         100,
-                                        UserTimezone::default(),
                                         &indicators,
                                     ),
                                     indicators,

+ 26 - 18
src/main.rs

@@ -144,6 +144,8 @@ struct State {
     show_tickers_dashboard: bool,
     tickers_table: TickersTable,
     confirmation_dialog: Option<String>,
+    layout_locked: bool,
+    timezone: UserTimezone,
 }
 
 #[allow(dead_code)]
@@ -199,6 +201,8 @@ impl State {
                 sidebar_location: saved_state.sidebar,
                 tickers_table: TickersTable::new(saved_state.favorited_tickers),
                 confirmation_dialog: None,
+                layout_locked: false,
+                timezone: saved_state.timezone,
             },
             open_main_window
                 .then(|_| Task::none())
@@ -264,10 +268,8 @@ impl State {
                 }
             }
             Message::ToggleLayoutLock => {
-                let dashboard = self.get_mut_dashboard(self.last_active_layout);
-
-                dashboard.layout_lock = !dashboard.layout_lock;
-                dashboard.focus = None;
+                self.layout_locked = !self.layout_locked;
+                self.get_mut_dashboard(self.last_active_layout).focus = None;
             }
             Message::WindowEvent(event) => match event {
                 WindowEvent::CloseRequested(window) => {
@@ -324,11 +326,6 @@ impl State {
                     .find(|(id, _)| **id == self.main_window.id)
                     .map(|(_, (position, _))| *position);
 
-                let user_tz = {
-                    let dashboard = self.get_dashboard(self.last_active_layout);
-                    dashboard.get_timezone()
-                };
-
                 let layout = layout::SerializableState::from_parts(
                     layouts,
                     self.theme.clone(),
@@ -336,7 +333,7 @@ impl State {
                     self.last_active_layout,
                     size,
                     position,
-                    user_tz,
+                    self.timezone,
                     self.sidebar_location,
                 );
 
@@ -390,7 +387,11 @@ impl State {
                 )
                 .then(|_: Task<window::Id>| Task::none());
 
-                return window_tasks.chain(dashboard.reset_layout().map(Message::Dashboard));
+                return window_tasks.chain(
+                    dashboard
+                        .reset_layout()
+                        .map(Message::Dashboard)
+                    );
             }
             Message::LayoutSelected(new_layout_id) => {
                 let active_popout_keys = self
@@ -478,9 +479,7 @@ impl State {
                 }
             }
             Message::SetTimezone(tz) => {
-                self.layouts.values_mut().for_each(|dashboard| {
-                    dashboard.set_timezone(self.main_window.id, tz);
-                });
+                self.timezone = tz;
             }
             Message::SidebarPosition(pos) => {
                 self.sidebar_location = pos;
@@ -507,7 +506,12 @@ impl State {
         if id != self.main_window.id {
             return container(
                 dashboard
-                .view_window(id, &self.main_window)
+                .view_window(
+                    id, 
+                    &self.main_window, 
+                    self.layout_locked,
+                    &self.timezone,
+                )
                 .map(Message::Dashboard)
             )
             .padding(padding::top(if cfg!(target_os = "macos") { 20 } else { 0 }))
@@ -524,7 +528,7 @@ impl State {
                     let layout_lock_button = {
                         create_button(
                             get_icon_text(
-                                if dashboard.layout_lock {
+                                if self.layout_locked {
                                     Icon::Locked
                                 } else {
                                     Icon::Unlocked
@@ -634,7 +638,11 @@ impl State {
             };
 
             let dashboard_view = dashboard
-                .view(&self.main_window)
+                .view(
+                    &self.main_window, 
+                    self.layout_locked,
+                    &self.timezone,
+                )
                 .map(Message::Dashboard);
 
             let base = column![
@@ -710,7 +718,7 @@ impl State {
         
                         let timezone_picklist = pick_list(
                             [UserTimezone::Utc, UserTimezone::Local],
-                            Some(dashboard.get_timezone()),
+                            Some(self.timezone),
                             Message::SetTimezone,
                         );
 

+ 16 - 36
src/screen/dashboard.rs

@@ -17,7 +17,8 @@ use crate::{
 };
 
 use super::{
-    create_notis_column, modal::dashboard_notification, DashboardError, Notification,
+    create_notis_column, modal::dashboard_notification, 
+    DashboardError, Notification,
     NotificationManager, UserTimezone,
 };
 
@@ -85,11 +86,9 @@ pub struct Dashboard {
     pub panes: pane_grid::State<PaneState>,
     pub focus: Option<(window::Id, pane_grid::Pane)>,
     pub popout: HashMap<window::Id, (pane_grid::State<PaneState>, (Point, Size))>,
-    pub layout_lock: bool,
     pub pane_streams: HashMap<Exchange, HashMap<Ticker, HashSet<StreamType>>>,
     notification_manager: NotificationManager,
     tickers_info: HashMap<Exchange, HashMap<Ticker, Option<TickerInfo>>>,
-    timezone: UserTimezone,
     pub trade_fetch_enabled: bool,
 }
 
@@ -104,12 +103,10 @@ impl Dashboard {
         Self {
             panes: pane_grid::State::with_configuration(Self::default_pane_config()),
             focus: None,
-            layout_lock: false,
             pane_streams: HashMap::new(),
             notification_manager: NotificationManager::new(),
             tickers_info: HashMap::new(),
             popout: HashMap::new(),
-            timezone: UserTimezone::default(),
             trade_fetch_enabled: false,
         }
     }
@@ -182,12 +179,10 @@ impl Dashboard {
         Self {
             panes,
             focus: None,
-            layout_lock: false,
             pane_streams: HashMap::new(),
             notification_manager: NotificationManager::new(),
             tickers_info: HashMap::new(),
             popout,
-            timezone: UserTimezone::default(),
             trade_fetch_enabled,
         }
     }
@@ -240,7 +235,6 @@ impl Dashboard {
             Message::ResetLayout => {
                 self.panes = pane_grid::State::with_configuration(Self::default_pane_config());
                 self.focus = None;
-                self.layout_lock = false;
                 (self.popout, self.pane_streams) = (HashMap::new(), HashMap::new());
             }
             Message::SavePopoutSpecs(specs) => {
@@ -349,8 +343,6 @@ impl Dashboard {
                             Task::done(Message::ErrorOccurred(window, Some(pane), err))
                         };
 
-                        let timezone = self.timezone;
-
                         let ticker_info = match self.get_ticker_info(&pane_stream) {
                             Some(info) => info,
                             None => {
@@ -365,7 +357,6 @@ impl Dashboard {
                             if let Err(err) = pane_state.set_content(
                                 ticker_info,
                                 &content_str, 
-                                timezone
                             ) {
                                 return err_occurred(err);
                             }
@@ -470,12 +461,10 @@ impl Dashboard {
                 match klines {
                     Ok(klines) => {
                         if let StreamType::Kline { timeframe, .. } = pane_stream {
-                            let timezone = self.timezone;
-
                             if let Some(pane_state) =
                                 self.get_mut_pane(main_window.id, window, pane_id)
                             {
-                                pane_state.insert_klines_vec(req_id, timeframe, &klines, timezone);
+                                pane_state.insert_klines_vec(req_id, timeframe, &klines);
                             }
                         }
                     }
@@ -539,8 +528,6 @@ impl Dashboard {
                 Ok(klines) => {
                     let mut inserted_panes = vec![];
 
-                    let timezone = self.timezone;
-
                     self.iter_all_panes_mut(main_window.id)
                         .for_each(|(window, pane, state)| {
                             if state.matches_stream(&stream_type) {
@@ -553,7 +540,6 @@ impl Dashboard {
                                                 klines.clone(),
                                                 timeframe,
                                                 tick_size,
-                                                timezone,
                                                 indicators,
                                             );
                                         }
@@ -566,7 +552,6 @@ impl Dashboard {
                                                 tick_size,
                                                 klines.clone(),
                                                 raw_trades,
-                                                timezone,
                                                 indicators,
                                             );
                                         }
@@ -964,12 +949,16 @@ impl Dashboard {
             }))
     }
 
-    pub fn view<'a>(&'a self, main_window: &'a Window) -> Element<'_, Message> {
+    pub fn view<'a>(
+        &'a self, 
+        main_window: &'a Window, 
+        layout_locked: bool,
+        timezone: &'a UserTimezone,
+    ) -> Element<'_, Message> {
         let focus = self.focus;
-        let pane_locked = self.layout_lock;
 
         let mut pane_grid = PaneGrid::new(&self.panes, |id, pane, maximized| {
-            let is_focused = !pane_locked && focus == Some((main_window.id, id));
+            let is_focused = !layout_locked && focus == Some((main_window.id, id));
             pane.view(
                 id,
                 self.panes.len(),
@@ -977,13 +966,14 @@ impl Dashboard {
                 maximized,
                 main_window.id,
                 main_window,
+                timezone,
                 self.notification_manager.get(&main_window.id, &id),
             )
         })
         .spacing(6)
         .style(style::pane_grid);
 
-        if !pane_locked {
+        if !layout_locked {
             pane_grid = pane_grid
                 .on_click(pane::Message::PaneClicked)
                 .on_resize(8, pane::Message::PaneResized)
@@ -1010,6 +1000,8 @@ impl Dashboard {
         &'a self,
         window: window::Id,
         main_window: &'a Window,
+        layout_locked: bool,
+        timezone: &'a UserTimezone,
     ) -> Element<'a, Message> {
         if let Some((state, _)) = self.popout.get(&window) {
             let content = container({
@@ -1022,11 +1014,12 @@ impl Dashboard {
                         false,
                         window,
                         main_window,
+                        timezone,
                         self.notification_manager.get(&window, &id),
                     )
                 });
 
-                if !self.layout_lock {
+                if !layout_locked {
                     pane_grid = pane_grid.on_click(pane::Message::PaneClicked);
                 }
                 pane_grid
@@ -1412,19 +1405,6 @@ impl Dashboard {
 
         pane_streams
     }
-
-    pub fn get_timezone(&self) -> UserTimezone {
-        self.timezone
-    }
-
-    pub fn set_timezone(&mut self, main_window: window::Id, timezone: UserTimezone) {
-        self.timezone = timezone;
-
-        self.iter_all_panes_mut(main_window)
-            .for_each(|(_, _, pane)| {
-                pane.content.change_timezone(timezone);
-            });
-    }
 }
 
 fn get_oi_fetch_task(

+ 21 - 29
src/screen/dashboard/pane.rs

@@ -11,7 +11,7 @@ use crate::{
         indicators::{CandlestickIndicator, FootprintIndicator, HeatmapIndicator, Indicator}, 
         timeandsales::TimeAndSales
     }, data_providers::{format_with_commas, Exchange, Kline, MarketType, OpenInterest, TickMultiplier, Ticker, TickerInfo, Timeframe}, layout::SerializableChartData, screen::{
-        self, create_button, modal::{pane_menu, pane_notification}, DashboardError, InfoType, Notification, UserTimezone
+        self, create_button, modal::{pane_menu, pane_notification}, DashboardError, InfoType, Notification, UserTimezone,
     }, style::{self, get_icon_text, Icon}, window::{self, Window}, StreamType
 };
 
@@ -169,7 +169,6 @@ impl PaneState {
         &mut self, 
         ticker_info: TickerInfo,
         content_str: &str, 
-        timezone: UserTimezone,
     ) -> Result<(), DashboardError> {
         self.content = match content_str {
             "heatmap" => {
@@ -188,7 +187,6 @@ impl PaneState {
                         },
                         tick_size,
                         100,
-                        timezone,
                         &enabled_indicators,
                     ),
                     enabled_indicators,
@@ -221,7 +219,6 @@ impl PaneState {
                         tick_size,
                         vec![],
                         vec![],
-                        timezone,
                         &enabled_indicators,
                     ),
                     enabled_indicators,
@@ -254,7 +251,6 @@ impl PaneState {
                         vec![],
                         timeframe,
                         tick_size,
-                        timezone,
                         &enabled_indicators,
                     ),
                     enabled_indicators,
@@ -293,7 +289,6 @@ impl PaneState {
         req_id: Option<uuid::Uuid>,
         timeframe: Timeframe,
         klines: &Vec<Kline>,
-        timezone: UserTimezone,
     ) {
         match &mut self.content {
             PaneContent::Candlestick(chart, indicators) => {
@@ -308,7 +303,6 @@ impl PaneState {
                         klines.clone(), 
                         timeframe, 
                         tick_size, 
-                        timezone,
                         indicators,
                     );
                 }
@@ -326,7 +320,6 @@ impl PaneState {
                         tick_size,
                         klines.clone(),
                         raw_trades,
-                        timezone,
                         indicators,
                     );
                 }
@@ -345,6 +338,7 @@ impl PaneState {
         maximized: bool,
         window: window::Id,
         main_window: &'a Window,
+        timezone: &'a UserTimezone,
         notifications: Option<&'a Vec<screen::Notification>>,
     ) -> pane_grid::Content<'a, Message, Theme, Renderer> {
         let mut stream_info_element = row![]
@@ -432,13 +426,13 @@ impl PaneState {
             PaneContent::Starter => 
                 center(text("select a ticker to start").size(16)).into(),
             PaneContent::Heatmap(content, indicators) => 
-                view_chart(id, self, content, notifications, indicators),
+                view_chart(id, self, content, notifications, indicators, timezone),
             PaneContent::Footprint(content, indicators) => 
-                view_chart(id, self, content, notifications, indicators),
+                view_chart(id, self, content, notifications, indicators, timezone),
             PaneContent::Candlestick(content, indicators) => 
-                view_chart(id, self, content, notifications, indicators),
+                view_chart(id, self, content, notifications, indicators, timezone),
             PaneContent::TimeAndSales(content) => 
-                view_panel(id, self, content, notifications),
+                view_panel(id, self, content, notifications, timezone),
         })
         .style(move |theme| style::pane_primary(theme, is_focused));
 
@@ -470,6 +464,7 @@ trait ChartView {
         state: &'a PaneState, 
         indicators: &'a [I],
         notifications: Option<&'a Vec<screen::Notification>>,
+        timezone: &'a UserTimezone,
     ) -> Element<Message>;
 }
 
@@ -545,9 +540,10 @@ impl ChartView for HeatmapChart {
         state: &'a PaneState,
         indicators: &'a [I],
         notifications: Option<&'a Vec<screen::Notification>>,
+        timezone: &'a UserTimezone,
     ) -> Element<Message> {
         let underlay = self
-            .view(indicators, state.settings.ticker_info)
+            .view(indicators, state.settings.ticker_info, timezone)
             .map(move |message| Message::ChartUserUpdate(pane, message));
 
         let settings_view = || {
@@ -576,9 +572,10 @@ impl ChartView for FootprintChart {
         state: &'a PaneState,
         indicators: &'a [I],
         notifications: Option<&'a Vec<screen::Notification>>,
+        timezone: &'a UserTimezone,
     ) -> Element<Message> {
         let underlay = self
-            .view(indicators, state.settings.ticker_info)
+            .view(indicators, state.settings.ticker_info, timezone)
             .map(move |message| Message::ChartUserUpdate(pane, message));
 
         let settings_view = || {
@@ -607,9 +604,10 @@ impl ChartView for CandlestickChart {
         state: &'a PaneState,
         indicators: &'a [I],
         notifications: Option<&'a Vec<screen::Notification>>,
+        timezone: &'a UserTimezone,
     ) -> Element<Message> {
         let underlay = self
-            .view(indicators, state.settings.ticker_info)
+            .view(indicators, state.settings.ticker_info, timezone)
             .map(move |message| Message::ChartUserUpdate(pane, message));
             
         let settings_view = || {
@@ -634,16 +632,17 @@ impl ChartView for CandlestickChart {
 /// 
 /// e.g. Time&Sales pane
 trait PanelView {
-    fn view(&self, pane: pane_grid::Pane, state: &PaneState) -> Element<Message>;
+    fn view(&self, pane: pane_grid::Pane, state: &PaneState, timezone: &UserTimezone) -> Element<Message>;
 }
 
 impl PanelView for TimeAndSales {
     fn view(
         &self, 
         pane: pane_grid::Pane, 
-        state: &PaneState, 
+        state: &PaneState,
+        timezone: &UserTimezone,
     ) -> Element<Message> {
-        let underlay = self.view();
+        let underlay = self.view(timezone);
 
         match state.modal {
             PaneModal::Settings => {
@@ -899,8 +898,9 @@ fn view_panel<'a, C: PanelView>(
     state: &'a PaneState,
     content: &'a C,
     notifications: Option<&'a Vec<screen::Notification>>,
+    timezone: &'a UserTimezone,
 ) -> Element<'a, Message> {
-    let base = center(content.view(pane, state));
+    let base = center(content.view(pane, state, timezone));
 
     if let Some(notifications) = notifications {
         pane_notification(
@@ -921,8 +921,9 @@ fn view_chart<'a, C: ChartView, I: Indicator>(
     content: &'a C,
     notifications: Option<&'a Vec<screen::Notification>>,
     indicators: &'a [I],
+    timezone: &'a UserTimezone,
 ) -> Element<'a, Message> {
-    content.view(pane, state, indicators, notifications)
+    content.view(pane, state, indicators, notifications, timezone)
 }
 
 // Pane controls, title bar
@@ -1015,15 +1016,6 @@ pub enum PaneContent {
 }
 
 impl PaneContent {
-    pub fn change_timezone(&mut self, timezone: UserTimezone) {
-        match self {
-            PaneContent::Heatmap(chart, _) => chart.change_timezone(timezone),
-            PaneContent::Footprint(chart, _) => chart.change_timezone(timezone),
-            PaneContent::Candlestick(chart, _) => chart.change_timezone(timezone),
-            _ => {}
-        }
-    }
-
     pub fn toggle_indicator(&mut self, indicator_str: String) {
         match self {
             PaneContent::Heatmap(chart, indicators) => {