
// SPDX-License-Identifier: CC-BY-NC-SA-4.0
//
// Copyright (C) 2026 Bit by Bit Signal Processing LLC (https://bxbsp.com)
//
// This work is placed under the "Creative Commons Attribution
// NonCommercial ShareAlike 4.0 International" license, known
// by the shortened acronym "CC-BY-NC-SA-4.0".
//
// This work is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// A CC-BY-NC-SA-4.0 license allows you to use this work for
// noncommercial purposes so long as attribution is made to the
// original author.  Modified versions of this work may be distributed,
// but only under the same license.  For further details, see the
// Creative Commons License "CC-BY-NC-SA-4.0".
//
// You should have received a copy of the CC-BY-NC-SA-4.0 license
// along with this work. If not, see
// <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
//

//

#ifndef DISPLAYS_HH
#define DISPLAYS_HH


#include "display.hh"

#define SWITCH_VT

class displays : public display, public runnable
{
  const static int MAX_DISPLAYS = 20;

  virtual void run();

#ifdef SWITCH_VT
  static int vt_to_open;
#endif
  
public:

  class local_display* local_displays[MAX_DISPLAYS];
  int                 num_local_displays;

  class web_display*   web_displays;
  
  int            num_panes_per_display;
  
  void           check_for_new_displays();
  
  displays(int num_panes_per_display = 1);
  ~displays();

  virtual void   beginDrawToStatic()  { if(parent) ((display*)parent)->beginDrawToStatic(); }
  virtual void   endDrawToStatic()    { if(parent) ((display*)parent)->endDrawToStatic(); }
  virtual void   clearDrawToStatic()  { if(parent) ((display*)parent)->clearDrawToStatic(); }

  virtual void   touch_recognized_beep();
  virtual void   entry_accepted_beep();
  virtual void   entry_rejected_beep();

  virtual void   pane_change();

  //virtual void   mark_layout_dirty() { layout_dirty = true; if(parent) parent->mark_layout_dirty(); }
  
  void           page_flip();
  void           copy_static_to_drawing();
  virtual bool   draw();

  void           get_and_process_events();

  void           display_inactive_message(display* d);

  virtual void      trash_events_until_release()             { if(parent) ((display*)parent)->trash_events_until_release();      }
  virtual void      trash_events_for_us(long microseconds)   { if(parent) ((display*)parent)->trash_events_for_us(microseconds); }

  virtual bool need_fast_display();

  bool do_event_loop;
  virtual void event_loop();
  virtual void end_inner_event_loop();
  
  //
  // Point, rect, and line drawing functions.
  //
  virtual void   draw_point_no_boundscheck(point p, color c);
  virtual color  get_point_no_boundscheck(point p);

  virtual void   set_text_size(int height_pixels);

  //
  // Text drawing functions.
  //
  // multicolor text uses ASCII x = 10 (0x0A) and up to indicate a switch to color
  // c[x-10].  Flags are in draw_text.hh
  //
  virtual void   draw_text(const char* text, color c, int x, int y, int flags = 0);
  virtual void   draw_multicolored_text(const char* text, int start_color, dt_colors& c, int x, int y, int flags = 0);
  virtual int    calculate_text_width(const char* text);
  virtual int    calculate_text_height(const char* text);

  virtual void   draw_text(const wchar_t* text, color c, int x, int y, int flags = 0);
  virtual void   draw_multicolored_text(const wchar_t* text, int start_color, dt_colors& c, int x, int y, int flags = 0);
  virtual int    calculate_text_width(const wchar_t* text);
  virtual int    calculate_text_height(const wchar_t* text);
  
  virtual void   draw_text(const char16_t* text, color c, int x, int y, int flags = 0);
  virtual void   draw_multicolored_text(const char16_t* text, int start_color, dt_colors& c, int x, int y, int flags = 0);
  virtual int    calculate_text_width(const char16_t* text);
  virtual int    calculate_text_height(const char16_t* text);

  virtual void   draw_text(const char32_t* text, color c, int x, int y, int flags = 0);
  virtual void   draw_multicolored_text(const char32_t* text, int start_color, dt_colors& c, int x, int y, int flags = 0);
  virtual int    calculate_text_width(const char32_t* text);
  virtual int    calculate_text_height(const char32_t* text);

  
  virtual void   draw_svg_from_data(uint8_t* svg_data, int svg_data_length, int offset_x=0, int offset_y=0, int draw_width=0, int draw_height=0);

  virtual void   clear_rect(color c, point corner1, point corner2);
  virtual void   draw_line_known_background(pointf p0, pointf p1, color c, color bg);
  virtual void   draw_line(pointf p0, pointf p1, color c);
  virtual void   draw_line_vertical(point p0, point p1, color c);
  virtual void   draw_line_horizontal(point p0, point p1, color c);
  virtual void   draw_circle(pointf p0, float radius, color c);
  virtual void   draw_triangle(pointf p0, pointf p1, pointf p2, color c);

  virtual void   draw_graph_data(uint32_t     color,
				 int          num_points,
				 float        x_start,
				 float        x_step,
				 float        x_at_left,
				 float        x_at_right,
				 float        y_at_bottom,
				 float        y_at_top,
				 float        x_offset,
				 float        y_offset,
				 float        width,
				 float        height,
				 data_point*  y_data);

  virtual void draw_ephemeral_alert(const char* text, int text_height, color c, color bg);

  void check_for_display_changes();  
};



inline void displays::pane_change()
{
  if(parent)
    ((display*)parent)->pane_change();
}


inline bool displays::draw()
{
  bool result = true;
  check_for_display_changes();

  if(parent)
    result = ((display*)parent)->draw();

  return result;
}

inline void displays::draw_point_no_boundscheck(point p, color c)
{
  if(parent)
    parent->draw_point_no_boundscheck(p, c);
}

inline color displays::get_point_no_boundscheck(point p)
{
  if(parent)
    return parent->get_point_no_boundscheck(p);

  return 0;
}

inline void displays::clear_rect(color c, point corner1, point corner2)
{
  if(parent)
    parent->clear_rect(c, corner1, corner2);
}



inline void displays::draw_text(const char* text, color c, int x, int y, int flags)
{
  if(parent)
    parent->draw_text(text, c, x, y, flags);
}


inline void displays::draw_text(const wchar_t* text, color c, int x, int y, int flags)
{
  if(parent)
    parent->draw_text(text, c, x, y, flags);
}


inline void displays::draw_text(const char16_t* text, color c, int x, int y, int flags)
{
  if(parent)
    parent->draw_text(text, c, x, y, flags);
}


inline void displays::draw_text(const char32_t* text, color c, int x, int y, int flags)
{
  if(parent)
    parent->draw_text(text, c, x, y, flags);
}


inline void displays::draw_multicolored_text(const char* text, int start_color, dt_colors& c, int x, int y, int flags)
{
  if(parent)
    parent->draw_multicolored_text(text, start_color, c, x, y, flags);
}


inline void displays::draw_multicolored_text(const wchar_t* text, int start_color, dt_colors& c, int x, int y, int flags)
{
  if(parent)
    parent->draw_multicolored_text(text, start_color, c, x, y, flags);
}


inline void displays::draw_multicolored_text(const char16_t* text, int start_color, dt_colors& c, int x, int y, int flags)
{
  if(parent)
    parent->draw_multicolored_text(text, start_color, c, x, y, flags);
}


inline void displays::draw_multicolored_text(const char32_t* text, int start_color, dt_colors& c, int x, int y, int flags)
{
  if(parent)
    parent->draw_multicolored_text(text, start_color, c, x, y, flags);
}


inline int  displays::calculate_text_width(const char* text)
{
  if(parent)
    return parent->calculate_text_width(text);

  return 200;
}

inline int  displays::calculate_text_width(const wchar_t* text)
{
  if(parent)
    return parent->calculate_text_width(text);

  return 200;
}

inline int  displays::calculate_text_width(const char16_t* text)
{
  if(parent)
    return parent->calculate_text_width(text);

  return 200;
}

inline int  displays::calculate_text_width(const char32_t* text)
{
  if(parent)
    return parent->calculate_text_width(text);

  return 200;
}


inline int  displays::calculate_text_height(const char* text)
{
  if(parent)
    return parent->calculate_text_height(text);

  return 100;
}

inline int  displays::calculate_text_height(const wchar_t* text)
{
  if(parent)
    return parent->calculate_text_height(text);

  return 100;
}

inline int  displays::calculate_text_height(const char16_t* text)
{
  if(parent)
    return parent->calculate_text_height(text);

  return 100;
}

inline int  displays::calculate_text_height(const char32_t* text)
{
  if(parent)
    return parent->calculate_text_height(text);

  return 100;
}


inline void displays::set_text_size(int height_pixels)
{
  if(parent)
    parent->set_text_size(height_pixels);
}


inline void displays::draw_svg_from_data(uint8_t* svg_data, int svg_data_length, int offset_x, int offset_y, int draw_width, int draw_height)
{
  if(parent)
    parent->draw_svg_from_data(svg_data, svg_data_length, offset_x, offset_y, draw_width, draw_height);
}


inline void displays::draw_line_known_background(pointf p0, pointf p1, color c, color bg)
{
  if(parent)
    parent->draw_line_known_background(p0, p1, c, bg);
}

inline void displays::draw_line(pointf p0, pointf p1, color c)
{
  if(parent)
    parent->draw_line(p0, p1, c);
}

inline void displays::draw_line_vertical(point p0, point p1, color c)
{
  if(parent)
    parent->draw_line_vertical(p0, p1, c);
}

inline void displays::draw_line_horizontal(point p0, point p1, color c)
{
  if(parent)
    parent->draw_line_horizontal(p0, p1, c);
}

inline void displays::draw_circle(pointf p0, float radius, color c)
{
  if(parent)
    parent->draw_circle(p0, radius, c);
}


inline void displays::draw_triangle(pointf p0, pointf p1, pointf p2, color c)
{
  if(parent)
    parent->draw_triangle(p0, p1, p2, c);
}

inline void displays::touch_recognized_beep()
{
  if(parent)
    ((display*)parent)->touch_recognized_beep();
}

inline void displays::entry_accepted_beep()
{
  if(parent)
    ((display*)parent)->entry_accepted_beep();
}

inline void displays::entry_rejected_beep()
{
  if(parent)
    ((display*)parent)->entry_rejected_beep();
}


inline void displays::draw_graph_data(uint32_t     color,
				      int          num_points,
				      float        x_start,
				      float        x_step,
				      float        x_at_left,
				      float        x_at_right,
				      float        y_at_bottom,
				      float        y_at_top,
				      float        x_offset,
				      float        y_offset,
				      float        width,
				      float        height,
				      data_point*  y_data)
{
  if(parent)
    {
      ((display*)parent)->draw_graph_data ( color,
					    num_points,
					    x_start,
					    x_step,
					    x_at_left,
					    x_at_right,
					    y_at_bottom,
					    y_at_top,
					    x_offset,
					    y_offset,
					    width,
					    height,
					    y_data);
    }
}
  
  
inline void displays::draw_ephemeral_alert(const char* text, int text_height, color c, color bg)
{
  if(parent)
    ((display*)parent)->draw_ephemeral_alert(text, text_height, c, bg);
}

  
#endif

