/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CThemes.cpp  -  description
                             -------------------
    begin                : Fri Nov 08 2003
    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"
 ***************************************************************************/

#include <FL/fl_draw.h>
#include <FL/Fl_XPM_Image.h>
#include <FL/Enumerations.h>
#include <sptk3/sptk.h>
#include <sptk3/CThemes.h>
#include <sptk3/CDirectoryDS.h>
#include <sptk3/string_ext.h>

#ifdef _WIN32   
#include <windows.h>
#endif

#include <stdio.h>

using namespace std;
using namespace sptk;

extern void fl_internal_boxtype(Fl_Boxtype,Fl_Box_Draw_F*);

CFontsVector   CThemes::screenFonts;
CFontsMap      CThemes::m_fonts;

Fl_Box_Draw_F *CThemes::m_flatBox;
Fl_Box_Draw_F *CThemes::m_thinUpBox;
Fl_Box_Draw_F *CThemes::m_upBox;
Fl_Box_Draw_F *CThemes::m_thinDownBox;
Fl_Box_Draw_F *CThemes::m_downBox;

Fl_Image      *CThemes::m_background[7];
Fl_Image      *CThemes::m_progressBar[2];
CScrollBarImages CThemes::m_scrollBar[2];
CButtonImage   CThemes::m_normalButtons[4];
CButtonImage   CThemes::m_comboButtons[4];
CButtonImage   CThemes::m_checkButtons[4];
CButtonImage   CThemes::m_radioButtons[4];
CButtonImage   CThemes::m_largeButtons[4];
bool           CThemes::m_flatButtons;

CRegistry     *CThemes::m_registry;
bool           CThemes::m_desaturateInactiveButtons;
int            CThemes::m_buttonFocusRadius;

CThemes        themes;

CButtonImage::CButtonImage(Fl_Image *img) { 
	m_colorImage = m_grayImage = 0L; set(img,false);
}

void CButtonImage::clear() {
	if (m_colorImage) {
		delete m_colorImage;
		delete m_grayImage;
		m_colorImage = m_grayImage = 0L;
	}
}

CButtonImage::~CButtonImage() {
	clear();
}

void CButtonImage::set(Fl_Image *img,bool desaturateInactive) {
	clear();
	if (img) {
		m_colorImage = img;
		m_grayImage  = img->copy();
		if (desaturateInactive)
			m_grayImage->desaturate();
	}
}

static Fl_XPM_Image *loadValidateXPMImage(string fileName) {
	Fl_XPM_Image *img = new Fl_XPM_Image(fileName.c_str());
	if (img) {
		if (img->data()) return img;
		delete img;
		img = 0L;
	}
	return img;
}

void CScrollBarImages::load(int buttonSize,string themeDir,CThemeScrollBarType atype) {
	m_buttonSize = buttonSize;
	string scrollBarDir = themeDir+"/";
	if (atype == THM_SCROLLBAR_VERTICAL) 
		scrollBarDir += "vscrollbar";
	else
		scrollBarDir += "hscrollbar";
	clear();
	m_normalImage = loadValidateXPMImage(scrollBarDir+"0.xpm");
	m_activeImage = loadValidateXPMImage(scrollBarDir+"1.xpm");
	m_sliderImage = loadValidateXPMImage(scrollBarDir+"2.xpm");
}

void CScrollBarImages::clear() {
	if (m_normalImage) {
		delete m_normalImage;
		m_normalImage = 0L;
	}
	if (m_activeImage) {
		delete m_activeImage;
		m_activeImage = 0L;
	}
	if (m_sliderImage) {
		delete m_sliderImage;
		m_sliderImage = 0L;
	}
}

CThemes::CThemes() {
	m_flatBox = Fl::get_boxtype(FL_FLAT_BOX);
	m_thinUpBox = Fl::get_boxtype(FL_THIN_UP_BOX);
	m_upBox = Fl::get_boxtype(FL_UP_BOX);
	m_thinDownBox = Fl::get_boxtype(FL_THIN_DOWN_BOX);
	m_downBox = Fl::get_boxtype(FL_DOWN_BOX);

	m_registry = 0L;
	m_desaturateInactiveButtons = false;
	m_buttonFocusRadius = 0;

	unsigned i;
	for (i = 0; i < 7; i++) m_background[i] = 0L;

	if (!screenFonts.size()) {
		int k = Fl::set_fonts("*");
		for (int i = 0; i < k; i++) {
			int attributes = 0; 
			string fontName = Fl::get_font_name((Fl_Font)i,&attributes);
			CFont* font = new CFont(fontName,10,0,i,attributes);
			screenFonts.push_back(font);
		}
	}
}

CThemes::~CThemes() {
	if (m_registry) delete m_registry;
}

string CThemes::directory() {
#ifdef _WIN32   
	char windir[128];
	GetWindowsDirectory(windir,128);
	return windir + string("\\.themes.sptk");
#else
	return string(THEMES_PREFIX) + "/share/sptk";
#endif
}

void CThemes::reset() {
	Fl::set_boxtype(FL_FLAT_BOX,m_flatBox,0,0,0,0);
	Fl::set_boxtype(FL_THIN_UP_BOX,m_thinUpBox,1,1,2,2);
	Fl::set_boxtype(FL_UP_BOX,m_upBox,2,2,4,4);
	Fl::set_boxtype(FL_THIN_DOWN_BOX,m_thinDownBox,1,1,2,2);
	Fl::set_boxtype(FL_DOWN_BOX,m_downBox,2,2,4,4);

	unsigned i = 0;
	for (; i < 4; i++) 
		m_normalButtons[i].clear();

	for (i = 0; i < 2; i++) {
		m_comboButtons[i].clear();
		m_radioButtons[i].clear();
		m_checkButtons[i].clear();
	}
	m_scrollBar[THM_SCROLLBAR_VERTICAL].clear();
	m_scrollBar[THM_SCROLLBAR_HORIZONTAL].clear();
}

CButtonImage *CThemes::sizeToButtonImages(CThemeButtonSize sz) {
	switch (sz) {
		case THM_BUTTON_COMBO:
			return m_comboButtons;
		case THM_BUTTON_CHECK:
			return m_checkButtons;
		case THM_BUTTON_RADIO:
			return m_radioButtons;
		case THM_BUTTON_LARGE:
			return m_largeButtons;
		case THM_BUTTON_NORMAL:
			break;
	}
	return m_normalButtons;
}

void CThemes::replaceButton(CThemeButtonSize sz,CThemeButtonType btndx,string fileName) {
	Fl_XPM_Image *img = loadValidateXPMImage(fileName);
	CButtonImage *buttons = sizeToButtonImages(sz);
	if (img)
		buttons[btndx].set(img,m_desaturateInactiveButtons);
	else
		buttons[btndx].clear();
}

void CThemes::replaceImage(Fl_Image *images[],int ndx,string fileName) {
	if (images[ndx]) 
		delete images[ndx]; 
	images[ndx] = loadValidateXPMImage(fileName);
}

void CThemes::set(string themeName) {
	reset();
	if (themeName == "" || themeName == "default")
		return;
#ifdef _WIN32   
	string slash = "\\";
	char windir[128];
	GetWindowsDirectory(windir,128);
	string dirname = directory() + slash + themeName;
#else
	string slash = "/";
	string dirname = directory() + slash + themeName;
#endif

	m_desaturateInactiveButtons = false;
	int scrollBarButtonSize = 0;
	try {
		if (m_registry) delete m_registry;
		m_registry = new CRegistry(dirname + slash + "theme.ini","",PROGRAM_REGISTRY);
		bool defaultTheme = (lowerCase(themeName) == "default");

		if (!defaultTheme) 
			m_registry->load();

		CXmlNode* buttonsNode = m_registry->findOrCreate("buttons",false);
		m_desaturateInactiveButtons = buttonsNode->getAttribute("DesaturateInactive","N");
		m_buttonFocusRadius = buttonsNode->getAttribute("FocusRadius","0");
		m_flatButtons = buttonsNode->getAttribute("FlatInactive","N");

		CXmlNode* fontsTopic = m_registry->findOrCreate("fonts",false);
		m_fonts.clear();
		for (CXmlNode::iterator itor = fontsTopic->begin(); itor != fontsTopic->end(); itor++) {
			CXmlNode* fontInfo = *itor;
			string fontName = fontInfo->getAttribute("name","Arial");
			CFont* screenFont = screenFonts.find(fontName);
			if (!screenFont) continue;
			string object = fontInfo->getAttribute("object","Arial");
			CFont* font = new CFont(fontName,
					fontInfo->getAttribute("size","10"),
					fontInfo->getAttribute("color","0"),
					screenFont->index(),
					screenFont->attributes()
				);
			m_fonts[object] = font;
		}
		CFontsMap::iterator ftor = m_fonts.find("default");
		if (ftor == m_fonts.end()) {
			CFont* font = screenFonts[0];
			m_fonts["default"] = new CFont(font->name(),10,0,font->index(),font->attributes());
		}
	}
	catch (...) {}

	unsigned i;
	for (i = 0; i < 7; i++) 
		replaceImage(m_background,i,dirname + slash + "background"+int2string(i)+".xpm");

	for (i = 0; i < 2; i++) 
		replaceImage(m_progressBar,i,dirname + slash + "progress"+int2string(i)+".xpm");

	for (i = 0; i < 4; i++) 
		replaceButton(THM_BUTTON_NORMAL,CThemeButtonType(i),dirname + slash + "button"+int2string(i)+".xpm");

	for (i = 0; i < 2; i++) {
		replaceButton(THM_BUTTON_COMBO,CThemeButtonType(i),dirname + slash + "combo_button"+int2string(i)+".xpm");
		replaceButton(THM_BUTTON_CHECK,CThemeButtonType(i),dirname + slash + "check_button"+int2string(i)+".xpm");
		replaceButton(THM_BUTTON_RADIO,CThemeButtonType(i),dirname + slash + "radio_button"+int2string(i)+".xpm");
		replaceButton(THM_BUTTON_LARGE,CThemeButtonType(i),dirname + slash + "large_button"+int2string(i)+".xpm");
	}

	try {	
		CXmlNode& topic = *m_registry->findFirst("scrollbars",false);
		if (&topic) 
			scrollBarButtonSize = topic.getAttribute("ButtonSize","16");
	}
	catch (...) {}

	//m_registry->save();

	m_scrollBar[THM_SCROLLBAR_VERTICAL].load(scrollBarButtonSize,dirname,THM_SCROLLBAR_VERTICAL);
	m_scrollBar[THM_SCROLLBAR_HORIZONTAL].load(scrollBarButtonSize,dirname,THM_SCROLLBAR_HORIZONTAL);

	Fl::set_boxtype(FL_FLAT_BOX,drawFlatBox,0,0,0,0);
	Fl::set_boxtype(FL_THIN_DOWN_BOX,drawThinDownBox,1,1,2,2);
	Fl::set_boxtype(FL_DOWN_BOX,drawDownBox,2,2,4,4);
	Fl::set_boxtype(FL_UP_BOX,drawUpBox,2,2,4,4);
	Fl::set_boxtype(FL_THIN_UP_BOX,drawThinUpBox,1,1,2,2);
}

Fl_Image *CThemes::imageForColor(Fl_Color clr) {
	if (clr >= FL_DARK3 && clr <= FL_LIGHT3) {
		int ndx = 0;
		switch (clr) {
			case FL_DARK3: ndx = 0; break;
			case FL_DARK2: ndx = 1; break;
			case FL_DARK1: ndx = 2; break;
			case FL_BACKGROUND_COLOR: ndx = 3; break;
			case FL_LIGHT1: ndx = 4; break;
			case FL_LIGHT2: ndx = 5; break;
			case FL_LIGHT3: ndx = 6; break;
			default: return 0;
		}
		return m_background[ndx];
	}
	return 0L;
}

void CThemes::paintBackground(int xx,int yy,int ww,int hh,Fl_Image *image) {
	if (!image) return;
	if (ww < 0 || hh < 0) return;
	int dx = image->w();
	int dy = image->h();
	fl_push_clip(xx,yy,ww,hh);
	int maxx = xx + ww;
	int maxy = yy + hh;
   /// Image alignments
	yy = (yy / dy) * dy;
	xx = (xx / dx) * dx;
	for (int xi = xx; xi < maxx; xi += dx) {
		for (int yi = yy; yi < maxy; yi += dy) {
			image->draw(xi,yi,dx,dy,0,0);
         //image->draw(xi,yi);
		}
	}
	fl_pop_clip();
}

void CThemes::drawFlatBox(int x,int y,int w,int h,Fl_Color clr) {
	Fl_Image *image = imageForColor(clr);
	if (image) {
		paintBackground(x,y,w,h,image);
	} else {
		fl_color(clr);
		fl_rectf(x,y,w,h);
	}
}

void CThemes::drawThinUpBox(int x,int y,int w,int h,Fl_Color clr) {
	Fl_Image *image = imageForColor(clr);
	if (image) {
		paintBackground(x,y,w,h,image);
	} else {
		fl_color(clr);
		fl_rectf(x,y,w,h);
	}
	fl_draw_box(FL_THIN_UP_FRAME,x,y,w,h,clr);
}

void CThemes::drawUpBox(int x,int y,int w,int h,Fl_Color clr) {
	Fl_Image *image = imageForColor(clr);
	if (image) {
		paintBackground(x,y,w,h,image);
	} else {
		fl_color(clr);
		fl_rectf(x,y,w,h);
	}
	fl_draw_box(FL_UP_FRAME,x,y,w,h,clr);
}

void CThemes::drawThinDownBox(int x,int y,int w,int h,Fl_Color clr) {
	Fl_Image *image = imageForColor(clr);
	if (image) {
		paintBackground(x,y,w,h,image);
	} else {
		fl_color(clr);
		fl_rectf(x,y,w,h);
	}
	fl_draw_box(FL_THIN_DOWN_FRAME,x,y,w,h,clr);
}

void CThemes::drawDownBox(int x,int y,int w,int h,Fl_Color clr) {
	Fl_Image *image = imageForColor(clr);
	if (image) {
		paintBackground(x,y,w,h,image);
	} else {
		fl_color(clr);
		fl_rectf(x,y,w,h);
	}
	fl_draw_box(FL_DOWN_FRAME,x,y,w,h,clr);
}

bool CThemes::sizeButton(CThemeButtonSize sz,int& w,int& h) {
	CButtonImage *buttons = sizeToButtonImages(sz);
	Fl_Image *image = buttons[0].m_colorImage;
	if (!image) return false;
	if (sz == THM_BUTTON_COMBO) {
		w = image->w();
	} else {
		if (w < image->h() + CThemes::m_buttonFocusRadius)
			w = image->h() + CThemes::m_buttonFocusRadius;
	}
	h = image->h();
	return true;
}

void CThemes::paintHorizStretchedImage(int x,int y,int w,int zone,Fl_Image *image,CRect *fragment) {
	int imageX = 0;
	int imageY = 0;

	int imageW = image->w();
	if (fragment && fragment->x()+fragment->w() < imageW) {
		imageX = fragment->x();
		imageW = fragment->w();
	}

	int imageH = image->h();
	if (fragment && fragment->y()+fragment->h() < imageH) {
		imageY = fragment->y();
		imageH = fragment->h();
	}

	int sideFrame = w / 2;
	if (w % 2) sideFrame++;

	if (imageW < sideFrame * 2) {
		sideFrame = imageW / 2 - 2;
		if (sideFrame < 0) sideFrame = 0;
	}
	if (zone > sideFrame) zone = sideFrame;

   // Draw the left edge
	image->draw(x,y,zone,imageH,imageX,imageY);

   // Draw the middle area
	int xstart = x + zone;
	int xend = x + w - zone;
	int xsize = imageW - 2 * zone;
	if (xsize > 0) {
		for (int xx = xstart; xx < xend; xx += xsize) {
			if (xx + xsize > xend) xsize = xend - xx;
			image->draw(xx,y,xsize,imageH,imageX+zone,imageY);
		}
	}

  // Draw the right edge
	image->draw(x+w-zone,y,zone,imageH,imageX+imageW-zone,imageY);
}

void CThemes::paintVertStretchedImage(int x,int y,int h,int zone,Fl_Image *image,CRect *fragment) {
	int imageX = 0;
	int imageY = 0;

	int imageW = image->w();
	int imageH = image->h();

	if (fragment && fragment->x()+fragment->w() < imageW) {
		imageX = fragment->x();
		imageW = fragment->w();
	}

	if (fragment && fragment->y()+fragment->h() < imageH) {
		imageY = fragment->y();
		imageH = fragment->h();
	}

	int sideFrame = h / 2;
	if (h % 2) sideFrame++;

	if (imageH < sideFrame * 2) {
		sideFrame = imageH / 2 - 2;
		if (sideFrame < 0) sideFrame = 0;
	}
	if (zone > sideFrame) zone = sideFrame;

   // Draw the top edge
	image->draw(x,y,imageW,zone,imageX,imageY);

   // Draw the middle area
	int ystart = y + zone;
	int yend = y + h - zone;
	int ysize = imageH - 2 * zone;
	if (ysize > 0) {
		for (int yy = ystart; yy < yend; yy += ysize) {
			if (yy + ysize > yend) ysize = yend - yy;
			image->draw(x,yy,imageW,ysize,imageX,imageY+zone);
		}
	}

  // Draw the bottom edge
	image->draw(x,y+h-zone,imageW,zone,imageX,imageY+imageH-zone);
}

bool CThemes::drawButton(CThemeButtonSize sz,int x,int y,int& w,int& h,bool highlited,bool pressed,bool defaultButton) {
	int ndx = 0;
	if (defaultButton) {
		x -= 2;
		y -= 2;
		ndx += 2;
	}

	if (pressed) ndx++;

	Fl_Image *image;
	CButtonImage *buttons = sizeToButtonImages(sz);
	if (highlited) 
		image = buttons[ndx].m_colorImage;
	else image = buttons[ndx].m_grayImage;

	if (!image || image->w() < 10) {
		return false;
	}

	h = image->h();

	if (m_flatButtons && !highlited) {
		if (defaultButton) {
			fl_draw_box(FL_DOWN_BOX,x,y,w,h,FL_BACKGROUND_COLOR);
		} else {
			fl_draw_box(FL_FLAT_BOX,x,y,w,h,FL_BACKGROUND_COLOR);
		}
	} else {
		paintHorizStretchedImage(x,y,w,10,image);
	}

	return true;
}

bool CThemes::drawCheckButton(int x,int y,bool checked,bool highlited) {
	Fl_Image *image;
	int ndx = 0;
	if (checked) ndx = 1;
	if (highlited) 
		image = m_checkButtons[ndx].m_colorImage;
	else image = m_checkButtons[ndx].m_grayImage;

	if (!image || image->w() < 10) return false;

	image->draw(x,y);

	return true;
}

bool CThemes::drawRadioButton(int x,int y,bool checked,bool highlited) {
	Fl_Image *image;
	int ndx = 0;
	if (checked) ndx = 1;
	if (highlited) 
		image = m_radioButtons[ndx].m_colorImage;
	else image = m_radioButtons[ndx].m_grayImage;

	if (!image || image->w() < 10) return false;

	image->draw(x,y);

	return true;
}

bool CThemes::sizeProgressBar(int& w,int& h) {
	Fl_Image *image = m_progressBar[0];
	if (image && image->data()) {
		w = image->w();
		h = image->h();
		return true;
	} else {
		w = h = 0;
		return false;
	}
}

bool CThemes::drawProgressBar(int x,int y,int w,float percent) {
	if (percent > 100) percent = 100;
	if (percent < 0) percent = 0;
	if (m_progressBar[0] && m_progressBar[0]->data()) {
		int xspace = (m_progressBar[0]->w() - m_progressBar[1]->w()) / 2; 
		int yspace = (m_progressBar[0]->h() - m_progressBar[1]->h()) / 2; 
		int psize  = int((w - xspace * 2) * percent / 100 + 0.5);
		paintHorizStretchedImage(x,y,w,10,m_progressBar[0]);
		paintHorizStretchedImage(x+xspace,y+yspace,psize,8,m_progressBar[1]);
		return true;
	} else {
		return false;
	}
}

bool CThemes::sizeScrollBar(int& w,int& h) {
	bool vertical = w < h;
	CScrollBarImages *images = &m_scrollBar[THM_SCROLLBAR_HORIZONTAL];
	if (vertical)
		images = &m_scrollBar[THM_SCROLLBAR_VERTICAL];
	if (images->m_normalImage) {
		if (vertical) {
			w = images->m_normalImage->w();
			if (h < images->buttonSize() * 2 + 10)
				h = images->buttonSize() * 2 + 10;
		} else {
			h = images->m_normalImage->h();
			if (w < images->buttonSize() * 2 + 10)
				w= images->buttonSize() * 2 + 10;
		}
		return true;
	}
	if (vertical) {
		w = 16;
		if (h < 44) h = 44;
	} else {
		h = 16;
		if (w < 44) w = 44;
	}
	return false;
}

bool CThemes::drawScrollBar(int x,int y,int w,int h,float minimum,float maximum,float value,float sliderSize,int activeZone,bool active) {
	bool vertical = w < h;

   // Selecting the group of images
	CScrollBarImages *images = &m_scrollBar[THM_SCROLLBAR_HORIZONTAL];
	if (vertical)
		images = &m_scrollBar[THM_SCROLLBAR_VERTICAL];

   // Painting the background
	int bsize = images->buttonSize();
	if (!bsize) bsize = 14;
	Fl_Image *normalImage = images->m_normalImage;
	Fl_Image *activeImage = images->m_activeImage;
	if (normalImage && activeImage) {
		if (vertical) {
			CRect backgroundRect(0,bsize,normalImage->w(),normalImage->h()-bsize*2-1); 
			paintVertStretchedImage(x,y+bsize,h-bsize*2,10,normalImage,&backgroundRect);
		} else {
			CRect backgroundRect(bsize,0,normalImage->w()-bsize*2-1,normalImage->h()); 
			paintHorizStretchedImage(x+bsize,y,w-bsize*2,10,normalImage,&backgroundRect);
		}
	} else {
		fl_draw_box(FL_THIN_DOWN_BOX,x,y,w,h,FL_DARK3);
	}

   // Painting the buttons
	Fl_Image *firstButtonSrc = normalImage;
	Fl_Image *secondButtonSrc = normalImage;
	switch (activeZone) {
		case 1: firstButtonSrc = activeImage; break;
		case 2: secondButtonSrc = activeImage; break;
	}

	if (normalImage) {
      // Images available
		if (vertical) {
			firstButtonSrc->draw(x,y,normalImage->w(),bsize,0,0);
			secondButtonSrc->draw(x,y+h-bsize,normalImage->w(),bsize,0,normalImage->h()-bsize-1);
		} else {
			firstButtonSrc->draw(x,y,bsize,normalImage->h(),0,0);
			secondButtonSrc->draw(x+w-bsize,y,bsize,normalImage->h(),normalImage->w()-bsize-1,0);
		}
	} else {
      // Images not available
		if (vertical) {
			fl_draw_box(activeZone==1?FL_FLAT_BOX:FL_THIN_UP_BOX,x+1,y+1,w-2,bsize,FL_BACKGROUND_COLOR);
			fl_draw_box(activeZone==2?FL_FLAT_BOX:FL_THIN_UP_BOX,x+1,y+h-bsize-1,w-2,bsize,FL_BACKGROUND_COLOR);
			if (active)
				fl_color(FL_BLACK);
			else
				fl_color(fl_inactive(FL_BLACK));
			int w1 = (w-4)/3; if (w1 < 1) w1 = 1;
			int x1 = x+(w-2*w1-1)/2;
			int yy1 = y+(w-w1-1)/2;
			fl_polygon(x1, yy1+w1, x1+2*w1, yy1+w1, x1+w1, yy1);
			yy1 += h-w;
			fl_polygon(x1, yy1, x1+w1, yy1+w1, x1+2*w1, yy1);
		} else {
			fl_draw_box(activeZone==1?FL_FLAT_BOX:FL_THIN_UP_BOX,x+1,y+1,bsize,h-2,FL_BACKGROUND_COLOR);
			fl_draw_box(activeZone==2?FL_FLAT_BOX:FL_THIN_UP_BOX,x+w-bsize-1,y+1,bsize,h-2,FL_BACKGROUND_COLOR);
			if (active)
				fl_color(FL_BLACK);
			else
				fl_color(fl_inactive(FL_BLACK));
			int w1 = (h-4)/3; if (w1 < 1) w1 = 1;
			int x1 = x+(h-w1-1)/2;
			int yy1 = y+(h-2*w1-1)/2;
			fl_polygon(x1, yy1+w1, x1+w1, yy1+2*w1, x1+w1, yy1);
			x1 += (w-h);
			fl_polygon(x1, yy1, x1, yy1+2*w1, x1+w1, yy1+w1);
		}
	}

   // Draw the slider
	double val;
	if (minimum == maximum)
		val = 0.5;
	else {
		val = (value-minimum)/(maximum-minimum);
		if (val > 1.0) val = 1.0;
		else if (val < 0.0) val = 0.0;
	}

	int ww = (vertical ? h : w) - bsize * 2;
	int S = int(sliderSize * ww+.5);
	if (S < 10) S = 10;
	int xx = int(val*(ww-S)+.5) + bsize;

	int xsl, ysl, wsl, hsl;
	Fl_Image *sliderImage = images->m_sliderImage;
	if (vertical) {
		ysl = y+xx;
		hsl = S;
		xsl = x;
		wsl = w;
		if (hsl > 0 && sliderImage) {
			int offset = (wsl - sliderImage->w()) / 2;
			paintVertStretchedImage(xsl+offset,ysl,hsl,10,sliderImage);
		}
	} else {
		xsl = x+xx;
		wsl = S;
		ysl = y;
		hsl = h;
		if (wsl > 0 && sliderImage) { 
			int offset = (hsl - sliderImage->h()) / 2;
			paintHorizStretchedImage(xsl,ysl+offset,wsl,10,sliderImage);
		}
	}
	if (!normalImage && wsl>0 && hsl>0) {
		fl_draw_box(FL_THIN_UP_BOX,xsl+1,ysl+1,wsl-2,hsl-2,FL_BACKGROUND_COLOR);
	}

	return true;
}

CStrings CThemes::availableThemes() {
	CStrings  themes;
	CDirectoryDS   dir;
	themes.push_back("Default");
	try {
		dir.directory(directory());

		dir.showPolicy(DDS_HIDE_FILES|DDS_HIDE_DOT_FILES);
		dir.open();
		while (!dir.eof()) {
			if (dir["Type"].asString() == "Directory") {
				std::string dirName = dir["Name"];
				if (dirName != "CVS")
					themes.push_back(dirName);
			}
			dir.next();
		}
	}
	catch (...) {
	}
	dir.close();

	return themes;
}
