1pub mod auxiliary_bar;
8pub mod background;
9pub mod crosshair;
10pub mod current_price;
11pub mod grid;
12pub mod indicators;
13pub mod price_axis;
14pub mod range_bar;
15pub mod region_shading;
16pub mod time_axis;
17pub mod watermark;
18
19pub use auxiliary_bar::AuxiliaryBarLayer;
21pub use background::BackgroundLayer;
22pub use crosshair::CrosshairLayer;
23pub use current_price::{CurrentPriceConfig, CurrentPriceLayer, LineStyle};
24pub use grid::GridLayer;
25pub use indicators::band::{BandConfig, BandLayer};
26pub use indicators::line_series::{LineSeriesConfig, LineSeriesLayer};
27pub use price_axis::PriceAxisLayer;
28pub use range_bar::{RangeBarConfig, RangeBarLayer, RangeBarStyle};
29pub use region_shading::{RegionBoundary, RegionShadingLayer, ShadingRegion};
30pub use time_axis::TimeAxisLayer;
31pub use watermark::{WatermarkConfig, WatermarkLayer};
32
33pub use auxiliary_bar::VolumeLayer;
35pub use range_bar::{CandlestickConfig, CandlestickLayer};
36pub use region_shading::SessionShadingLayer;
37
38use crate::data::ChartData;
39use crate::error::Result;
40use crate::renderer::RenderContext;
41use crate::style::ChartStyle;
42use crate::theme::ChartTheme;
43use crate::viewport::{Rect, Viewport};
44
45#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
51pub enum LayerStage {
52 ScreenBackground,
54 ChartBackground,
56 ChartUnderlay,
58 ChartMain,
60 ChartIndicator,
62 VolumePane,
64 ChartOverlay,
66 PriceAxis,
68 TimeAxis,
70 Hud,
72}
73
74impl LayerStage {
75 pub fn default_clip_rect(self, viewport: &Viewport) -> Rect {
77 match self {
78 LayerStage::ScreenBackground => viewport.screen_rect,
79 LayerStage::ChartBackground
80 | LayerStage::ChartUnderlay
81 | LayerStage::ChartMain
82 | LayerStage::ChartIndicator
83 | LayerStage::ChartOverlay => viewport.chart_content_rect(),
84 LayerStage::VolumePane => viewport.volume_rect(),
85 LayerStage::PriceAxis => viewport.price_axis_rect(),
86 LayerStage::TimeAxis => viewport.time_axis_rect(),
87 LayerStage::Hud => viewport.screen_rect,
88 }
89 }
90}
91
92pub trait Layer: Send + Sync {
98 fn name(&self) -> &str;
100
101 fn update(
106 &mut self,
107 data: &ChartData,
108 viewport: &Viewport,
109 theme: &ChartTheme,
110 style: &ChartStyle,
111 );
112
113 fn stage(&self) -> LayerStage {
115 LayerStage::ChartMain
116 }
117
118 fn clip_rect(&self, viewport: &Viewport) -> Rect {
123 self.stage().default_clip_rect(viewport)
124 }
125
126 fn render(&self, context: &mut RenderContext, render_pass: &mut wgpu::RenderPass)
131 -> Result<()>;
132
133 fn needs_render(&self) -> bool {
138 true }
140
141 fn z_order(&self) -> i32 {
146 0 }
148
149 fn is_enabled(&self) -> bool {
151 true }
153
154 fn set_enabled(&mut self, enabled: bool);
156
157 fn get_config(&self) -> serde_json::Value {
161 serde_json::Value::Null }
163
164 fn set_config(&mut self, _config: serde_json::Value) -> Result<()> {
166 Ok(()) }
168}
169
170pub struct LayerManager {
172 layers: Vec<Box<dyn Layer>>,
173 dirty: bool,
174}
175
176impl LayerManager {
177 pub fn new() -> Self {
179 Self {
180 layers: Vec::new(),
181 dirty: true,
182 }
183 }
184
185 pub fn add_layer(&mut self, layer: Box<dyn Layer>) {
187 self.layers.push(layer);
188 self.sort_layers();
189 self.dirty = true;
190 }
191
192 pub fn remove_layer(&mut self, name: &str) -> Option<Box<dyn Layer>> {
194 if let Some(index) = self.layers.iter().position(|layer| layer.name() == name) {
195 self.dirty = true;
196 Some(self.layers.remove(index))
197 } else {
198 None
199 }
200 }
201
202 pub fn get_layer_mut(&mut self, name: &str) -> Option<&mut (dyn Layer + '_)> {
204 for layer in &mut self.layers {
205 if layer.name() == name {
206 return Some(&mut **layer);
207 }
208 }
209 None
210 }
211
212 pub fn get_layer(&self, name: &str) -> Option<&dyn Layer> {
214 self.layers
215 .iter()
216 .find(|layer| layer.name() == name)
217 .map(|layer| layer.as_ref())
218 }
219
220 pub fn update_all(
222 &mut self,
223 data: &ChartData,
224 viewport: &Viewport,
225 theme: &ChartTheme,
226 style: &ChartStyle,
227 ) {
228 for layer in &mut self.layers {
229 if layer.is_enabled() {
230 layer.update(data, viewport, theme, style);
231 }
232 }
233 self.dirty = true;
234 }
235
236 pub fn render_all(
238 &self,
239 context: &mut RenderContext,
240 render_pass: &mut wgpu::RenderPass,
241 ) -> Result<()> {
242 for layer in &self.layers {
243 if layer.is_enabled() && layer.needs_render() {
244 #[cfg(feature = "text-rendering")]
246 {
247 let stage_priority = (layer.stage() as i32) * 1000 + layer.z_order();
248 context.set_stage_priority(stage_priority);
249 }
250
251 let clip_rect = {
252 let viewport = context.viewport();
253 layer.clip_rect(viewport)
254 };
255
256 let x = clip_rect.x.max(0.0) as u32;
258 let y = clip_rect.y.max(0.0) as u32;
259 let width = clip_rect.width.max(0.0) as u32;
260 let height = clip_rect.height.max(0.0) as u32;
261
262 render_pass.set_scissor_rect(x, y, width, height);
263
264 layer.render(context, render_pass)?;
265 context.commit(render_pass)?;
266 }
267 }
268 let full_rect = context.viewport().screen_rect;
270 render_pass.set_scissor_rect(
271 full_rect.x as u32,
272 full_rect.y as u32,
273 full_rect.width as u32,
274 full_rect.height as u32,
275 );
276 Ok(())
277 }
278
279 pub fn needs_render(&self) -> bool {
281 self.dirty
282 || self
283 .layers
284 .iter()
285 .any(|layer| layer.is_enabled() && layer.needs_render())
286 }
287
288 pub fn mark_clean(&mut self) {
290 self.dirty = false;
291 }
292
293 pub fn layer_count(&self) -> usize {
295 self.layers.len()
296 }
297
298 pub fn enabled_layer_count(&self) -> usize {
300 self.layers
301 .iter()
302 .filter(|layer| layer.is_enabled())
303 .count()
304 }
305
306 pub fn layer_names(&self) -> Vec<&str> {
308 self.layers.iter().map(|layer| layer.name()).collect()
309 }
310
311 pub fn set_layer_enabled(&mut self, name: &str, enabled: bool) -> bool {
313 if let Some(layer) = self.get_layer_mut(name) {
314 layer.set_enabled(enabled);
315 self.dirty = true;
316 true
317 } else {
318 false
319 }
320 }
321
322 pub fn clear(&mut self) {
324 self.layers.clear();
325 self.dirty = true;
326 }
327
328 fn sort_layers(&mut self) {
330 use std::cmp::Ordering;
331
332 self.layers.sort_by(|a, b| match a.stage().cmp(&b.stage()) {
333 Ordering::Equal => a.z_order().cmp(&b.z_order()),
334 other => other,
335 });
336 }
337}
338
339impl Default for LayerManager {
340 fn default() -> Self {
341 Self::new()
342 }
343}
344
345pub trait LayerBuilder {
347 fn basic_range_chart() -> LayerManager {
349 let mut manager = LayerManager::new();
350
351 manager.add_layer(Box::new(BackgroundLayer::new()));
353 manager.add_layer(Box::new(RegionShadingLayer::new()));
354 manager.add_layer(Box::new(GridLayer::new()));
355 manager.add_layer(Box::new(RangeBarLayer::new()));
356 manager.add_layer(Box::new(AuxiliaryBarLayer::new()));
357
358 let mut price_config = CurrentPriceConfig::default();
359 price_config.line_style = LineStyle::Dashed;
360 price_config.line_width = 1.0;
361 manager.add_layer(Box::new(CurrentPriceLayer::with_config(price_config)));
362 manager.add_layer(Box::new(PriceAxisLayer::new()));
363 manager.add_layer(Box::new(TimeAxisLayer::new()));
364 manager.add_layer(Box::new(CrosshairLayer::new()));
365
366 manager
367 }
368
369 fn basic_financial_chart() -> LayerManager {
371 Self::basic_range_chart()
372 }
373
374 fn chart_with_watermark(label: String) -> LayerManager {
376 let mut manager = Self::basic_range_chart();
377 manager.add_layer(Box::new(WatermarkLayer::new(label)));
378 manager
379 }
380}
381
382impl LayerBuilder for LayerManager {}
383
384#[cfg(test)]
385mod tests {
386 use super::*;
387 use crate::theme::ChartTheme;
388 use crate::viewport::Viewport;
389
390 struct MockLayer {
392 name: String,
393 enabled: bool,
394 z_order: i32,
395 stage: LayerStage,
396 render_count: std::sync::Arc<std::sync::Mutex<u32>>,
397 }
398
399 impl MockLayer {
400 fn new(name: &str, z_order: i32) -> Self {
401 Self::with_stage(name, z_order, LayerStage::ChartMain)
402 }
403
404 fn with_stage(name: &str, z_order: i32, stage: LayerStage) -> Self {
405 Self {
406 name: name.to_string(),
407 enabled: true,
408 z_order,
409 stage,
410 render_count: std::sync::Arc::new(std::sync::Mutex::new(0)),
411 }
412 }
413 }
414
415 impl Layer for MockLayer {
416 fn name(&self) -> &str {
417 &self.name
418 }
419
420 fn update(
421 &mut self,
422 _data: &ChartData,
423 _viewport: &Viewport,
424 _theme: &ChartTheme,
425 _style: &ChartStyle,
426 ) {
427 }
429
430 fn stage(&self) -> LayerStage {
431 self.stage
432 }
433
434 fn render(
435 &self,
436 _context: &mut RenderContext,
437 _render_pass: &mut wgpu::RenderPass,
438 ) -> Result<()> {
439 *self.render_count.lock().unwrap() += 1;
440 Ok(())
441 }
442
443 fn z_order(&self) -> i32 {
444 self.z_order
445 }
446
447 fn is_enabled(&self) -> bool {
448 self.enabled
449 }
450
451 fn set_enabled(&mut self, enabled: bool) {
452 self.enabled = enabled;
453 }
454 }
455
456 #[test]
457 fn test_layer_manager_basic_operations() {
458 let mut manager = LayerManager::new();
459 assert_eq!(manager.layer_count(), 0);
460
461 manager.add_layer(Box::new(MockLayer::new("layer1", 1)));
463 manager.add_layer(Box::new(MockLayer::new("layer2", 0)));
464 manager.add_layer(Box::new(MockLayer::new("layer3", 2)));
465
466 assert_eq!(manager.layer_count(), 3);
467 assert_eq!(manager.enabled_layer_count(), 3);
468
469 let names = manager.layer_names();
471 assert_eq!(names, vec!["layer2", "layer1", "layer3"]); }
473
474 #[test]
475 fn test_layer_enable_disable() {
476 let mut manager = LayerManager::new();
477 manager.add_layer(Box::new(MockLayer::new("test", 0)));
478
479 assert_eq!(manager.enabled_layer_count(), 1);
480
481 manager.set_layer_enabled("test", false);
482 assert_eq!(manager.enabled_layer_count(), 0);
483
484 manager.set_layer_enabled("test", true);
485 assert_eq!(manager.enabled_layer_count(), 1);
486 }
487
488 #[test]
489 fn test_layer_removal() {
490 let mut manager = LayerManager::new();
491 manager.add_layer(Box::new(MockLayer::new("remove_me", 0)));
492 manager.add_layer(Box::new(MockLayer::new("keep_me", 1)));
493
494 assert_eq!(manager.layer_count(), 2);
495
496 let removed = manager.remove_layer("remove_me");
497 assert!(removed.is_some());
498 assert_eq!(manager.layer_count(), 1);
499
500 let not_found = manager.remove_layer("not_found");
501 assert!(not_found.is_none());
502 }
503
504 #[test]
505 fn test_stage_sorting() {
506 let mut manager = LayerManager::new();
507 manager.add_layer(Box::new(MockLayer::with_stage("hud", 0, LayerStage::Hud)));
508 manager.add_layer(Box::new(MockLayer::with_stage(
509 "background",
510 0,
511 LayerStage::ScreenBackground,
512 )));
513 manager.add_layer(Box::new(MockLayer::with_stage(
514 "indicator",
515 0,
516 LayerStage::ChartIndicator,
517 )));
518
519 let names = manager.layer_names();
520 assert_eq!(names, vec!["background", "indicator", "hud"]);
521 }
522}