/* This file is part of the KDE libraries
    Copyright (c) 1998 Emmeran Seehuber (the_emmy@hotmail.com)
 
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#ifndef KLCHILD_H
#define KLCHILD_H

#include <kconfigbase.h>
#include "klchildmeta.h"

/**
* My own assert (i hope this will be included in kdebug)
*
* This is a hard assert. It will stop the execution
* of the program and ask for future actions.
*
* You then can:
*   'C' : Continue the program
*   'S' : Stop the program to analyse it. Just throws an arithmetic exception.
*         This require that the program runs in a debugger and that the debugger
*         is able to examine an crashed programm. (no problem with gdb)
*   'A' : Abort the program (= exit(20))
*/
#ifndef NDEBUG
extern void _hassert(const char *why, const char *file, ulong line);
#define HASSERT(x) { if(!(x) ) { _hassert(#x,__FILE__,__LINE__); } }
#define WARN(x) { static char __warn_buff[4096];  sprintf(__warn_buff,"%s:%d:%s",__FILE__,__LINE__,(const char *)(x)); KDEBUG( KDEBUG_WARN, 0, __warn_buff); }
#else
#define HASSERT(x)
#define WARN(x)
#endif

/**
* My own min 
*/
inline long KLMin(long a, long b)
  { return( a < b ? a : b ); };

/**
* My own max
*/
inline long KLMax(long a, long b)
  { return( a > b ? a : b ); };

/**
* @return the not null minmum of a and b
*/
inline long KLNonNullMin(long a, long b)
  { return(a == 0 ? b : (b == 0 ? a : KLMin(a,b) ) ); };

/**
* KLE layout constant. The maximumsize. If your widget could be
* sizes as big the user likes, add this in the askMinMax() method.
*/
const ulong KLMaxSize = 10000;
const ulong KLDefWeight = 100;

/**
* KLChild - The baseclass for all layout elements
*
* This is the baseclass for everything wich is used in the layout.
* More documentation to follow ...
*
*
* Calling herachie:
*
* <pre>
* Constructor()
* { 
*   Setup()
*   {
*     AskMinMax()
*     {
*       Show()
*       Hide()
*     }
*   }
*   Cleanup()
* }
* Destructor()
* </pre>
*
* {} means, that the functions inside this "level" can be called in the given 
* order many times. (e.g. when Show() is successfull, you can be sure
* that Hide() will be called before the next Show() call is done)
* Only when the first call in an level is successfull (e.g. Setup() or Show())
* the oder calls are executed
*
* NOTE: 
* <pre>
*   X => Vertical Row (Height)
*   Y => Hriziontal Coloumn (Width)
* </pre>
*/
class KLDevice;
class KLChildMeta;
class KLDropMarkList;
class KLChild {
public:

  /**
  * Setupinformation
  *
  * Containts information about the display device and the
  * environment pointer
  */

  class KLSetupInfo {
  public:
    /**
    * The display device
    */
    KLDevice* device;     

    /**
    * Environment to read all settings from.
    */
    KConfigBase* config;

    /**
    */
    KLSetupInfo() : device(NULL), config(NULL) {};
  };

  /**
  * Class for asking sizes and calculating. 
  */
  class KLMinMaxSizes {
  public:
    /**
    * Minimum X size. The widget canīt get smaller
    */
    ulong minX;

    /**
    * Minimum Y size. The widget canīt get smaller
    */
    ulong minY;

    /**
    * Default X size. 
    */
    ulong defX;

    /**
    * Default Y size. 
    */
    ulong defY;

    /**
    * Maximum X size. The widget canīt get bigger
    */
    ulong maxX;

    /**
    * Maximum Y size.  The widget canīt get bigger
    */
    ulong maxY;

    /**
    */
    KLMinMaxSizes() { init(); };

    /**
    * Resetīs everything to 0.
    */
    void init();

    /**
    * Validates the sizes. E.g. if the minimum is bigger than the maximum
    */
    void validate();

    /**
    */
    KLMinMaxSizes operator+(const KLMinMaxSizes &mms );

    /**
    */
    KLMinMaxSizes &operator +=(const KLMinMaxSizes &mms );

    /**
    * Debug dump
    */
    void dumpSize();
  };

  /**
  * Showing information for a child
  *
  * All coordinates are absolute to the display device
  *
  * NOTE: x + xSize - 1 => Abs. bottom line
  */
  class KLShowInfo {
  public:

    /**
    */
    ulong x;

    /**
    */
    ulong y;

    /**
    */
    ulong xSize;

    /**
    */
    ulong ySize;

    // Use this functions to get the absolute coords
    ulong getX1() const { return( x ); };
    ulong getY1() const { return( y ); };
    ulong getX2() const { return( x + xSize - 1 ); };
    ulong getY2() const { return( y + ySize - 1 ); };

    /**
    * Check if the widget matches the given coords. 
    *
    * @result true when matching
    */
    bool matchCoords( ulong xCoord, ulong yCoord ) const
    { return ( (xCoord >= getX1() ) && (yCoord >= getY1() ) && 
               (xCoord <= getX2() ) && (yCoord <= getY2() ) ); };

    /**
    */
    KLShowInfo() { init(); };

    /**
    * Resets everything to 0
    */
    void init();

  };

private:
  /** 
  * Baseclass data
  */
  ulong a_stopRelayout; // Count of layout stop calls
  bool a_doRelayout;            // TRUE: After restarting layout, perform an relayout
  bool a_hidden;
  ulong a_fixXSize;
  ulong a_fixYSize;
  ulong a_xWeight;
  ulong a_yWeight;
  ulong a_disapearLevel;

public:
  /**
  * @return if the widget is hidden
  */
  bool hidden() const;

  /**
  * @return the fix x size of the object or 0 if
  * none set.
  */
  ulong fixXSize() const;

  /**
  * @return the fix y size of the object or 0 if
  * none set.
  */
  ulong fixYSize() const;

  /**
  * @return the x weight of the obejct
  */
  ulong xWeight() const;

  /**
  * @return the y weight of the obejct
  */
  ulong yWeight() const;

  /**
  * @return the disapearlevel of this child
  */
  ulong disapearLevel() const;

  /**
  * Shows/Hides the object. 
  *
  * If hidden, all other objects in the same group
  * will get the space of this object.
  *
  * Changing this when showed forces a relayout
  */
  void setHidden( bool hide );

  /**
  * Gives the object a fix x size. This overwrites 
  * the normal Min/Max sizes
  *
  * Set to 0, if you not longer want a fix size.
  * This is also the default.
  *
  * Changing this when showed forces a relayout
  *
  * @see also KLChild#setFixYSize
  */
  void setFixXSize(ulong fixXSize);

  /**
  * Gives the object a fix Y size. This overwrites 
  * the normal Min/Max sizes
  *
  * Set to 0, if you not longer want a fix size.
  * This is also the default.
  *
  * Changing this when showed forces a relayout
  *
  * @see also KLChild#setFixXSize
  */
  void setFixYSize(ulong fixYSize);

  /**
  * Sets both a fix X and Y size at the
  * same time
  *
  * Only forces one relayout when showed
  *
  * @see also KLChild#setFixSize
  */
  void setFixSizes(ulong fixXSize, ulong fixYSize);

  /**
  * Sets the x weight of the object.
  * 
  * The weight is important when spreading
  * the availble space in a group.
  *
  * The formular used to calculate the 
  * space for one object is:
  *
  * <pre>
  * xSize = availspace * Sum of weight of all nonhidden objects in group  / objectweight
  * </pre>
  *
  * Ok, this is not the exact formular, because other things like min/max sizes 
  * must also be token into consideration.
  *
  * The default value is 100.
  *
  * A special case is a weight of 0. If an object has this weight, 
  * then the maximum will be set to the minimum, so that the object
  * always only get itīs minmum sizes.
  *
  * @see setYWeight()
  */
  void setXWeight(ulong xWeight);

  /**
  * Sets the Y Weight
  *
  * @see setXWeight()
  */
  void setYWeight(ulong yWeight);

  /**
  * Sets both x and y weight
  * 
  * @see setXWeight(), setYWeight()
  */
  void setWeight(ulong weight);

  /**
  * Sets the disapearlevel of this
  * widget.
  *
  * If you set an disapearlevel higger than
  * 0, the minimumsize of this child will
  * not be added to the normal minimumsize.
  *
  * If the parent group runs out of space
  * to display all childs, it will start to
  * hide the childs with the higgest disaperlevel.
  *
  * Note: This does not affect the hidden()-flag.
  *
  * As higger the disapearlevel is, as sooner will
  * this child be hidden.
  *
  * Default value is 0, wich means no disapearing.
  *
  * (not yet implementated in the groups)
  */
  void setDisapearLevel(ulong disapearLevel);

protected:
  /**
  * Local copy of the setup information
  * 
  * Only valid between klSetup() and klCleanup()
  *
  */
  KLSetupInfo a_setupInfo;

  /**
  * Local copy of Min/Max sizes 
  * 
  * Only valid between klAskMinMax() and klCleanup()
  */
  KLMinMaxSizes a_minMaxSizes;

  /**
  * Local copy of show information
  *
  * Only valid between klShow() and klHide()
  */

  KLShowInfo a_showInfo;

public:
  /**
  * Get the setup info
  */
  KLSetupInfo& setupInfo();
  
  /**
  * Get the Min/Max sizes
  */
  KLMinMaxSizes& minMaxSizes();

  /**
  * Get the show info
  */
  KLShowInfo& showInfo();
   

public:
  /**
  * Parent group object, or NULL if non exists
  */
  class KLGroup *parentGroup;

  /**
  * Internal states of this object
  */
  enum StateInfo {
    SI_None, 
    SI_SetupDone, 
    SI_Showed
  } a_state;

  
  // Group private flag: Used only in the layoutprocess (@see KLHVGroup#showControl)
  // TRUE: This object is final layouted. This means, the layoutprocess
  // has determinated that the object should get a bigger size than the one allowd. This leads into a 
  // recalculation of the complete group. All "final layouted" objects will be skiped then
  bool layoutFinal;

private:
  // Internal flag: in klAskMinMax() with one fix size set.
  bool askingNonFixSizes; 

public:
  /**
  * Constructor
  */
  KLChild();

  /**
  * Destructor
  */
  virtual ~KLChild();

  /**
  *  Do your setup work (e.g. load a image, load fonts)
  *  First call baseclass, and return false if it returns false.
  *  false means, setup has failed.
  */
  virtual bool klSetup( KLSetupInfo *setupInfo );

  /**
  * Ask for the sizes of this widget. Must first call
  * itīs base class (to do such things like adding bordersizes).
  * If returning FALSE, return also
  * FALSE immedatly (e.g. a fix size has been set)
  * Otherwise ADD your sizes. (e.g. size of the setted text)
  *
  * NOTE: Itīs VERY important, that you ADD your sizes
  * You will destroy the complete layout, if you do not so !!!
  *
  * @return FALSE does NOT mean failure.
  */

  virtual bool klAskMinMax(KLMinMaxSizes *minMaxSizes);

  /** 
  * Show the element. ShowInfo contains the X and Y coords,
  * sizes and a systemdepending device information (Window-Handle)
  * First call baseclass, and return false if it returns false.
  * FALSE means, show has failed
  */
  virtual bool klShow(KLShowInfo *showInfo);

  /**
  * Just hide it
  * First do your hiding stuff, then call baseclass.
  */
  virtual void klHide();

  /**
  * Do your cleanup work. (e.g. flush images, or fonts)
  * First do your hiding stuff, then call baseclass
  */
  virtual void klCleanup();

  /**
  * Find the widget at x/y
  * Can only be called between klShow() and klHide()
  *
  * @return child found at x/y or NULL
  */
  virtual KLChild *findChild( ulong x, ulong y ) const;

  /**
  * Call this function, if you want to get the minmax sizes
  * of an object
  */
  void klDoAskMinMax(KLMinMaxSizes *minMaxSizes);

  /**
  * *INTERNAL FUNCTON*
  * Just checks, if the weight is 0, and if this is true
  * sets the maxmimum to the minimum. Does also
  * validate the minMaxSizes
  * May be extended in future to do more, and get more parameters
  */
  void klPostAskMinMax(KLMinMaxSizes *minMaxSizes);
  
public:
  /**
  * Relayout this widget. 
  *
  * @param relayoutParent true to force relayout of parent. If there
  *        is no parent, the device is will be relayouted
  *
  * @see startRelayout
  * @see stopRelayout
  */
  virtual void doRelayout( bool relayoutParent );

  /**
  * Stop the relayouting of this widget.
  *
  * This function can be called nested. You must
  * have an matching #startRelayout() call
  * for every #stopRelayout() call
  *
  * When this widget is a group, it
  * will also call #stopRelayout() on all
  * group members
  *
  * @see #startRelayout
  * @see #doRelayout
  */
  virtual void stopRelayout();

  /**
  * Starts the relayouting of this widget
  *
  * Only relayouts, if the nexting level is 0
  * and the #doRelayout() was called
  *
  * @see #stopRelayout
  * @see #doRelayout
  */
  virtual void startRelayout();

public: 
  /**
  * Setup input graping. The device knows more
  * Can only be called when setted up.
  *
  * @see #cleanupGrap
  */
  virtual void setupGrap();

  /**
  * Cleanup input graping. 
  *
  * @see #setupGrap
  */
  virtual void cleanupGrap();

public:
  /**
  * Create dropmarks for this child/group
  *
  * Dropmarks descripes the designer, where he
  * is able to insert childs
  *
  * KLChild does not add any dropmarks. This is 
  * usualy done by the subclasses, such as 
  * KLHVGroup or KLReplaceMe
  *
  * @param dml DropMarkList to insert the dropmarks into
  */
  virtual void addDropMarks( KLDropMarkList * dml );

public:
  DECLARE_KLMETA_STANDALONE();
private:
  KLChildMeta *realMetaClass;
public:
  bool metaIsA(const char *classname);
  bool metaInherits(const char *classname);
  const KLChildMeta *getRealMetaClass() const;

public:
  // Streaming operators
  typedef void (*_child_change_func)(KLChild&);
  typedef void (*_child_change_p1_func)(KLChild&,ulong param);

  class KLStreamHelp {
  public:
    KLChild *child;
    _child_change_p1_func func;
    KLChild &operator<<(ulong param);
  };

  /**
  * For information, how to use this streaming, just
  * look at the supplied examples.
  *
  * You set each attribute also with using streaming
  */
  KLChild &operator<<(_child_change_func func);
  KLStreamHelp &operator<<(_child_change_p1_func func);


private:
  // Disable copy constructor and operator=
  KLChild( KLChild& ) { HASSERT(FALSE); };
  KLChild &operator=(KLChild &) { HASSERT(FALSE); return *this; };
};


/////////////////////////////////////////////////////////////////
// Inline functions
/////////////////////////////////////////////////////////////////

// Stream funcs
/**
* Just sets the hiddenflag true.
*
* @see KLChild#setHidden
*/
inline void setHidden(KLChild& child)
{ child.setHidden(true); };

inline void setFixXSize(KLChild& child,ulong fixXSize)
{ child.setFixXSize(fixXSize); }

inline void setFixYSize(KLChild &child, ulong fixYSize)
{ child.setFixYSize(fixYSize); };

inline void setFixSize(KLChild &child, ulong fixSize)
{ child.setFixSizes(fixSize,fixSize); };

inline void setXWeight(KLChild &child, ulong xWeight)
{ child.setXWeight(xWeight); };

inline void setYWeight(KLChild &child, ulong yWeight)
{ child.setYWeight(yWeight); };

inline void setWeight(KLChild &child, ulong weight)
{ child.setWeight(weight); };

inline void setDisapearLevel(KLChild &child, ulong disapearLevel)
{ child.setDisapearLevel(disapearLevel); };


// Inline functions for all parameter GET functions
inline bool KLChild::hidden() const
{ return this->a_hidden; }

inline ulong KLChild::fixXSize() const
{ return this->a_fixXSize; }

inline ulong KLChild::fixYSize() const
{ return this->a_fixYSize; }

inline ulong KLChild::xWeight() const
{ return this->a_xWeight; }

inline ulong KLChild::yWeight() const
{ return this->a_yWeight; }

inline ulong KLChild::disapearLevel() const
{ return this->a_disapearLevel; }

inline KLChild::KLSetupInfo& KLChild::setupInfo() 
{ return a_setupInfo; }

inline KLChild::KLMinMaxSizes& KLChild::minMaxSizes() 
{ return a_minMaxSizes; }

inline KLChild::KLShowInfo& KLChild::showInfo() 
{ return a_showInfo; }

#endif 


Documentation generated by emmy@gate on Tue Sep 22 21:13:27 MEST 1998