/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CThemes.cpp  -  description
                             -------------------
    begin                : Fri Nov 08 20003
    copyright            : (C) 2003-2006 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>
#include <sptk3/CFont.h>

namespace sptk {

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

   /// @brief 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;

		static CFontsMap      m_fonts;

      /// 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();  

		/// @brief All the available screen fonts
		static CFontsVector   screenFonts;
	};

   /// @}
}
#endif
