#include "CtrlLib.h"

namespace Upp {

#define LTIMING(x)  // TIMING(x)

CH_STYLE(ToolButton, Style, StyleDefault)
{
	CtrlsImageLook(look, CtrlsImg::I_TB, 6);
	font = StdFont();
	for(int i = 0; i < 4; i++)
		textcolor[i] = Button::StyleNormal().textcolor[i];
	textcolor[CTRL_CHECKED] = textcolor[CTRL_NORMAL];
	textcolor[CTRL_HOTCHECKED] = textcolor[CTRL_HOT];
	for(int i = 0; i < 6; i++) {
		light[i] = false;
		contrast[i] = 0;
	}
	light[CTRL_PRESSED] = light[CTRL_HOT] = light[CTRL_HOTCHECKED] = true;
	overpaint = 0;
}

CH_STYLE(ToolButton, Style, StyleSolid)
{
	const Button::Style& bs = Button::StyleNormal();
	look[0] = bs.look[0];
	look[1] = bs.look[1];
	look[2] = bs.look[2];
	look[3] = bs.look[3];
	look[4] = bs.look[2];
	look[5] = bs.look[1];
	font = StdFont();
	for(int i = 0; i < 4; i++)
		textcolor[i] = Button::StyleNormal().textcolor[i];
	textcolor[CTRL_CHECKED] = textcolor[CTRL_NORMAL];
	textcolor[CTRL_HOTCHECKED] = textcolor[CTRL_HOT];
	for(int i = 0; i < 6; i++) {
		light[i] = false;
		contrast[i] = 0;
	}
	light[CTRL_PRESSED] = light[CTRL_HOT] = light[CTRL_HOTCHECKED] = true;
}

ToolButton::ToolButton()
{
	Reset();
	checked = false;
	paint_checked = false;
	nodarkadjust = false;
	Transparent();
	kind = NOLABEL;
}

ToolButton::~ToolButton() {}

void ToolButton::ResetKeepStyle()
{
	repeat = false;
	accel = 0;
	checked = false;
	NoWantFocus();
	minsize = Size(0, 0);
	maxiconsize = Size(INT_MAX, INT_MAX);
	Tip("");
	Help("");
	Topic("");
	Description("");
}

void ToolButton::Reset()
{
	ResetKeepStyle();
	style = &StyleDefault();
}

void ToolButton::UpdateTip()
{
	LTIMING("UpdateTip");
	String s = tiptext;
	if(IsNull(s) && kind == NOLABEL)
		s = text;
	if(accel) {
		if(s.GetCount())
			s << ' ';
		s << '(' << GetKeyDesc(accel) << ')';
	}
	Ctrl::Tip(s);
}

Bar::Item& ToolButton::Text(const char *txt)
{
	String newtext;
	ExtractAccessKey(txt, newtext);
	if(newtext != text) {
		text = newtext;
		UpdateTip();
		Refresh();
	}
	return *this;
}

ToolButton& ToolButton::SetStyle(const Style& s)
{
	if(style != &s) {
		style = &s;
		Refresh();
	}
	return *this;
}

Bar::Item& ToolButton::Check(bool check)
{
	if(checked != check) {
		checked = check;
		Refresh();
	}
	return *this;
}

Bar::Item& ToolButton::Radio(bool check)
{
	return Check(check);
}

Bar::Item& ToolButton::Key(dword key)
{
	if(key) {
		accel = key;
		UpdateTip();
	}
	return *this;
}

Bar::Item& ToolButton::Repeat(bool r)
{
	repeat = r;
	return *this;
}

ToolButton& ToolButton::Label(const char *text, int _kind)
{
	if(kind != _kind) {
		kind = _kind;
		Refresh();
	}
	Text(text);
	return *this;
}

ToolButton& ToolButton::Label(const char *text)
{
	Label(text, kind == NOLABEL ? RIGHTLABEL : kind);
	return *this;
}

ToolButton& ToolButton::Kind(int _kind)
{
	if(kind != _kind)
		Refresh();
	return *this;
}

Image ToolButton::GetImage() const
{
	UPP::Image m = img;
	if(IsDarkColorFace() && !nodarkadjust)
		m = MakeImage(m, AdjustForDarkBk);
	m = CachedRescale(m, min(m.GetSize(), maxiconsize));
	return m;
}

Bar::Item& ToolButton::Image(const UPP::Image& img_)
{
	Upp::Image m = img_;
	if(!m.IsSame(img)) {
		img = m;
		Refresh();
	}
	return *this;
}

Bar::Item& ToolButton::Enable(bool enable)
{
	Ctrl::Enable(enable);
	return *this;
}

Bar::Item& ToolButton::Tip(const char *tip)
{
	if(tiptext != tip) {
		tiptext = tip;
		UpdateTip();
	}
	return *this;
}

Bar::Item& ToolButton::Help(const char *help)
{
	HelpLine(help);
	return *this;
}

Bar::Item& ToolButton::Topic(const char *help)
{
	HelpTopic(help);
	return *this;
}

Bar::Item& ToolButton::Description(const char *desc)
{
	Ctrl::Description(desc);
	return *this;
}

struct sCachedContrast : public ImageMaker
{
	int   d;
	Image img;

	virtual String Key() const {
		String s;
		RawCat(s, d);
		RawCat(s, img.GetSerialId());
		return s;
	}

	virtual Image Make() const {
		return Contrast(img, 256 + d);
	}
};

Image CachedContrast(const Image& m, int d)
{
	if(d == 0)
		return m;
	sCachedContrast cr;
	cr.d = d;
	cr.img = m;
	return MakeImage(cr);
}

void  ToolButton::Paint(Draw& w)
{
	LTIMING("ToolButton::Paint");
	paint_checked = checked;
	Size sz = GetSize();
	UPP::Image image = GetImage();
	Size isz = image.GetSize();
//	Ctrl *q = GetParent()->GetParent();
//	if(!q || !q->IsTransparent())
//		w.DrawRect(sz, checked && !HasMouse() ? Blend(SColorFace, SColorLight) : SColorFace);
	int li = IsEnabled() ? HasMouse() ? GetMouseLeft() ? CTRL_PRESSED
						                               : checked ? CTRL_HOTCHECKED : CTRL_HOT
				                       : checked ? CTRL_CHECKED : CTRL_NORMAL
					     : CTRL_DISABLED;
	ChPaint(w, sz, style->look[li]);
	Point off = style->offset[li];
	Point ip = (sz - isz) / 2 + off;
	Size tsz(0, 0);
	if(kind != NOLABEL)
		tsz = GetTextSize(text, style->font);
	if(kind == BOTTOMLABEL) {
		ip.y  -= tsz.cy / 2 + 1;
		w.DrawText((sz.cx - tsz.cx) / 2 + off.x, ip.y + isz.cy + 2 + off.y, text, style->font, style->textcolor[li]);
	}
	if(kind == RIGHTLABEL) {
		ip.x -= tsz.cx / 2 + 2;
		w.DrawText(ip.x + isz.cx + 3 + off.x, (sz.cy - tsz.cy) / 2 + off.y, text, style->font, style->textcolor[li]);
	}
	UPP::Image img = CachedContrast(image, style->contrast[li]);
	if(!IsEnabled())
		img = DisabledImage(img);
	if(IsEnabled() && style->light[li])
		DrawHighlightImage(w, ip.x, ip.y, img, true);
	else
		w.DrawImage(ip.x, ip.y, img);
}

void  ToolButton::MouseEnter(Point, dword)
{
	BarCtrl::SendHelpLine(this);
	Refresh();
}

void  ToolButton::MouseLeave()
{
	BarCtrl::ClearHelpLine(this);
	Refresh();
}

Size  ToolButton::GetMinSize() const
{
	UPP::Image image = GetImage();
	Size sz = image.GetSize();
	if(sz.IsEmpty())
		sz = Size(16, 16);
	sz += 6;
	if(text.GetCount()) {
		Size tsz = GetTextSize(text, style->font);
		if(kind == BOTTOMLABEL) {
			sz.cy += tsz.cy + 3;
			sz.cx = max(sz.cx, tsz.cx + 9);
		}
		if(kind == RIGHTLABEL) {
			sz.cx += tsz.cx + 6;
			sz.cy = max(sz.cy, tsz.cy + 6);
		}
	}
	return max(sz, minsize);
}

void  ToolButton::LeftDown(Point, dword)
{
	Refresh();
	if(repeat)
		WhenAction();
}

void  ToolButton::LeftRepeat(Point, dword)
{
	Refresh();
	if(repeat)
		WhenAction();
}

void  ToolButton::LeftUp(Point, dword)
{
	Refresh();
	if(!repeat)
		WhenAction();
}

bool  ToolButton::HotKey(dword key)
{
	if(key == accel) {
		WhenAction();
		return true;
	}
	return false;
}

void ToolButton::FinalSync()
{
	if(checked != paint_checked)
		Refresh();
}

String ToolButton::GetDesc() const
{
	return tiptext;
}

int ToolButton::OverPaint() const
{
	return style->overpaint;
}

}
