/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CThemes.cpp  -  description
                             -------------------
    begin                : Fri Nov 08 20003
    copyright            : (C) 2003-2005 by Alexey S.Parshin
    email                : alexeyp@gmail.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; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

   Please report all bugs and problems to "alexeyp@gmail.com"
 ***************************************************************************/

#ifndef __CTHEMES_H__
#define __CTHEMES_H__

#include <FL/Fl.h>
#include <FL/Fl_Image.h>
#include <sptk3/CStrings.h>
#include <sptk3/CRegistry.h>
#include <sptk3/CRect.h>

/// @addtogroup gui GUI Classes
/// @{

/// Class CButtonImage provides a storage for two images (color and desaturated).
class CButtonImage {
public:

   Fl_Image *m_colorImage;   ///< Color image
   Fl_Image *m_grayImage;    ///< Desaturated image
public:

   /// Constructor
   /// @param image Fl_Image *, image to use as color image. The desaturated counterpart is generated automatically.
   CButtonImage(Fl_Image *image=0L);

   /// Destructor
   ~CButtonImage();

   /// Deallocates the allocated resources (if any) and sets images to NULL
   void clear();

   /// Sets an image to use
   /// @param image Fl_Image *, image to use as color image. The desaturated counterpart is generated automatically.
   /// @param desaturateInactive bool, true if you need to desaturate button image when mouse is not over it
   void set(Fl_Image *image,bool desaturateInactive);
};

/// Theme button type - defines which routine to use for which FLTK button type
enum CThemeButtonType { THM_BUTTON_UP, THM_BUTTON_DOWN, THM_DEFAULT_BUTTON_UP, THM_DEFAULT_BUTTON_DOWN };

/// Theme button size - defines the button size and look to select the correct pixmap
enum CThemeButtonSize { THM_BUTTON_COMBO, THM_BUTTON_CHECK, THM_BUTTON_RADIO, THM_BUTTON_NORMAL, THM_BUTTON_LARGE };

/// Theme scroll bar type - defines the scroll bar direction
enum CThemeScrollBarType { THM_SCROLLBAR_VERTICAL, THM_SCROLLBAR_HORIZONTAL };

/// The complete set of four images to draw a scroll bar
class CScrollBarImages {
public:
   Fl_Image     *m_normalImage;  ///< Full image of the scroll bar: buttons and slider
   Fl_Image     *m_activeImage;  ///< Image of the scroll bar without slider, with buttons pushed down
   Fl_Image     *m_sliderImage;  ///< Image of the scroll bar slider
   int           m_buttonSize;   ///< Width of the button in horizontal scrollbar
public:
   /// Default constructor
   CScrollBarImages() { m_normalImage = m_activeImage = m_sliderImage = 0L; m_buttonSize = 0; }

   /// Loads the images from the theme files
   /// @param btnSize int, the size of the button in theme
   /// @param themeDir std::string, the directory where theme is located
   /// @param atype CThemeScrollBarType, scroll bar type
   void load(int btnSize,std::string themeDir,CThemeScrollBarType atype);

   /// Clears the scrollbar images for the default theme
   void clear();

   /// Returns the button size - width of the button in horizontal scrollbar
   int buttonSize() { return m_buttonSize; }
};

/// @brief Widget themes
///
/// Class CThemes is a static loader for the themes. Only one one instance of the class should exist, and it's created automatically.
/// The class allows to load a set of routines to draw the particular elements of the interface, and the images for these routines.
class CThemes {
   static Fl_Box_Draw_F *m_flatBox;
   static Fl_Box_Draw_F *m_thinUpBox;
   static Fl_Box_Draw_F *m_upBox;
   static Fl_Box_Draw_F *m_thinDownBox;
   static Fl_Box_Draw_F *m_downBox;

   /// An array of the background images to replace the original FLTK colors
   /// FL_DARK3..FL_BACKGROUND..FL_LIGHT3
   static Fl_Image      *m_background[7];

   /// Four different types of button pixmaps - for normal button, normal pressed button, default button, and default pressed button accordingly.
   static CButtonImage   m_normalButtons[4];

   /// Two different types of combo box button pixmaps - for normal button, and normal pressed button. Two extra array members are reserved.
   static CButtonImage   m_comboButtons[4];

   /// Two different types of check box button pixmaps - for check box unchecked, and check box checked. Two extra array members are reserved.
   static CButtonImage   m_checkButtons[4];

   /// Two different types of radio button pixmaps - for radio button unchecked, and radio button checked. Two extra array members are reserved.
   static CButtonImage   m_radioButtons[4];

   /// Two different types of large button pixmaps - for large button, and large pressed button. Two extra array members are reserved.
   static CButtonImage   m_largeButtons[4];

   /// Two images for painting a progress bar.
   /// One image is for the frame, one for the progress bar itself. Images should have the 
   /// compatible size. If you put the progress bar image on top its frame - they should show 
   /// a picture of 100% progress
   static Fl_Image      *m_progressBar[2];

   /// Images for painting a scroll bar (horizontal and vertical).
   /// Images should have the compatible size. 
   /// If you put the slider image on top its frame - they should show 
   /// a picture of 100% progress
   static CScrollBarImages m_scrollBar[2];

   /// Flag indicating if buttons should be drawn as flat bars if mouse isn't over the button
   static bool           m_flatButtons;

   /// Theme registry. Contains several importang theme settings.
   static CRegistry     *m_registry;

   /// Restores the original FLTK theme
   static void reset();

   /// Returns the correct image array for the given button size
   /// @param sz CThemeButtonSize, the general type of the button. @see CThemeButtonSize for possible button types.
   static CButtonImage *sizeToButtonImages(CThemeButtonSize sz);

   /// Loads and sets the pixmap from the file for the given button size and type
   /// @param sz CThemeButtonSize, theme button size
   /// @param bt CThemeButtonType, theme button type
   /// @param fileName std::string, pixmap file name
   static void replaceButton(CThemeButtonSize sz,CThemeButtonType bt,std::string fileName);

   /// Loads and sets the pixmap from the file for the given pixmap array member
   /// @param ndx int, image index
   /// @param fileName std::string, pixmap file name
   static void replaceImage(Fl_Image *images[],int ndx,std::string fileName);

   /// Paints the rectangle with the background image.
   /// @param xx int, rectangle x-coordinate
   /// @param yy int, rectangle y-coordinate
   /// @param ww int, rectangle width
   /// @param hh int, rectangle height
   /// @param image Fl_Image *, image to use
   static void paintBackground(int xx,int yy,int ww,int hh,Fl_Image *image);

   /// Paints the image stretched horizontally.
   /// The image has left and right parts painted w/o changing. The part of 
   /// the image in the middle is stretched, currently - by the very primitive way.
   /// @param xx int, image x-coordinate
   /// @param yy int, image y-coordinate
   /// @param ww int, area width
   /// @param zz int, non-stretched sides of image on the left and right
   /// @param image Fl_Image *, image to use
   /// @param fragment CRect *, which fragment of the image to use
   static void paintHorizStretchedImage(int xx,int yy,int ww,int zz,Fl_Image *image,CRect *fragment=0);

   /// Paints the image stretched vertically.
   /// The image has top and bottom parts painted w/o changing. The part of 
   /// the image in the middle is stretched, currently - by the very primitive way.
   /// @param xx int, image x-coordinate
   /// @param yy int, image y-coordinate
   /// @param hh int, area height
   /// @param zz int, non-stretched sides of image on the left and right
   /// @param image Fl_Image *, image to use
   /// @param fragment CRect *, which fragment of the image to use
   static void paintVertStretchedImage(int xx,int yy,int hh,int zz,Fl_Image *image,CRect *fragment=0);

   /// Determines the background image (if any) for the given color in range
   /// FL_DARK3..FL_LIGHT3
   static Fl_Image *imageForColor(Fl_Color clr);

   /// Flag the shows if theme buttons should be desaturated for the inactive 
   /// state of the button
   static bool m_desaturateInactiveButtons;

   /// Defines a radius of the focus frame' corner
   static int  m_buttonFocusRadius;

public:

   /// Default constructor
   CThemes();

   /// Destructor
   ~CThemes();

   /// Loads and sets the theme. The themeName is the directory with the theme images.
   static void set(std::string themeName);

   /// The replacement rountine to draw standard FL_FLAT_BOX
   static void drawFlatBox(int x,int y,int w,int h,Fl_Color clr);

   /// The replacement rountine to draw standard FL_THIN_UP_BOX
   static void drawThinUpBox(int x,int y,int w,int h,Fl_Color clr);

   /// The replacement rountine to draw standard FL_UP_BOX
   static void drawUpBox(int x,int y,int w,int h,Fl_Color clr);

   /// The replacement rountine to draw standard FL_THIN_DOWN_BOX
   static void drawThinDownBox(int x,int y,int w,int h,Fl_Color clr);

   /// The replacement rountine to draw standard FL_DOWN_BOX
   static void drawDownBox(int x,int y,int w,int h,Fl_Color clr);

   /// The rountine to draw theme button
   /// @param sz CThemeButtonSize,
   /// @param x int, button x-coordinate
   /// @param y int, button y-coordinate
   /// @param w int&, button width, may be altered by button to meet the button size requirements
   /// @param h int&, button height, may be altered by button to meet the button size requirements
   /// @param highlited bool, true to draw the highlighted button
   /// @param pressed bool, true to draw pressed button
   /// @param defaultButton bool, true to draw default button
   static bool drawButton(CThemeButtonSize sz,int x,int y,int& w,int& h,bool highlited,bool pressed,bool defaultButton);

   /// Computes and returns the correct size of the button in the parameters.
   /// @param sz CThemeButtonSize, the general type of the button. @see CThemeButtonSize for possible button types.
   /// @param w int&, button width, may be altered by button to meet the button size requirements
   /// @param h int&, button height, may be altered by button to meet the button size requirements
   /// @returns false, if theme has no pixmap for the button, or true otherwise
   static bool sizeButton(CThemeButtonSize sz,int& w,int& h);

   /// Computes and returns the minimum size of the progress bar
   /// @param w int&, progress bar width, may be altered by progress bar to meet the progress bar size requirements
   /// @param h int&, progress bar height, may be altered by progress bar to meet the progress bar size requirements
   /// @returns false, if theme has no pixmap for the progress bar, or true otherwise
   static bool sizeProgressBar(int& w,int& h);

   /// Computes and returns the minimum size of the scroll bar
   /// @param w int&, scroll bar width, may be altered by scroll bar to meet the scroll bar size requirements
   /// @param h int&, scroll bar height, may be altered by scroll bar to meet the scroll bar size requirements
   /// @returns false, if theme has no pixmaps for the scroll bar, or true otherwise
   static bool sizeScrollBar(int& w,int& h);

   /// Returns the button focuse corner radius
   static int  buttonFocusRadius() { return m_buttonFocusRadius; }

   /// Draws a check button image
   /// @returns false, if theme has no pixmap for the button, or true otherwise
   /// @param x int, x-coordinate of the button
   /// @param y int, y-coordinate of the button
   /// @param checked bool, is button checked?
   /// @param highlited bool, is button highlited?
   static bool drawCheckButton(int x,int y,bool checked,bool highlited);

   /// Draws a radio button image
   /// @returns false, if theme has no pixmap for the button, or true otherwise
   /// @param x int, x-coordinate of the button
   /// @param y int, y-coordinate of the button
   /// @param checked bool, is button checked?
   /// @param highlited bool, is button highlited?
   static bool drawRadioButton(int x,int y,bool checked,bool highlited);

   /// Draws a progress bar image
   /// The height of the image is defined by the 'progress0.xpm' image of the theme.
   /// The width of the image is adjusted as required, but it can't be less than
   /// returned by sizeProgressBar() method.
   /// @returns false, if theme has no pixmaps for the progress bar, or true otherwise
   /// @param x int, x-coordinate of the progress bar
   /// @param y int, y-coordinate of the progress bar
   /// @param w int, width of the progress bar
   /// @param percent float, percent value of the progress bar
   static bool drawProgressBar(int x,int y,int w,float percent);

   /// Draws a scroll bar image. 
   /// The type of the scroll bar is defined by max of (w,h).
   /// @returns false, if theme has no pixmaps for the scroll bar, or true otherwise
   /// @param x int, x-coordinate of the scroll bar
   /// @param y int, y-coordinate of the scroll bar
   /// @param w int, width of the scroll bar
   /// @param h int, width of the scroll bar
   /// @param minimum float, minimum value of the scroll bar
   /// @param maximum float, maximum value of the scroll bar
   /// @param value float, value of the scroll bar
   /// @param size float, size of the scroll bar
   /// @param activeZone int, 0 - no active zone, 1 - button 1, 2 - button 2, 3 - slider, +8 - pushed
   /// @param active bool, true if scrollbar is active (enabled)
   static bool drawScrollBar(int x,int y,int w,int h,float minimum,float maximum,float value,float size,int activeZone,bool active);

   /// Returns the list of the available themes
   static CStrings availableThemes();

   /// Themes root directory
   static std::string directory(); /// Themes root directory
};

/// @}

#endif
