
// 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/>.
//

#include "multiwindow.hh"


multiwindow::multiwindow(color bg) : window(bg)
{
  subwindows = new List<window>;
  layout_calculator = new layout_plan;

  num_subwindows = 0;

  target_aspect_x = 3;
  target_aspect_y = 2;
  force_aspect = false;
}


multiwindow::~multiwindow()
{
  delete subwindows;
  delete layout_calculator;
}


void multiwindow::update_data()
{
  for(ListElement<window>* le=subwindows->first(); le; le=le->next())
    {
      le->data()->update_data();
    }
}


void multiwindow::draw_dynamic()
{
  for(ListElement<window>* le=subwindows->first(); le; le=le->next())
    {
      le->data()->draw_dynamic();
    }
}


void multiwindow::layout()
{
  int xmargin = 10;
  int ymargin = 10;

  clear(bgcolor);

  //printf("target_aspect_x=%d, target_aspect_y=%d\n", target_aspect_x, target_aspect_y);
  
  layout_calculator->do_layout(0, 0,
			       width, height,
			       xmargin, ymargin,
			       *subwindows,
			       target_aspect_x,
			       target_aspect_y,
			       force_aspect);
  
  layout_dirty = false;
  dirty = true;
}

void multiwindow::draw_dirty()
{
  if(dirty)
    {
      for(ListElement<window>* le=subwindows->first(); le; le=le->next())
	{
	  window* w = le->data();
	  if(w->layout_dirty)
	    w->layout();
	  if(w->dirty)
	    w->draw_dirty();
	}
    }
}

int multiwindow::get_selected_y_offset()
{
  if(parent)
    return parent->get_selected_y_offset();
  else
    return 0;
}


bool multiwindow::handle_event(my_event& me)
{
  //printf("in multiwindow::handle_event %p\n", this);
  int xoff = 0;
  int yoff = 0;
  window* p = this;
  while(p)
    {
      xoff += p->offset.x;
      yoff += p->offset.y;
      p = p->parent;
    }
  
  for(ListElement<window>* le=subwindows->last(); le; le=le->previous())
    {
      window* w = le->data();
      int x = me.c[0].x - xoff - w->offset.x;
      int y = me.c[0].y - yoff - w->offset.y;
      
      if((x>0 && x<w->width && y>0 && y<w->height) || me.type == EVENT_KEY_PRESS || me.type == EVENT_KEY_RELEASE || me.type == EVENT_KEY_HOLD)
	{      
	  bool handled = w->handle_event(me);
	  if(handled)
	    {
	      //printf("Window at screen offset (%d,%d) (%dx%d) claimed event.\n", xoff + w->offset.x, yoff + w->offset.y, w->width, w->height);
	      return true;
	    }
	}
    } 

  return false;
}




void multiwindow::add(window* win, bool stealthy)
{
  if(win->parent)
    {
      printf("Re-adding window already added.\n");
      abort();
    }

  bool autodelete = true;
  
  subwindows->addAtEnd(win, autodelete);
  num_subwindows++;
  win->parent = this;

  if(!stealthy)
    mark_layout_dirty();
}



void multiwindow::remove(window* win)
{
  if(subwindows->isInList(win))
    {
      subwindows->remove(win);
      num_subwindows--;
      mark_layout_dirty();
      return;
    }

  // If we get here, didn't find the window.
  
  // If it wasn't there, it might have been removed without informing us.
  // So don't cause a problem.
  //printf("ERROR: Removing a window that's not on any screen of the multiwindow.\n");
  //abort();
}



//
// remove_no_delete is called, for example, by windows that are children
// of this multiwindow that are in the process of deleting themselves.
// we don't want to delete them twice.
//
void multiwindow::remove_no_delete(window* win)
{
  if(subwindows->isInList(win))
    {
      subwindows->extract(win);
      num_subwindows--;
      mark_layout_dirty();
      win->parent = 0;
      return;
    }

  // If we get here, didn't find the window.
  
  // If it wasn't there, it might have been removed without informing us.
  // So don't cause a problem.
  //printf("ERROR: Removing a window that's not on any screen of the multiwindow.\n");
  //abort();
}



void multiwindow::remove_all()
{
  subwindows->remove_all();

  num_subwindows = 0;
  mark_layout_dirty();
}


void multiwindow::change_layout(layout_plan* new_layout)
{
  delete layout_calculator;
  layout_calculator = new_layout;
}

