/*
  libuta - a C++ widget library based on SDL (Simple Direct Layer)
  Copyright (C) 1999-2002  Karsten Laux

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 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
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  Boston, MA  02111-1307, SA.
*/


#ifndef _WIDGET_H
#define _WIDGET_H

#include <list>
#include <sigc++/signal_system.h>
#include <list>
#include "rect.h"
#include "color.h"
#include "surface.h"
#include "event.h"


namespace uta {

/** Widget Baseclass.
 */
class Widget : public SigC::Object, public Rect
{

 public:

  ///
  Widget();
  ///
  Widget(Widget* parent, int x, int y, int w, int h);
  ///
  virtual ~Widget();
  ///

  ///
  SigC::Signal0<void> deleted;
  ///
  SigC::Signal0<void> exposed;
  ///
  SigC::Signal0<void> hidden;
  ///
  SigC::Signal0<void> enabled;
  ///
  SigC::Signal0<void> disabled;
  
  ///
  SigC::Signal0<void> gainedMouse;
  ///
  SigC::Signal0<void> lostMouse;
  ///
  SigC::Signal0<void> gainedKeyboard;
  ///
  SigC::Signal0<void> lostKeyboard;
  

  /**Set background image.
     The surface is NOT copied. you will have to ensure it is accesible
     as long as this widget lives. (use Resources...)
     If tileIt is true, the image will be tiled if the surface is smaller
     than the widget; otherwise it gets scaled to fit the size.
  */
  void setBackground(const Surface* backgrnd, bool tileIt = true);
  ///setting background color.
  void setColor(const Color &color);
  ///to set the background colour when the widget is disabled
  void setDisabledColor(const Color& color);
  ///
  void setAlpha(unsigned char);
  ///
  void setDisabledAlpha(unsigned char);
  /**Set autodelete flag.
     Normally if a widget gets deleted its constructor automatically 
     deletes all its childs.
     If the autodelete flag is set false the widget gets not deleted upon 
     its parent's destruction.
  */
  void setAutoDelete(bool yes) {autoDelete_ = yes;};

  ///
  void setTransparency(bool flag) { if(surface_) surface_->setTransparency(flag);} 
   
  ///screen update
  virtual void update();
  ///show up this widget and itīs childs.
  void show();
  ///hide this widget and itīs childs.
  void hide();
  ///close  this widget and itīs childs.
  void close();
  ///enable this widget tree
  void enable();
  /**disable this widget tree. 
     The widget tree gets greyed and the member ignore any events.
  */
  void disable();

  virtual void resize(int w, int h) 
    { 
      Rect::resize(w,h);
      //FIXME !!!!!!!!!!!
      //being very crude here ... (it is 1:00am)
      delete surface_;
      surface_ = new Surface(w,h);
      rect_.resize(w,h);
      window_.resize(w,h);
      needsUpdate_=true;
      };
  ///
  void forceUpdate(int);

  /** just blit to the parentīs surface.
   */
  virtual void blit();
  ///
  bool handleEvent(const Event*);
  ///
  virtual bool processEvent(const Event*) { return false;}; 

  /**widget content has changed.
     this is called by the mainloop or parentwidget to test, 
     whether this widget or one of itīs childs have to be reblitted.
  */
  bool needsUpdate();

  ///
  bool isHidden() const { return hidden_; };
  ///
  bool isClosed() const { return closed_; };
  ///
  bool isEnabled() const { return !disabled_; };
  ///
  bool hasFocus() const { return haveFocus_;};
  ///
  bool isAutoDelete() const { return autoDelete_;};

  /**insert a child widget.
     this is only to be called from the constructor of a childwidget.
     it will return the surface the child has to blit its own surface to
  */
  Surface* insertChild(Widget* child);

  ///
  void removeChild(Widget* child);
  ///like removeChild, but the other way
  void deParent();

  /**return geometry.
   */
  Rect getRect() { return rect_ ;};
  /**convert rect coords to global rect coords.
   */
  Rect globalCoord(Rect);
  /**convert global rect coords to local rect coords.
   */
  Rect localCoord(Rect);
  ///
  void addUpdateRects(std::list<Rect> &updateRects);

  ///
  bool releaseFocus();
  ///
  bool grabFocus();
  ///
  void setClickToFocus(bool val) 
    { 
      activateOnClick_ = val; 
    };
  ///
  void setPointToFocus(bool val) 
    { 
      activateOnMouse_ = val; 
    };
  ///
  void nextFocus();
  ///
  void prevFocus();
 
 protected:
 
  /**create the widget and childs.
     must be overloaded by derived classes to implemented their
     own grafx, etc.
     (each derived class may call the baseclassīs create to handle
     the basic stuff like background painting)
  */
  virtual void create();

  ///
  virtual void initMembers();

  /**blit whole widget.
     descendants may overwrite this in order to implement special
     blits. This methode gets called, if the whole widget needs to 
     be redrawn to the screen.
     The target is usually the screenbuffer.
   */
  virtual void blit_complete(Surface*);
  
  /**blit only dirty rects.
     descendants may overwrite this in order to implement special
     blits. Check dirtyRects to see what parts need to be reblitted.
     The target is usually the screenbuffer.
  */
  virtual void blit_dirty(Surface*);

  /**the parent. 
     if NULL this widget is  toplevel
  */
  Widget *parent_;
  /**destination rectangle. 
     the coords are relative to the parentīs coords.
   */
  Rect rect_;
  /**window rect.
     if local surface is bigger than destination rect; only this
     window is blitted.
  */
  Rect window_;
  /**background image. 
     may be NULL
  */
  const Surface *backgrnd_;
  /**surface buffer.
   */
  Surface *surface_;
  /**destination surface. 
     this widgets blits to this surface, whenever show is called
  */
  Surface *parentSurface_;
  /**backbuffer.
     stores background of transparent widgets.
  */
  Surface *backBuffer_;

  ///background color.
  Color color_;

  //disable bg color
  Color colorDis_;

  //disable bg alpha
  unsigned char alphaDis_;

  ///true when the mouse is over this widget
  bool haveFocus_;

  ///have we got a background surface ?
  bool drawBackground_;
  /**true if this widgets needs to be reblitted to itīs parentīs surface.
     a derived widget simply set this to true in order to get redrawn.
     This is handled completely by the baseclass.
  */
  bool needsUpdate_;
  ///
  bool needsReblit_;
  ///
  bool hidden_;
  ///
  bool hideRequest_;
  ///
  bool closed_;
  ///
  bool disabled_;
  ///
  bool disableRequest_;
  /// self delete when closing ?
  bool destroyWidget_;
 
  /**create child widget.
   */
  void createChild();

  ///child list.
  std::list<Widget*> childs_;

  /**list of dirty rects.
     this is used for faster redrawing; especially if the toplevel-
     widgets is big and only a small child-widgets needs to be redrawn.
  */
  std::list<Rect> dirtyRects_;
  ///
  bool tileBackground_;
  ///shall the widget be deleted, when closed ? default = yes
  bool autoDelete_;
  ///
  bool activateOnMouse_;
  ///
  bool activateOnClick_;
  ///
  std::list<Widget*> focusList_;
  ///
  std::list<Widget*>::iterator currentFocus_;
  ///
  bool acceptsFocus() const { return activateOnClick_ || activateOnMouse_; };
  ///
  bool mouseFocus_;

};

}
#endif // !_WIDGET_H
