/** 
 *  Yudit Unicode Editor Source File
 *
 *  GNU Copyright (C) 1997-2023  Gaspar Sinai <gaspar@yudit.org>  
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License, version 2,
 *  dated June 1991. See file COPYYING for details.
 *
 *  This program 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.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#include "swidget/SLayout.h"
#include <stdio.h>

SLayout::SLayout (void) : lc(0,0), rc(0,0), dlc(0,0), drc(0,0)
{
}

/**
 * The layout looks like this:
 * lc-------------+
 * |              |
 * |              |
 * +-------------rc
 * When resize happens the lc is moved by dlc *(lc-newlc)
 * so these are deltas. The unit for deltas are 1000, so resizing
 * by unit 1 is achieved by 100.
 * Example a component that has a minimum size of 100 and grows 
 * twice when resized:
 * lc.x lc.y  rc.y  rc.y  dlc.x dlc.y  drc.x drc.y
 * 0,   0,    10,   10     0,   0      100,  100
 * it will also move down if:
 * 0,   0,    10,   10     0,   100    100,  100
 * it will also move right if:
 * 0,   0,    10,   10     100,  0     100,  100
 */
SLayout::SLayout (const SLocation& _lc, const SLocation _rc,
       const  SLocation& _dlc, const SLocation _drc) : 
  lc (_lc), rc (_rc), dlc(_dlc), drc(_drc)
{
}

SLayout::SLayout (const SLocation& _lc, const SLocation _rc) 
   : lc (_lc), rc (_rc)
{
  dlc = SLocation (100, 100);
  drc = SLocation (100, 100);
}

SLayout::SLayout (const SDimension& _rc) : rc (_rc)
{
  lc = SLocation (0, 0);
  dlc = SLocation (100, 100);
  drc = SLocation (100, 100);
}

/**
 * copy the layout.
 */
SLayout::SLayout (const SLayout& l)
{
  lc = l.lc;
  rc = l.rc;
  dlc = l.dlc;
  drc = l.drc;
}
SLayout
SLayout::operator = (const SLayout& l)
{
  lc = l.lc;
  rc = l.rc;
  dlc = l.dlc;
  drc = l.drc;
  return *this;
}

SLayout::~SLayout ()
{
}

/**
 * Add layout to this to make a bigger layout.
 */
SLayout
SLayout::operator += (const SLayout l)
{
  if (l.rc.x > rc.x) rc.x = l.rc.x;
  if (l.rc.y > rc.y) rc.y = l.rc.y;
  return *this;
}

bool
SLayout::isEmpty() const
{
  return (lc == rc && rc == drc && drc == dlc && dlc == SLocation(0,0));
}

/**
 * This is in fact the minimum size.
 */
SDimension
SLayout::getDimension () const
{
  SLocation delta = rc - lc;
  if (delta.x < 0) delta.x = 2;
  if (delta.y < 0) delta.y = 2;
  return SDimension (delta.x, delta.y);
}

/**
 * This is in fact the minimum size.
 */
SLocation
SLayout::getLocation () const
{
  SLocation min = lc;
  return SLocation (min.minmerge(rc));
}

/**
 * Suppose in is the parent layout. we are resized.
 * @return the new location of this child component.
 */ 
SLocation 
SLayout::getLocation (const SLayout& parent, const SDimension& d) const
{
  SLocation l(d.width, d.height);
  SLocation delta = l - (parent.rc-parent.lc);
//fprintf (stderr, "dim=%u,%u delta=%d,%d parent=%d,%d\n", 
 //    d.width, d.height,
  //    delta.x, delta.y, parent.rc.x, parent.rc.y);
  SLocation lnew (lc.x + (delta.x * dlc.x) / 100, 
      lc.y + (delta.y * dlc.y) / 100);
/*
 NEW
  if (lnew.x < lc.x) lnew.x = lc.x;
  if (lnew.y < lc.y) lnew.y = lc.y;
*/
  return SLocation (lnew);
}

void SLayout::print()
{
  fprintf (stderr, "Layout lc=%d %d / %d%% %d%%\n", lc.x, lc.y, dlc.x, dlc.y);
  fprintf (stderr, "Layout rc=%d %d / %d%% %d%%\n", rc.x, rc.y, drc.x, drc.y);
}

/**
 * Suppose in is the parent layout. we are resized.
 * @return the new dimension of this child component.
 */ 
SDimension 
SLayout::getDimension (const SLayout& parent, const SDimension& d) const
{
  SLocation l(d.width, d.height);
  SLocation delta = l - (parent.rc - parent.lc);
  SLocation lnew (rc.x + (delta.x * drc.x) / 100, 
     rc.y + (delta.y * drc.y) / 100);
/*
 NEW
  if (lnew.x <= rc.x) lnew.x = rc.x +1;
  if (lnew.y <= rc.y) lnew.y = rc.y +1;
*/
  SLocation left = getLocation (parent, d);
  if (lnew.x <= left.x) lnew.x = left.x+1;
  if (lnew.y <= left.y) lnew.y = left.y+1;
  return SDimension (lnew.x - left.x, lnew.y - left.y);
}
bool
SLayout::operator == (const SLayout l) const
{
  return (lc == l.lc && rc == l.rc && dlc == l.dlc && drc == l.drc);
}

bool
SLayout::operator != (const SLayout l) const
{
  return (lc != l.lc || rc != l.rc || dlc != l.dlc || drc != l.drc);
}

/**
 * Accept the layout. This layout has to change.
 * becomes this size.
 * We should not call this with an empty layout.
 * @param old is the layout this layout was attached to.
 * @param nl is the layout this layout will be attached to.
 */
void
SLayout::setLayout (const SLayout& old, const SLayout& nl)
{
  if (old.isEmpty() || nl.isEmpty()) return;
  SDimension d = getDimension (old, nl.getDimension());
  SLocation l = getLocation (old, nl.getDimension());
  lc = l;
  rc = l + SLocation (d);
}
