/* acontainer.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2004-2024 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "acontainer.h"
#include "awindow.h"
#include "guielement.h"
#include "ascaler.h"

AContainer::AContElem::AContElem()
{
  _widelem = NULL;
  Cont = NULL;
  Width = Height = 0;
  MinWidth = MaxWidth = MinHeight = MaxHeight = -1;
  AutosizeMode = ACONT_NONE;
  WWeight = HWeight = 1;
  NoResize = false;
  m_center = CENTER_NONE;
}

Widget *AContainer::AContElem::widelem() const
{
  return _widelem;
}

AContainer *AContainer::AContElem::cont() const
{
  return Cont;
}

void AContainer::AContElem::widelem( Widget *newelem )
{
  _widelem = newelem;
  Cont = NULL;
}

void AContainer::AContElem::cont( AContainer *newcont )
{
  _widelem = NULL;
  Cont = newcont;
}

int AContainer::AContElem::width() const
{
  return Width;
}

void AContainer::AContElem::width( int nv )
{
  if ( nv >= 0 ) Width = nv;
}

int AContainer::AContElem::height() const
{
  return Height;
}

void AContainer::AContElem::height( int nv )
{
  if ( nv >= 0 ) Height = nv;
}

int AContainer::AContElem::minWidth() const
{
  return MinWidth;
}

void AContainer::AContElem::minWidth( int nv )
{
  MinWidth = nv;
  if ( MinWidth < -1 ) MinWidth = -1;
}

int AContainer::AContElem::maxWidth() const
{
  return MaxWidth;
}

void AContainer::AContElem::maxWidth( int nv )
{
  MaxWidth = nv;
  if ( MaxWidth < -1 ) MaxWidth = -1;
}

int AContainer::AContElem::minHeight() const
{
  return MinHeight;
}

void AContainer::AContElem::minHeight( int nv )
{
  MinHeight = nv;
  if ( MinHeight < -1 ) MinHeight = -1;
}

int AContainer::AContElem::maxHeight() const
{
  return MaxHeight;
}

void AContainer::AContElem::maxHeight( int nv )
{
  MaxHeight = nv;
  if ( MaxHeight < -1 ) MaxHeight = -1;
}

int AContainer::AContElem::autosizeMode() const
{
  return AutosizeMode;
}

void AContainer::AContElem::autosizeMode( int nv )
{
  AutosizeMode = nv & ( ACONT_MAXW | ACONT_MAXH | ACONT_MINW | ACONT_MINH );
}

int AContainer::AContElem::wWeight() const
{
  return WWeight;
}

void AContainer::AContElem::wWeight( int nv )
{
  WWeight = nv;
  if ( WWeight < 1 ) WWeight = 1;
}

int AContainer::AContElem::hWeight() const
{
  return HWeight;
}

void AContainer::AContElem::hWeight( int nv )
{
  HWeight = nv;
  if ( HWeight < 1 ) HWeight = 1;
}

bool AContainer::AContElem::noResize() const
{
  return NoResize;
}

void AContainer::AContElem::noResize( bool nv )
{
  NoResize = nv;
}

enum AContainer::AContElem::acont_elem_center_mode AContainer::AContElem::center() const
{
    return m_center;
}

void AContainer::AContElem::center( enum acont_elem_center_mode nv )
{
    m_center = nv;
}

AContainer::AContainer( AWindow *twin, int txelems, int tyelems )
{
  win = twin;
  xelems = txelems;
  if ( xelems < 1 ) xelems = 1;
  yelems = tyelems;
  if ( yelems < 1 ) yelems = 1;

  elements = new AContElem [xelems*yelems];
  parent = NULL;
  x = y = width = height = 0;
  BorderWidth = 5;
  MinSpace = 5;
  MaxSpace = -1;
  ergWidths = ergHeights = NULL;

  old_rearrange_width = old_rearrange_height = 0;

  m_move_infos.resize( xelems * yelems );
  m_resize_infos.resize( xelems * yelems );
  m_rearrange_infos.resize( xelems * yelems );
}

AContainer::AContainer( AWindow *twin,
                        int txelems,
                        int tyelems,
                        int border_width,
                        int min_space,
                        int max_space )
{
    win = twin;
    xelems = txelems;
    if ( xelems < 1 ) xelems = 1;
    yelems = tyelems;
    if ( yelems < 1 ) yelems = 1;
    
    elements = new AContElem[ xelems * yelems ];
    parent = NULL;
    x = y = width = height = 0;

    BorderWidth = border_width;
    if ( BorderWidth < 0 ) BorderWidth = 0;

    MinSpace = min_space;
    if ( MinSpace < 0 ) MinSpace = 0;

    MaxSpace = max_space;
    if ( MaxSpace < -1 ) MaxSpace = -1;

    ergWidths = ergHeights = NULL;
}

AContainer::~AContainer()
{
  int i;

  for ( i = 0; i < ( xelems * yelems ); i++ ) {
    if ( elements[i].cont() != NULL ) {
      delete elements[i].cont();
    }
  }
  if ( parent != NULL ) {
    parent->remove( this );
  } else {
    // top container
    if ( win != NULL ) win->removeContainer( this );
  }
  delete [] elements;
  if ( ergWidths != NULL ) delete [] ergWidths;
  if ( ergHeights != NULL ) delete [] ergHeights;
}

Widget *AContainer::add( Widget *newelement, int tx, int ty, int tautosizeMode )
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  elements[tx + xelems * ty].widelem( newelement );
  elements[tx + xelems * ty].autosizeMode( tautosizeMode );
  elements[tx + xelems * ty].noResize( ( ( tautosizeMode & ACONT_NORESIZE ) != 0 ) ? true : false );

  if ( ( tautosizeMode & ACONT_CENTER ) == ACONT_CENTER ) {
      elements[tx + xelems * ty].center( AContElem::CENTER_BOTH );
  } else if ( tautosizeMode & ACONT_CENTERH ) {
      elements[tx + xelems * ty].center( AContElem::CENTER_HORIZONTALLY );
  } else if ( tautosizeMode & ACONT_CENTERV ) {
      elements[tx + xelems * ty].center( AContElem::CENTER_VERTICALLY );
  } else {
      elements[tx + xelems * ty].center( AContElem::CENTER_NONE );
  }
  if ( win != NULL ) win->add( newelement );
  
  if ( ( tautosizeMode & ACONT_MINW ) != 0 ) {
    elements[tx + xelems * ty].minWidth( newelement->getWidth() );
  }
  if ( ( tautosizeMode & ACONT_MINH ) != 0 ) {
    elements[tx + xelems * ty].minHeight( newelement->getHeight() );
  }
  if ( ( tautosizeMode & ACONT_MAXW ) != 0 ) {
    elements[tx + xelems * ty].maxWidth( newelement->getWidth() );
  }
  if ( ( tautosizeMode & ACONT_MAXH ) != 0 ) {
    elements[tx + xelems * ty].maxHeight( newelement->getHeight() );
  }

  return newelement;
}

AContainer *AContainer::add( AContainer *newcont, int tx, int ty )
{
  int i;

  if ( newcont == NULL ) return NULL;

  for ( i = 0; i < ( xelems * yelems ); i++ ) {
    if ( elements[i].cont() == newcont ) {
      // already added so just return
      return newcont;
    }
  }

  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  elements[tx + xelems * ty].cont( newcont );
  newcont->setParent( this );
  return newcont;
}

//TODO setParent private machen und kein callback machen?
void AContainer::setParent( AContainer *newparent )
{
  AContainer *tc;

  if ( newparent != NULL ) {
    if ( parent != NULL ) {
      // only when different parent
      if ( parent != newparent ) {
	setParent( NULL );
	setParent( newparent );
      }
    } else {
      parent = newparent;
      parent->add( this ); /* add this element to the parent window
			    * when called from outside we have to do this
			    * add will do nothing if this is already in his list
			    * add will call setParent again, but because we already setted parent
			    * this won't be executed twice */
    }
  } else {
    if ( parent != NULL ) {
      tc = parent;
      parent = NULL;
      tc->remove( this );  /* remove from parent window because this can be called from outside
			    * because I set parent = NULL this won't be executed twice!
			    */
    }
  }
}

int AContainer::remove( const AContainer *v )
{
  int pos;
  AContainer *tc;

  if ( v == NULL ) return 1;

  for ( pos = 0; pos < ( xelems * yelems ); pos++ ) {
    if ( elements[pos].cont() == v ) break;
  }
  if ( ( pos < 0 ) || ( pos >= ( xelems * yelems ) ) ) return 1;

  tc = elements[pos].cont();
  elements[pos].cont( NULL );
  tc->setParent( NULL );
  return 0;
}

int AContainer::remove( const Widget *v )
{
  int pos;

  if ( v == NULL ) return 1;

  for ( pos = 0; pos < ( xelems * yelems ); pos++ ) {
    if ( elements[pos].widelem() == v ) break;
  }
  if ( ( pos < 0 ) || ( pos >= ( xelems * yelems ) ) ) {
    // we don't own it call it for all subcontainers
    for ( pos = 0; pos < ( xelems * yelems ); pos++ ) {
      if ( elements[pos].cont() != NULL ) {
	elements[pos].cont()->remove( v );
      }
    }
    return 1;
  }

  elements[pos].widelem( NULL );
  return 0;
}

class SpecialLimits
{
public:
  SpecialLimits()
  {
    min = max = -1;
  }
  
  int min, max;
};

int AContainer::resize( int nw, int nh )
{
  int *mins, *maxs, *weights, *erg;
  int i, ew, t1, t2;
  bool repeatScale;
  int realContWidth, realContHeight;
  int v, j;
  bool *contDone;

  SpecialLimits *specialWidths, *specialHeights;

  specialWidths = new SpecialLimits[xelems];
  specialHeights = new SpecialLimits[yelems];

  contDone = new bool[xelems * yelems * 2 * 2];
  for ( i = 0; i < ( xelems * yelems * 2 * 2 ); i++ ) contDone[i] = false;

  for ( repeatScale = true; repeatScale == true; ) {
    repeatScale = false;
    /* first scale all columns */
    mins = new int[ 2 * xelems + 1];
    for ( i = 0; i < ( 2 * xelems + 1 ); i++ ) mins[i] = 0;
    maxs = new int[ 2 * xelems + 1 ];
    for ( i = 0; i < ( 2 * xelems + 1 ); i++ ) maxs[i] = -1;
    weights = new int[ 2 * xelems + 1 ];
    for ( i = 0; i < ( 2 * xelems + 1 ); i++ ) weights[i] = 1;
    erg = new int[ 2 * xelems + 1 ];
    
    if ( BorderWidth > 0 ) t1 = BorderWidth;
    else t1 = 0;
    mins[0] = maxs[0] = mins[ 2 * xelems] = maxs[ 2 * xelems] = t1;
    
    if ( MinSpace > 0 ) t1 = MinSpace;
    else t1 = 0;
    if ( MaxSpace >= 0 ) t2 = MaxSpace;
    else t2 = -1;
    for ( i = 0; i < ( xelems - 1 ); i++ ) {
      mins[ 2 * i + 2 ] = t1;
      maxs[ 2 * i + 2 ] = t2;
    }
    
    for ( i = 0; i < xelems; i++ ) {
      t1 = 0;
      for ( j = 0; j < yelems; j++ ) {
	v = elements[i + j * xelems].minWidth();
	if ( v > t1 ) t1 = v;
      }
      
      if ( specialWidths[i].min > t1 ) {
	t1 = specialWidths[i].min;
      }
      
      t2 = -1;
      for ( j = 0; j < yelems; j++ ) {
	v = elements[i + j * xelems].maxWidth();
	if ( v >= 0 ) {
	  if ( t2 < 0 ) t2 = v;
	  else if ( v < t2 ) t2 = v;
	}
      }
      
      if ( specialWidths[i].max > 0 ) {
        if ( ( t2 == -1 ) ||
	     ( specialWidths[i].max < t2 ) ) {
	  t2 = specialWidths[i].max;
        }
      }
      
      if ( ( t1 > t2 ) && ( t2 >= 0 ) ) {
	// rather make the elements larger than making the smaller
	t2 = t1;
      }
      mins[ 2 * i + 1 ] = t1;
      maxs[ 2 * i + 1 ] = t2;
      
      if ( elements[i].wWeight() > 1 ) {
	weights[ 2 * i + 1 ] = elements[i].wWeight();
      }
    }
    ew = AScaler::scaleElements( nw, ( 2 * xelems + 1 ), mins, maxs, weights, erg );
    width = ew;

    if ( ergWidths == NULL ) ergWidths = new int[ xelems * 2 + 1 ];
    
    for ( i = 0; i < ( 2 * xelems + 1 ); i++ ) {
      ergWidths[i] = erg[i];
    }
    
    delete [] mins;
    delete [] maxs;
    delete [] weights;
    delete [] erg;
    
    /* now scale all rows */
    mins = new int[ 2 * yelems + 1];
    for ( i = 0; i < ( 2 * yelems + 1 ); i++ ) mins[i] = 0;
    maxs = new int[ 2 * yelems + 1 ];
    for ( i = 0; i < ( 2 * yelems + 1 ); i++ ) maxs[i] = -1;
    weights = new int[ 2 * yelems + 1 ];
    for ( i = 0; i < ( 2 * yelems + 1 ); i++ ) weights[i] = 1;
    erg = new int[ 2 * yelems + 1 ];
    
    if ( BorderWidth > 0 ) t1 = BorderWidth;
    else t1 = 0;
    mins[0] = maxs[0] = mins[ 2 * yelems] = maxs[ 2 * yelems] = t1;
    
    if ( MinSpace > 0 ) t1 = MinSpace;
    else t1 = 0;
    if ( MaxSpace >= 0 ) t2 = MaxSpace;
    else t2 = -1;
    for ( i = 0; i < ( yelems - 1 ); i++ ) {
      mins[ 2 * i + 2 ] = t1;
      maxs[ 2 * i + 2 ] = t2;
    }
    
    for ( i = 0; i < yelems; i++ ) {
      t1 = 0;
      for ( j = 0; j < xelems; j++ ) {
	v = elements[j + i * xelems].minHeight();
	if ( v > t1 ) t1 = v;
      }
      
      if ( specialHeights[i].min > t1 ) {
	t1 = specialHeights[i].min;
      }
      
      t2 = -1;
      for ( j = 0; j < xelems; j++ ) {
	v = elements[j + i * xelems].maxHeight();
	if ( v >= 0 ) {
	  if ( t2 < 0 ) t2 = v;
	  else if ( v < t2 ) t2 = v;
	}
      }

      if ( specialHeights[i].max > 0 ) {
        if ( ( t2 == -1 ) ||
	     ( specialHeights[i].max < t2 ) ) {
	  t2 = specialHeights[i].max;
        }
      }

      if ( ( t1 > t2 ) && ( t2 >= 0 ) ) {
	// rather make the elements larger than making the smaller
	t2 = t1;
      }
      
      mins[ 2 * i + 1 ] = t1;
      maxs[ 2 * i + 1 ] = t2;
      
      if ( elements[i * xelems].hWeight() > 1 ) {
	weights[ 2 * i + 1 ] = elements[i * xelems].hWeight();
      }
    }
    
    ew = AScaler::scaleElements( nh, ( 2 * yelems + 1 ), mins, maxs, weights, erg );
    height = ew;

    if ( ergHeights == NULL ) ergHeights = new int[ yelems * 2 + 1 ];
    
    for ( i = 0; i < ( 2 * yelems + 1 ); i++ ) {
      ergHeights[i] = erg[i];
    }
    
    delete [] mins;
    delete [] maxs;
    delete [] weights;
    delete [] erg;
    
    // now scale all sub containers
    for ( i = 0; i < ( xelems * yelems ); i++ ) {
      if ( elements[i].cont() != NULL ) {
	t1 = ergWidths[ 2 * ( i % xelems ) + 1];
	t2 = ergHeights[ 2 * ( i / xelems ) + 1];
	if ( ( t1 >= 0 ) && ( t2 >= 0 ) ) {
	  elements[i].cont()->resize( t1, t2 );
	  realContWidth = elements[i].cont()->getWidth();
	  realContHeight = elements[i].cont()->getHeight();
	  
	  /* update special widths/heights
	   * but only the first time for each container
	   * reason: When we fail to resize to wanted size
	   *         it will work the second time (no need to repeat)
	   *         or will fail just with the same values
	   * but use a special flag for each direction
	   * reason: when a container uses more space than wanted
	   *         and we give it more space in the next try
	   *         but it will than use less
	   */
          /* new method: we start with no limits (-1) and set min/max
           * if any container doesn't use the requested size
           * after setting min and max they are only allowed to grow
           * so there is enough space for the largest container
           */
          
	  if ( realContWidth > t1 ) {
            // cont needs more width than given
            // raise min and max values
	    if ( realContWidth > specialWidths[i % xelems].min ) {
              specialWidths[i % xelems].min = realContWidth;
              
              // check whether min is now larger than max and raise max in this case
              if ( specialWidths[i % xelems].max < realContWidth &&
                   specialWidths[i % xelems].max >= 0 ) {
                specialWidths[i % xelems].max = realContWidth;
              }
              
              if ( contDone[4 * i] == false ) {
                repeatScale = true;
              }
              contDone[4 * i] = true;
	    }
	  } else if ( realContWidth < t1 ) {
            // cont uses less than given
            // set max
	    if ( realContWidth > specialWidths[i % xelems].max ) {
              specialWidths[i % xelems].max = realContWidth;
              
              // if it's not less than current min
              if ( specialWidths[i % xelems].max < specialWidths[i % xelems].min ) {
                specialWidths[i % xelems].max = specialWidths[i % xelems].min;
              }
              
              if ( contDone[4 * i + 1] == false ) {
                repeatScale = true;
              }
              contDone[4 * i + 1] = true;
            }
	  }

	  if ( realContHeight > t2 ) {
            // cont needs more height than given
            // raise min and max values
	    if ( realContHeight > specialHeights[i / xelems].min ) {
              specialHeights[i / xelems].min = realContHeight;
              
              if ( specialHeights[i / xelems].max < realContHeight &&
                   specialHeights[i / xelems].max >= 0 ) {
                specialHeights[i / xelems].max = realContHeight;
              }

              if ( contDone[4 * i + 2] == false ) {
                repeatScale = true;
              }
              contDone[4 * i + 2] = true;
	    }
	  } else if ( realContHeight < t2 ) {
            // cont uses less than given
            // set max
	    if ( realContHeight > specialHeights[i / xelems].max ) {
              specialHeights[i / xelems].max = realContHeight;
             
              // if it's not less than current min
              if ( specialHeights[i / xelems].max < specialHeights[i / xelems].min ) {
                specialHeights[i / xelems].max = specialHeights[i / xelems].min;
              }
 
              if ( contDone[4 * i + 3] == false ) {
                repeatScale = true;
              }
              contDone[4 * i + 3] = true;
	    }
	  }
	}
      }
    }
  }

  delete [] contDone;
  delete [] specialWidths;
  delete [] specialHeights;

  return 0;
}

int AContainer::move( int nx, int ny )
{
  x = nx;
  y = ny;
  return 0;
}

int AContainer::rearrange( int vhmode )
{
  int i, j, cx, cy, tw, th, ind;
  int ux, uy, uw, uh;

  if ( ( ergWidths == NULL ) || ( ergHeights == NULL ) ) return 1;

  cy = y;
  for ( j = 0; j < ( 2 * yelems + 1 ); j++ ) {
    cx = x;
    th = ergHeights[j];
    if ( ( j % 2 ) == 1 ) {
      for ( i = 0; i < ( 2 * xelems + 1 ); i++ ) {
	tw = ergWidths[i];
	if ( tw < 0 ) tw = 0;
	
	if ( ( i % 2 ) == 1 ) {
	  ind = i / 2 + ( j / 2 ) * xelems;
	  ux = cx;
	  uy = cy;
	  uw = tw;
	  uh = th;
	  elements[ind].width( uw );
	  elements[ind].height( uh );
	  if ( elements[ind].widelem() != NULL ) {
          if ( elements[ind].center() & AContElem::CENTER_HORIZONTALLY ) {
              int tcx = ux + uw / 2;
              
              tcx -= elements[ind].widelem()->getWidth() / 2;
              if ( tcx > ux ) ux = tcx;
            }
          if ( elements[ind].center() & AContElem::CENTER_VERTICALLY ) {
              int tcy = uy + uh / 2;
              
              tcy -= elements[ind].widelem()->getHeight() / 2;
              if ( tcy > uy ) uy = tcy;
            }
            if ( vhmode == ACONT_ONLYH ) {
                uy = elements[ind].widelem()->getY();
                uh = elements[ind].widelem()->getHeight();
            } else if ( vhmode == ACONT_ONLYV ) {
                ux = elements[ind].widelem()->getX();
                uw = elements[ind].widelem()->getWidth();
            }
            //elements[ind].widelem()->move( ux, uy );
            m_move_infos[ind].active = true;
            m_move_infos[ind].x = ux;
            m_move_infos[ind].y = uy;
            if ( elements[ind].noResize() == false ) {
                //elements[ind].widelem()->resize( uw, uh );
                m_resize_infos[ind].active = true;
                m_resize_infos[ind].x = uw;
                m_resize_infos[ind].y = uh;
            }
	  } else if ( elements[ind].cont() != NULL ) {
	    if ( vhmode == ACONT_ONLYH ) {
	      uy = elements[ind].cont()->getY();
	    } else if ( vhmode == ACONT_ONLYV ) {
	      ux = elements[ind].cont()->getX();
	    }
	    //elements[ind].cont()->move( ux, uy );
            m_move_infos[ind].active = true;
            m_move_infos[ind].x = ux;
            m_move_infos[ind].y = uy;
	    //elements[ind].cont()->rearrange( vhmode );
            m_rearrange_infos[ind].active = true;
	  }
	}
	cx += tw;
      }
    }
    cy += th;
  }

  int start, stop, step;

  if ( width >= old_rearrange_width &&
       height >= old_rearrange_height ) {
      start = xelems * yelems - 1;
      stop = -1;
      step = -1;
  } else {
      start = 0;
      stop = xelems * yelems;
      step = 1;
  }

  for ( ind = start; ind != stop; ind += step ) {
      if ( m_move_infos[ind].active ) {

          if ( elements[ind].widelem() != NULL ) {
              elements[ind].widelem()->move( m_move_infos[ind].x,
                                             m_move_infos[ind].y );
          } else if ( elements[ind].cont() != NULL ) {
              elements[ind].cont()->move( m_move_infos[ind].x,
                                          m_move_infos[ind].y );
          }

          m_move_infos[ind].active = false;
      }
  }

  for ( ind = start; ind != stop; ind += step ) {
      if ( m_resize_infos[ind].active ) {
          elements[ind].widelem()->resize( m_resize_infos[ind].x,
                                           m_resize_infos[ind].y );

          m_resize_infos[ind].active = false;
      }
  }

  for ( ind = start; ind != stop; ind += step ) {
      if ( m_rearrange_infos[ind].active ) {
          elements[ind].cont()->rearrange( vhmode );

          m_rearrange_infos[ind].active = false;
      }
  }

  old_rearrange_width = width;
  old_rearrange_height = height;

  return 0;
}

void AContainer::setBorderWidth( int nv )
{
  BorderWidth = nv;
  if ( BorderWidth < 0 ) BorderWidth = 0;
}

int AContainer::getBorderWidth() const
{
  return BorderWidth;
}

void AContainer::setMinSpace( int nv )
{
  MinSpace = nv;
  if ( MinSpace < 0 ) MinSpace = 0;
}

int AContainer::getMinSpace() const
{
  return MinSpace;
}

void AContainer::setMaxSpace( int nv )
{
  MaxSpace = nv;
  if ( MaxSpace < -1 ) MaxSpace = -1;
}

int AContainer::getMaxSpace() const
{
  return MaxSpace;
}

void AContainer::setMinWidth( int nv, int tx, int ty )
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  elements[tx + xelems * ty].minWidth( nv );
}

int AContainer::getMinWidth( int tx, int ty ) const
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  return elements[tx + xelems * ty].minWidth();
}

void AContainer::setMaxWidth( int nv, int tx, int ty )
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  elements[tx + xelems * ty].maxWidth( nv );
}

int AContainer::getMaxWidth( int tx, int ty ) const
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  return elements[tx + xelems * ty].maxWidth();
}

void AContainer::setMinHeight( int nv, int tx, int ty )
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  elements[tx + xelems * ty].minHeight( nv );
}

int AContainer::getMinHeight( int tx, int ty ) const
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  return elements[tx + xelems * ty].minHeight();
}

void AContainer::setMaxHeight( int nv, int tx, int ty )
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  elements[tx + xelems * ty].maxHeight( nv );
}

int AContainer::getMaxHeight( int tx, int ty ) const
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  return elements[tx + xelems * ty].maxHeight();
}

void AContainer::setWWeight( int nv, int tx, int ty )
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  elements[tx + xelems * ty].wWeight( nv );
}

int AContainer::getWWeight( int tx, int ty ) const
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  return elements[tx + xelems * ty].wWeight();
}

void AContainer::setHWeight( int nv, int tx, int ty )
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  elements[tx + xelems * ty].hWeight( nv );
}

int AContainer::getHWeight( int tx, int ty ) const
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  return elements[tx + xelems * ty].hWeight();
}

int AContainer::getX() const
{
  return x;
}

int AContainer::getY() const
{
  return y;
}

void AContainer::readLimits()
{
  Widget *elem;
  int pos;

  for ( pos = 0; pos < ( xelems * yelems ); pos++ ) {
    if ( elements[pos].widelem() != NULL ) {
      elem = elements[pos].widelem();
      if ( ( elements[pos].autosizeMode() & ACONT_MINW ) != 0 ) {
	elements[pos].minWidth( elem->getWidth() );
      }
      if ( ( elements[pos].autosizeMode() & ACONT_MINH ) != 0 ) {
	elements[pos].minHeight( elem->getHeight() );
      }
      if ( ( elements[pos].autosizeMode() & ACONT_MAXW ) != 0 ) {
	elements[pos].maxWidth( elem->getWidth() );
      }
      if ( ( elements[pos].autosizeMode() & ACONT_MAXH ) != 0 ) {
	elements[pos].maxHeight( elem->getHeight() );
      }
    }
  }
}

int AContainer::getWidth() const
{
  return width;
}

int AContainer::getHeight() const
{
  return height;
}

int AContainer::getWidth( int tx, int ty ) const
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  return elements[tx + xelems * ty].width();
}

int AContainer::getHeight( int tx, int ty ) const
{
  if ( ( tx < 0 ) || ( tx >= xelems ) ) tx = 0;
  if ( ( ty < 0 ) || ( ty >= yelems ) ) ty = 0;
  return elements[tx + xelems * ty].height();
}

void AContainer::setNoResize( bool nv, int tx, int ty )
{
    if ( tx < 0 || tx >= xelems ) tx = 0;
    if ( ty < 0 || ty >= yelems ) ty = 0;
    elements[tx + xelems * ty].noResize( nv );
}

bool AContainer::getNoResize( int tx, int ty ) const
{
    if ( tx < 0 || tx >= xelems ) tx = 0;
    if ( ty < 0 || ty >= yelems ) ty = 0;
    return elements[tx + xelems * ty].noResize();
}

void AContainer::hide()
{
    for ( int pos = 0; pos < ( xelems * yelems ); pos++ ) {
        if ( elements[pos].widelem() ) {
            auto elem = elements[pos].widelem();

            auto guielem = dynamic_cast< GUIElement * >( elem );

            if ( guielem ) {
                guielem->hide();
            }
        } else if ( elements[pos].cont() ) {
            elements[pos].cont()->hide();
        }
    }
}

void AContainer::show()
{
    for ( int pos = 0; pos < ( xelems * yelems ); pos++ ) {
        if ( elements[pos].widelem() ) {
            auto elem = elements[pos].widelem();

            auto guielem = dynamic_cast< GUIElement * >( elem );

            if ( guielem ) {
                guielem->show();
            }
        } else if ( elements[pos].cont() ) {
            elements[pos].cont()->show();
        }
    }
}
