Skip to main content

pine_interpreter/
output.rs

1// Output-related types, traits, and implementations
2
3use std::collections::HashMap;
4
5/// Represents a color with RGBA components
6#[derive(Clone, Debug, PartialEq)]
7pub struct Color {
8    pub r: u8, // Red component (0-255)
9    pub g: u8, // Green component (0-255)
10    pub b: u8, // Blue component (0-255)
11    pub t: u8, // Transparency (0-100)
12}
13
14impl Color {
15    pub fn new(r: u8, g: u8, b: u8, t: u8) -> Self {
16        Color { r, g, b, t }
17    }
18}
19
20/// Represents a label drawable object
21#[derive(Clone, Debug)]
22pub struct Label {
23    pub x: f64,
24    pub y: f64,
25    pub text: String,
26    pub xloc: String,
27    pub yloc: String,
28    pub color: Option<Color>,
29    pub style: String,
30    pub textcolor: Option<Color>,
31    pub size: String,
32    pub textalign: String,
33    pub tooltip: Option<String>,
34    pub text_font_family: String,
35}
36
37/// Represents a box drawable object
38/// A `fill(...)` between two plots or hlines.
39#[derive(Clone, Debug)]
40pub struct FillObject {
41    /// Id of the first plot/hline (`None` when it was `na`).
42    pub id1: Option<usize>,
43    /// Id of the second plot/hline.
44    pub id2: Option<usize>,
45    pub color: Option<Color>,
46    pub title: String,
47}
48
49/// Chart-wide settings written by global functions like `bgcolor`/`barcolor`.
50#[derive(Clone, Debug, Default)]
51pub struct GlobalContext {
52    /// Background color (`bgcolor`).
53    pub bgcolor: Option<Color>,
54    /// Price-bar color (`barcolor`).
55    pub barcolor: Option<Color>,
56}
57
58/// An `alertcondition(...)` declaration — a named alert with a message.
59#[derive(Clone, Debug, Default)]
60pub struct AlertCondition {
61    pub title: String,
62    pub message: String,
63}
64
65/// The `indicator(...)` declaration — a script's identity and display settings.
66#[derive(Clone, Debug, Default)]
67pub struct Indicator {
68    pub title: String,
69    pub shorttitle: String,
70    pub overlay: bool,
71    pub format: String,
72    pub precision: Option<i64>,
73    pub timeframe: String,
74}
75
76/// A trend line drawn between two points, `(x1, y1)`–`(x2, y2)`.
77#[derive(Clone, Debug)]
78pub struct LineObject {
79    pub x1: f64,
80    pub y1: f64,
81    pub x2: f64,
82    pub y2: f64,
83    pub xloc: String,
84    pub extend: String,
85    pub color: Option<Color>,
86    pub style: String,
87    pub width: f64,
88}
89
90/// One cell of a [`Table`].
91#[derive(Clone, Debug, Default)]
92pub struct TableCell {
93    pub text: String,
94    pub text_color: Option<Color>,
95    pub bgcolor: Option<Color>,
96    pub text_size: String,
97    pub text_halign: String,
98    pub text_valign: String,
99}
100
101/// A table overlay: a fixed grid of cells anchored to a chart position.
102#[derive(Clone, Debug)]
103pub struct Table {
104    pub position: String,
105    pub columns: usize,
106    pub rows: usize,
107    pub bgcolor: Option<Color>,
108    pub cells: HashMap<(usize, usize), TableCell>,
109}
110
111#[derive(Clone, Debug)]
112pub struct PineBox {
113    pub left: f64,
114    pub top: f64,
115    pub right: f64,
116    pub bottom: f64,
117    pub border_color: Option<Color>,
118    pub border_width: f64,
119    pub border_style: String,
120    pub extend: String,
121    pub xloc: String,
122    pub bgcolor: Option<Color>,
123    pub text: String,
124    pub text_size: f64,
125    pub text_color: Option<Color>,
126    pub text_halign: String,
127    pub text_valign: String,
128    pub text_wrap: String,
129    pub text_font_family: String,
130}
131
132/// Represents a plot output
133#[derive(Clone, Debug, Default)]
134pub struct Plot {
135    pub series: f64,
136    pub title: String,
137    pub color: Option<Color>,
138    pub linewidth: f64,
139    pub style: String,
140    pub trackprice: bool,
141    pub histbase: f64,
142    pub offset: f64,
143    pub join: bool,
144    pub editable: bool,
145    pub show_last: Option<f64>,
146    pub display: String,
147    pub format: Option<String>,
148    pub precision: Option<f64>,
149    pub force_overlay: bool,
150    pub linestyle: String,
151}
152
153/// Represents a plotarrow output
154#[derive(Clone, Debug)]
155pub struct Plotarrow {
156    pub series: f64,
157    pub title: String,
158    pub colorup: Option<Color>,
159    pub colordown: Option<Color>,
160    pub offset: f64,
161    pub minheight: f64,
162    pub maxheight: f64,
163    pub editable: bool,
164    pub show_last: Option<f64>,
165    pub display: String,
166    pub format: Option<String>,
167    pub precision: Option<f64>,
168    pub force_overlay: bool,
169}
170
171/// Represents a plotbar output
172#[derive(Clone, Debug)]
173pub struct Plotbar {
174    pub open: f64,
175    pub high: f64,
176    pub low: f64,
177    pub close: f64,
178    pub title: String,
179    pub color: Option<Color>,
180    pub editable: bool,
181    pub show_last: Option<f64>,
182    pub display: String,
183    pub format: Option<String>,
184    pub precision: Option<f64>,
185    pub force_overlay: bool,
186}
187
188/// Represents a plotcandle output
189#[derive(Clone, Debug)]
190pub struct Plotcandle {
191    pub open: f64,
192    pub high: f64,
193    pub low: f64,
194    pub close: f64,
195    pub title: String,
196    pub color: Option<Color>,
197    pub wickcolor: Option<Color>,
198    pub editable: bool,
199    pub show_last: Option<f64>,
200    pub bordercolor: Option<Color>,
201    pub display: String,
202    pub format: Option<String>,
203    pub precision: Option<f64>,
204    pub force_overlay: bool,
205}
206
207/// Represents a plotchar output
208#[derive(Clone, Debug)]
209pub struct Plotchar {
210    pub series: f64,
211    pub title: String,
212    pub char: String,
213    pub location: String,
214    pub color: Option<Color>,
215    pub offset: f64,
216    pub text: String,
217    pub textcolor: Option<Color>,
218    pub editable: bool,
219    pub size: String,
220    pub show_last: Option<f64>,
221    pub display: String,
222    pub format: Option<String>,
223    pub precision: Option<f64>,
224    pub force_overlay: bool,
225}
226
227/// Represents a plotshape output
228#[derive(Clone, Debug)]
229pub struct Plotshape {
230    pub series: f64,
231    pub title: String,
232    pub style: String,
233    pub location: String,
234    pub color: Option<Color>,
235    pub offset: f64,
236    pub text: String,
237    pub textcolor: Option<Color>,
238    pub editable: bool,
239    pub size: String,
240    pub show_last: Option<f64>,
241    pub display: String,
242    pub format: Option<String>,
243    pub precision: Option<f64>,
244    pub force_overlay: bool,
245}
246
247/// Log level
248#[derive(Debug, Clone, Copy, PartialEq, Eq)]
249pub enum LogLevel {
250    Info,
251    Warning,
252    Error,
253}
254
255/// A log entry with level and message
256#[derive(Debug, Clone)]
257pub struct LogEntry {
258    pub level: LogLevel,
259    pub message: String,
260}
261
262/// The default value of a declared input, preserved with its type so a host can
263/// render the right settings widget.
264#[derive(Debug, Clone, PartialEq)]
265pub enum InputValue {
266    Int(i64),
267    Float(f64),
268    Bool(bool),
269    Str(String),
270    Color(Color),
271}
272
273/// A declared script input (`input.int(...)`, `input.source(...)`, ...).
274///
275/// Recorded into the output so a host can enumerate a script's configurable
276/// settings without executing anything itself. The script still receives the
277/// default value at runtime.
278#[derive(Debug, Clone)]
279pub struct Input {
280    /// Which `input.*` function declared it: `"int"`, `"float"`, `"bool"`,
281    /// `"string"`, `"source"`, `"color"`, `"session"`, `"time"`.
282    pub kind: String,
283    /// Display title (`title` argument), empty when none was given.
284    pub title: String,
285    /// Group the input belongs to (`group` argument), empty when none.
286    pub group: String,
287    /// Default value returned to the script.
288    pub default: InputValue,
289}
290
291/// Base trait for all output implementations
292///
293/// This trait defines the minimal contract that all output types must implement.
294/// Extension traits (LogOutput, PlotOutput, etc.) add additional capabilities.
295pub trait PineOutput: Default + Clone + std::fmt::Debug + 'static {
296    /// Clear all output data for a new iteration
297    fn clear(&mut self);
298}
299
300/// Extension trait for logging output
301pub trait LogOutput: PineOutput {
302    /// Add a log entry with the given level and message
303    fn add_log(&mut self, level: LogLevel, message: String);
304    /// Get all log entries
305    fn get_logs(&self) -> &[LogEntry];
306}
307
308/// Macro to easily implement all output traits by delegating to a base field
309///
310/// # Example
311/// ```ignore
312/// impl_output_traits_delegate!(CustomOutput, base);
313/// ```
314#[macro_export]
315macro_rules! impl_output_traits_delegate {
316    ($type:ty, $field:ident) => {
317        impl $crate::LogOutput for $type {
318            fn add_log(&mut self, level: $crate::LogLevel, message: String) {
319                self.$field.add_log(level, message)
320            }
321            fn get_logs(&self) -> &[$crate::LogEntry] {
322                self.$field.get_logs()
323            }
324        }
325
326        impl $crate::PlotOutput for $type {
327            fn add_plot(&mut self, plot: $crate::Plot) {
328                self.$field.add_plot(plot)
329            }
330            fn plots(&self) -> &[$crate::Plot] {
331                self.$field.plots()
332            }
333            fn add_plotarrow(&mut self, arrow: $crate::Plotarrow) {
334                self.$field.add_plotarrow(arrow)
335            }
336            fn plotarrows(&self) -> &[$crate::Plotarrow] {
337                self.$field.plotarrows()
338            }
339            fn add_plotbar(&mut self, bar: $crate::Plotbar) {
340                self.$field.add_plotbar(bar)
341            }
342            fn plotbars(&self) -> &[$crate::Plotbar] {
343                self.$field.plotbars()
344            }
345            fn add_plotcandle(&mut self, candle: $crate::Plotcandle) {
346                self.$field.add_plotcandle(candle)
347            }
348            fn plotcandles(&self) -> &[$crate::Plotcandle] {
349                self.$field.plotcandles()
350            }
351            fn add_plotchar(&mut self, char: $crate::Plotchar) {
352                self.$field.add_plotchar(char)
353            }
354            fn plotchars(&self) -> &[$crate::Plotchar] {
355                self.$field.plotchars()
356            }
357            fn add_plotshape(&mut self, shape: $crate::Plotshape) {
358                self.$field.add_plotshape(shape)
359            }
360            fn plotshapes(&self) -> &[$crate::Plotshape] {
361                self.$field.plotshapes()
362            }
363        }
364
365        impl $crate::LabelOutput for $type {
366            fn add_label(&mut self, label: $crate::Label) -> usize {
367                self.$field.add_label(label)
368            }
369            fn get_label(&self, id: usize) -> Option<&$crate::Label> {
370                self.$field.get_label(id)
371            }
372            fn get_label_mut(&mut self, id: usize) -> Option<&mut $crate::Label> {
373                self.$field.get_label_mut(id)
374            }
375            fn delete_label(&mut self, id: usize) -> bool {
376                self.$field.delete_label(id)
377            }
378        }
379
380        impl $crate::BoxOutput for $type {
381            fn add_box(&mut self, box_obj: $crate::PineBox) -> usize {
382                self.$field.add_box(box_obj)
383            }
384            fn get_box(&self, id: usize) -> Option<&$crate::PineBox> {
385                self.$field.get_box(id)
386            }
387            fn get_box_mut(&mut self, id: usize) -> Option<&mut $crate::PineBox> {
388                self.$field.get_box_mut(id)
389            }
390            fn delete_box(&mut self, id: usize) -> bool {
391                self.$field.delete_box(id)
392            }
393        }
394
395        impl $crate::InputOutput for $type {
396            fn add_input(&mut self, input: $crate::Input) {
397                self.$field.add_input(input)
398            }
399            fn inputs(&self) -> &[$crate::Input] {
400                self.$field.inputs()
401            }
402        }
403
404        impl $crate::IndicatorOutput for $type {
405            fn set_indicator(&mut self, indicator: $crate::Indicator) {
406                self.$field.set_indicator(indicator)
407            }
408            fn indicator(&self) -> Option<&$crate::Indicator> {
409                self.$field.indicator()
410            }
411        }
412
413        impl $crate::AlertConditionOutput for $type {
414            fn add_alertcondition(&mut self, alert: $crate::AlertCondition) {
415                self.$field.add_alertcondition(alert)
416            }
417            fn alertconditions(&self) -> &[$crate::AlertCondition] {
418                self.$field.alertconditions()
419            }
420        }
421
422        impl $crate::FillOutput for $type {
423            fn add_fill(&mut self, fill: $crate::FillObject) {
424                self.$field.add_fill(fill)
425            }
426            fn fills(&self) -> &[$crate::FillObject] {
427                self.$field.fills()
428            }
429        }
430
431        impl $crate::GlobalOutput for $type {
432            fn set_bgcolor(&mut self, color: Option<$crate::Color>) {
433                self.$field.set_bgcolor(color)
434            }
435            fn set_barcolor(&mut self, color: Option<$crate::Color>) {
436                self.$field.set_barcolor(color)
437            }
438            fn global_context(&self) -> &$crate::GlobalContext {
439                self.$field.global_context()
440            }
441        }
442
443        impl $crate::LineOutput for $type {
444            fn add_line(&mut self, line: $crate::LineObject) -> usize {
445                self.$field.add_line(line)
446            }
447            fn get_line(&self, id: usize) -> Option<&$crate::LineObject> {
448                self.$field.get_line(id)
449            }
450            fn get_line_mut(&mut self, id: usize) -> Option<&mut $crate::LineObject> {
451                self.$field.get_line_mut(id)
452            }
453            fn delete_line(&mut self, id: usize) -> bool {
454                self.$field.delete_line(id)
455            }
456        }
457
458        impl $crate::TableOutput for $type {
459            fn add_table(&mut self, table: $crate::Table) -> usize {
460                self.$field.add_table(table)
461            }
462            fn get_table(&self, id: usize) -> Option<&$crate::Table> {
463                self.$field.get_table(id)
464            }
465            fn get_table_mut(&mut self, id: usize) -> Option<&mut $crate::Table> {
466                self.$field.get_table_mut(id)
467            }
468            fn delete_table(&mut self, id: usize) -> bool {
469                self.$field.delete_table(id)
470            }
471        }
472    };
473}
474
475/// Extension trait for plot-related output
476pub trait PlotOutput: PineOutput {
477    /// Add a plot output
478    fn add_plot(&mut self, plot: Plot);
479    /// Get all plot outputs
480    fn plots(&self) -> &[Plot];
481
482    /// Add a plotarrow output
483    fn add_plotarrow(&mut self, arrow: Plotarrow);
484    /// Get all plotarrow outputs
485    fn plotarrows(&self) -> &[Plotarrow];
486
487    /// Add a plotbar output
488    fn add_plotbar(&mut self, bar: Plotbar);
489    /// Get all plotbar outputs
490    fn plotbars(&self) -> &[Plotbar];
491
492    /// Add a plotcandle output
493    fn add_plotcandle(&mut self, candle: Plotcandle);
494    /// Get all plotcandle outputs
495    fn plotcandles(&self) -> &[Plotcandle];
496
497    /// Add a plotchar output
498    fn add_plotchar(&mut self, char: Plotchar);
499    /// Get all plotchar outputs
500    fn plotchars(&self) -> &[Plotchar];
501
502    /// Add a plotshape output
503    fn add_plotshape(&mut self, shape: Plotshape);
504    /// Get all plotshape outputs
505    fn plotshapes(&self) -> &[Plotshape];
506}
507
508/// Extension trait for label output
509pub trait LabelOutput: PineOutput {
510    /// Add a label and return its ID
511    fn add_label(&mut self, label: Label) -> usize;
512    /// Get a reference to a label by ID
513    fn get_label(&self, id: usize) -> Option<&Label>;
514    /// Get a mutable reference to a label by ID
515    fn get_label_mut(&mut self, id: usize) -> Option<&mut Label>;
516    /// Delete a label by ID and return true if it existed
517    fn delete_label(&mut self, id: usize) -> bool;
518}
519
520/// Extension trait for box output
521pub trait BoxOutput: PineOutput {
522    /// Add a box and return its ID
523    fn add_box(&mut self, box_obj: PineBox) -> usize;
524    /// Get a reference to a box by ID
525    fn get_box(&self, id: usize) -> Option<&PineBox>;
526    /// Get a mutable reference to a box by ID
527    fn get_box_mut(&mut self, id: usize) -> Option<&mut PineBox>;
528    /// Delete a box by ID and return true if it existed
529    fn delete_box(&mut self, id: usize) -> bool;
530}
531
532/// Extension trait for table output
533pub trait TableOutput: PineOutput {
534    /// Add a table and return its ID
535    fn add_table(&mut self, table: Table) -> usize;
536    /// Get a reference to a table by ID
537    fn get_table(&self, id: usize) -> Option<&Table>;
538    /// Get a mutable reference to a table by ID
539    fn get_table_mut(&mut self, id: usize) -> Option<&mut Table>;
540    /// Delete a table by ID and return true if it existed
541    fn delete_table(&mut self, id: usize) -> bool;
542}
543
544/// Extension trait for line output
545pub trait LineOutput: PineOutput {
546    /// Add a line and return its ID
547    fn add_line(&mut self, line: LineObject) -> usize;
548    /// Get a reference to a line by ID
549    fn get_line(&self, id: usize) -> Option<&LineObject>;
550    /// Get a mutable reference to a line by ID
551    fn get_line_mut(&mut self, id: usize) -> Option<&mut LineObject>;
552    /// Delete a line by ID and return true if it existed
553    fn delete_line(&mut self, id: usize) -> bool;
554}
555
556/// Extension trait for recording `fill(...)` areas.
557pub trait FillOutput: PineOutput {
558    fn add_fill(&mut self, fill: FillObject);
559    fn fills(&self) -> &[FillObject];
560}
561
562/// Extension trait for chart-wide globals (`bgcolor`, `barcolor`).
563pub trait GlobalOutput: PineOutput {
564    fn set_bgcolor(&mut self, color: Option<Color>);
565    fn set_barcolor(&mut self, color: Option<Color>);
566    /// The accumulated chart-wide settings.
567    fn global_context(&self) -> &GlobalContext;
568}
569
570/// Extension trait for recording declared alert conditions.
571pub trait AlertConditionOutput: PineOutput {
572    /// Record a declared alert condition.
573    fn add_alertcondition(&mut self, alert: AlertCondition);
574    /// Every alert condition declared so far, in declaration order.
575    fn alertconditions(&self) -> &[AlertCondition];
576}
577
578/// Extension trait for the script's `indicator(...)` declaration.
579pub trait IndicatorOutput: PineOutput {
580    /// Record the indicator declaration (a script has at most one).
581    fn set_indicator(&mut self, indicator: Indicator);
582    /// The declaration, if the script declared one.
583    fn indicator(&self) -> Option<&Indicator>;
584}
585
586/// Extension trait for recording declared inputs
587pub trait InputOutput: PineOutput {
588    /// Record a declared input.
589    fn add_input(&mut self, input: Input);
590    /// Every input declared so far, in declaration order.
591    fn inputs(&self) -> &[Input];
592}
593
594/// Default implementation of PineOutput that supports all features
595#[derive(Default, Clone, Debug)]
596pub struct DefaultPineOutput {
597    /// Label storage for drawable objects
598    labels: HashMap<usize, Label>,
599    /// Next label ID
600    next_label_id: usize,
601    /// Box storage for drawable objects
602    boxes: HashMap<usize, PineBox>,
603    /// Next box ID
604    next_box_id: usize,
605    /// Line storage for drawable objects
606    lines: HashMap<usize, LineObject>,
607    /// Next line ID
608    next_line_id: usize,
609    /// Table storage for drawable objects
610    tables: HashMap<usize, Table>,
611    /// Next table ID
612    next_table_id: usize,
613    /// Plot outputs
614    plots: Vec<Plot>,
615    /// Plotarrow outputs
616    plotarrows: Vec<Plotarrow>,
617    /// Plotbar outputs
618    plotbars: Vec<Plotbar>,
619    /// Plotcandle outputs
620    plotcandles: Vec<Plotcandle>,
621    /// Plotchar outputs
622    plotchars: Vec<Plotchar>,
623    /// Plotshape outputs
624    plotshapes: Vec<Plotshape>,
625    /// Log entries
626    logs: Vec<LogEntry>,
627    /// Declared inputs
628    inputs: Vec<Input>,
629    /// The `indicator(...)` declaration, if any.
630    indicator: Option<Indicator>,
631    /// Chart-wide settings (`bgcolor`, `barcolor`).
632    globals: GlobalContext,
633    /// Declared alert conditions.
634    alertconditions: Vec<AlertCondition>,
635    /// `fill(...)` areas.
636    fills: Vec<FillObject>,
637}
638
639impl PineOutput for DefaultPineOutput {
640    fn clear(&mut self) {
641        self.labels.clear();
642        self.boxes.clear();
643        self.plots.clear();
644        self.plotarrows.clear();
645        self.plotbars.clear();
646        self.plotcandles.clear();
647        self.plotchars.clear();
648        self.plotshapes.clear();
649        self.logs.clear();
650        self.inputs.clear();
651        self.indicator = None;
652        self.globals = GlobalContext::default();
653        self.alertconditions.clear();
654        self.fills.clear();
655        self.lines.clear();
656        self.tables.clear();
657        // Reset ID counters
658        self.next_label_id = 0;
659        self.next_box_id = 0;
660        self.next_line_id = 0;
661        self.next_table_id = 0;
662    }
663}
664
665impl LogOutput for DefaultPineOutput {
666    fn add_log(&mut self, level: LogLevel, message: String) {
667        self.logs.push(LogEntry { level, message });
668    }
669
670    fn get_logs(&self) -> &[LogEntry] {
671        &self.logs
672    }
673}
674
675impl PlotOutput for DefaultPineOutput {
676    fn add_plot(&mut self, plot: Plot) {
677        self.plots.push(plot);
678    }
679
680    fn plots(&self) -> &[Plot] {
681        &self.plots
682    }
683
684    fn add_plotarrow(&mut self, arrow: Plotarrow) {
685        self.plotarrows.push(arrow);
686    }
687
688    fn plotarrows(&self) -> &[Plotarrow] {
689        &self.plotarrows
690    }
691
692    fn add_plotbar(&mut self, bar: Plotbar) {
693        self.plotbars.push(bar);
694    }
695
696    fn plotbars(&self) -> &[Plotbar] {
697        &self.plotbars
698    }
699
700    fn add_plotcandle(&mut self, candle: Plotcandle) {
701        self.plotcandles.push(candle);
702    }
703
704    fn plotcandles(&self) -> &[Plotcandle] {
705        &self.plotcandles
706    }
707
708    fn add_plotchar(&mut self, char: Plotchar) {
709        self.plotchars.push(char);
710    }
711
712    fn plotchars(&self) -> &[Plotchar] {
713        &self.plotchars
714    }
715
716    fn add_plotshape(&mut self, shape: Plotshape) {
717        self.plotshapes.push(shape);
718    }
719
720    fn plotshapes(&self) -> &[Plotshape] {
721        &self.plotshapes
722    }
723}
724
725impl LabelOutput for DefaultPineOutput {
726    fn add_label(&mut self, label: Label) -> usize {
727        let id = self.next_label_id;
728        self.next_label_id += 1;
729        self.labels.insert(id, label);
730        id
731    }
732
733    fn get_label(&self, id: usize) -> Option<&Label> {
734        self.labels.get(&id)
735    }
736
737    fn get_label_mut(&mut self, id: usize) -> Option<&mut Label> {
738        self.labels.get_mut(&id)
739    }
740
741    fn delete_label(&mut self, id: usize) -> bool {
742        self.labels.remove(&id).is_some()
743    }
744}
745
746impl BoxOutput for DefaultPineOutput {
747    fn add_box(&mut self, box_obj: PineBox) -> usize {
748        let id = self.next_box_id;
749        self.next_box_id += 1;
750        self.boxes.insert(id, box_obj);
751        id
752    }
753
754    fn get_box(&self, id: usize) -> Option<&PineBox> {
755        self.boxes.get(&id)
756    }
757
758    fn get_box_mut(&mut self, id: usize) -> Option<&mut PineBox> {
759        self.boxes.get_mut(&id)
760    }
761
762    fn delete_box(&mut self, id: usize) -> bool {
763        self.boxes.remove(&id).is_some()
764    }
765}
766
767impl LineOutput for DefaultPineOutput {
768    fn add_line(&mut self, line: LineObject) -> usize {
769        let id = self.next_line_id;
770        self.next_line_id += 1;
771        self.lines.insert(id, line);
772        id
773    }
774
775    fn get_line(&self, id: usize) -> Option<&LineObject> {
776        self.lines.get(&id)
777    }
778
779    fn get_line_mut(&mut self, id: usize) -> Option<&mut LineObject> {
780        self.lines.get_mut(&id)
781    }
782
783    fn delete_line(&mut self, id: usize) -> bool {
784        self.lines.remove(&id).is_some()
785    }
786}
787
788impl TableOutput for DefaultPineOutput {
789    fn add_table(&mut self, table: Table) -> usize {
790        let id = self.next_table_id;
791        self.next_table_id += 1;
792        self.tables.insert(id, table);
793        id
794    }
795
796    fn get_table(&self, id: usize) -> Option<&Table> {
797        self.tables.get(&id)
798    }
799
800    fn get_table_mut(&mut self, id: usize) -> Option<&mut Table> {
801        self.tables.get_mut(&id)
802    }
803
804    fn delete_table(&mut self, id: usize) -> bool {
805        self.tables.remove(&id).is_some()
806    }
807}
808
809impl InputOutput for DefaultPineOutput {
810    fn add_input(&mut self, input: Input) {
811        self.inputs.push(input);
812    }
813
814    fn inputs(&self) -> &[Input] {
815        &self.inputs
816    }
817}
818
819impl IndicatorOutput for DefaultPineOutput {
820    fn set_indicator(&mut self, indicator: Indicator) {
821        self.indicator = Some(indicator);
822    }
823
824    fn indicator(&self) -> Option<&Indicator> {
825        self.indicator.as_ref()
826    }
827}
828
829impl AlertConditionOutput for DefaultPineOutput {
830    fn add_alertcondition(&mut self, alert: AlertCondition) {
831        self.alertconditions.push(alert);
832    }
833
834    fn alertconditions(&self) -> &[AlertCondition] {
835        &self.alertconditions
836    }
837}
838
839impl FillOutput for DefaultPineOutput {
840    fn add_fill(&mut self, fill: FillObject) {
841        self.fills.push(fill);
842    }
843
844    fn fills(&self) -> &[FillObject] {
845        &self.fills
846    }
847}
848
849impl GlobalOutput for DefaultPineOutput {
850    fn set_bgcolor(&mut self, color: Option<Color>) {
851        self.globals.bgcolor = color;
852    }
853
854    fn set_barcolor(&mut self, color: Option<Color>) {
855        self.globals.barcolor = color;
856    }
857
858    fn global_context(&self) -> &GlobalContext {
859        &self.globals
860    }
861}