/***************************************************************************

	CButton.cpp

	(c) 2000-2017 Benoît Minisini <g4mba5@gmail.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2, or (at your option)
	any later version.

	This program 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
	MA 02110-1301, USA.

***************************************************************************/

#define __CBUTTON_CPP

#include <qapplication.h>
#include <qevent.h>
#include <qpushbutton.h>
#include <qtoolbutton.h>
#include <qsizepolicy.h>
#include <qicon.h>
#include <qlayout.h>
#include <qobject.h>
//Added by qt3to4:
#include <QResizeEvent>
#include <QPixmap>
#include <QStylePainter>
#include <QStyleOptionToolButton>

#include "gambas.h"

#include "CWidget.h"
#include "CPicture.h"
#include "CWindow.h"
#include "CButton.h"

/*#define DEBUG_CBUTTON*/

DECLARE_EVENT(EVENT_Click);
DECLARE_EVENT(EVENT_ClickToggle);
DECLARE_EVENT(EVENT_ClickTool);

//---------------------------------------------------------------------------

static void set_button_text(CBUTTON *_object, const QString &text)
{
	WIDGET->setText(text);
	WIDGET->calcMinimumSize();
}

static void set_button_picture(CBUTTON *_object)
{
	QPixmap p;
	QIcon icon;

	if (THIS->picture)
	{
		p = *(THIS->picture->pixmap);
		CWIDGET_iconset(icon, p);
		WIDGET->setIcon(icon);
		WIDGET->setIconSize(p.size());
	}
	else
	{
		WIDGET->setIcon(icon);
	}

	WIDGET->calcMinimumSize();
}

static void set_tool_button(CBUTTON *_object, bool set_text, QString text)
{
	QPixmap p;
	QIcon icon;

	if (!set_text)
		text = WIDGET_TOOL->text();

	if (THIS->picture)
	{
		p = *(THIS->picture->pixmap);

		WIDGET_TOOL->setText(text);
		CWIDGET_iconset(icon, p);

		WIDGET_TOOL->setIcon(icon);
		WIDGET->setIconSize(p.size());
		//WIDGET_TOOL->setUsesTextLabel(qtext.length() > 0);
		if (text.length())
			WIDGET_TOOL->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
		else
			WIDGET_TOOL->setToolButtonStyle(Qt::ToolButtonIconOnly);
	}
	else
	{
		WIDGET_TOOL->setIcon(icon);
		WIDGET_TOOL->setText(text);
		WIDGET_TOOL->setToolButtonStyle(Qt::ToolButtonTextOnly);
		//WIDGET_TOOL->setUsesTextLabel(qtext.length() > 0);
	}

	WIDGET->calcMinimumSize();
}

//---------------------------------------------------------------------------


BEGIN_METHOD(CBUTTON_new, GB_OBJECT parent)

	MyPushButton *wid = new MyPushButton(QCONTAINER(VARG(parent)));

	QObject::connect(wid, SIGNAL(clicked()), &CButton::manager, SLOT(clicked()));

	wid->setAutoDefault(false);

	CWIDGET_new(wid, (void *)_object);

	// We assume that the button widget destructor will always be called before
	// its gambas window is released.
	WIDGET->top = CWidget::getWindow((CWIDGET *)THIS);

END_METHOD


BEGIN_METHOD(CTOGGLEBUTTON_new, GB_OBJECT parent)

	QPushButton *wid = new MyPushButton(QCONTAINER(VARG(parent)));

	QObject::connect(wid, SIGNAL(toggled(bool)), &CButton::manager, SLOT(clickedToggle()));

	//wid->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
	wid->setAutoDefault(false);
	wid->setCheckable(TRUE);

	CWIDGET_new(wid, (void *)_object);

END_METHOD


BEGIN_METHOD(CTOOLBUTTON_new, GB_OBJECT parent)

	MyToolButton *wid = new MyToolButton(QCONTAINER(VARG(parent)));

	QObject::connect(wid, SIGNAL(clicked()), &CButton::manager, SLOT(clickedTool()));

	//wid->setToggleButton(TRUE);
	wid->setAutoRaise(true);

	CWIDGET_new(wid, (void *)_object);
	wid->calcMinimumSize();

END_METHOD


BEGIN_METHOD_VOID(CBUTTON_free)

	CLEAR_PICTURE(&(OBJECT(CBUTTON)->picture));

END_METHOD

BEGIN_PROPERTY(CBUTTON_text)

	if (READ_PROPERTY)
		RETURN_NEW_STRING(WIDGET->text());
	else
		set_button_text(THIS, QSTRING_PROP());

END_PROPERTY


BEGIN_PROPERTY(CBUTTON_picture)

	if (READ_PROPERTY)
		GB.ReturnObject(THIS->picture);
	else
	{
		GB.StoreObject(PROP(GB_OBJECT), POINTER(&(THIS->picture)));
		set_button_picture(THIS);
	}

END_PROPERTY


BEGIN_PROPERTY(CTOOLBUTTON_text)

	if (READ_PROPERTY)
		RETURN_NEW_STRING(WIDGET->text());
	else
		set_tool_button(THIS, true, QSTRING_PROP());

END_PROPERTY


BEGIN_PROPERTY(CTOOLBUTTON_picture)

	if (READ_PROPERTY)
		GB.ReturnObject(THIS->picture);
	else
	{
		GB.StoreObject(PROP(GB_OBJECT), POINTER(&(THIS->picture)));
		set_tool_button(THIS, false, QString());
	}

END_PROPERTY

/*
BEGIN_PROPERTY(CTOOLBUTTON_picture)

	QToolButton *wid = QTOOLBUTTON(_object);
	char **pict = (char **)&(OBJECT(CBUTTON)->picture);

	if (READ_PROPERTY)
		GB.ReturnString(*pict, 0);
	else
		wid->setIconSet(QIconSet(*PIXMAP_set_widget(PROPERTY(GB_STRING), pict), QIconSet::Small));

END_PROPERTY
*/

BEGIN_PROPERTY(CBUTTON_value)

	if (READ_PROPERTY)
		GB.ReturnBoolean(0);
	else if (VPROP(GB_BOOLEAN))
		WIDGET->animateClick();

END_PROPERTY


BEGIN_PROPERTY(CTOGGLEBUTTON_value)

	if (READ_PROPERTY)
		GB.ReturnBoolean(WIDGET->isChecked());
	else
		WIDGET->setChecked(VPROP(GB_BOOLEAN));

END_PROPERTY


BEGIN_PROPERTY(CTOOLBUTTON_value)

	if (READ_PROPERTY)
		GB.ReturnBoolean(WIDGET_TOOL->isChecked());
	else
	{
		if (WIDGET->isCheckable())
			WIDGET_TOOL->setChecked(VPROP(GB_BOOLEAN));
		else
			WIDGET->animateClick();
		//qApp->postEvent(WIDGET_TOOL, new QEvent(QEvent::Leave));
	}

END_PROPERTY


BEGIN_PROPERTY(CBUTTON_flat)

	if (READ_PROPERTY)
		GB.ReturnBoolean(WIDGET->isFlat());
	else
		WIDGET->setFlat(VPROP(GB_BOOLEAN));

END_PROPERTY


BEGIN_PROPERTY(CBUTTON_border)

	if (READ_PROPERTY)
		GB.ReturnBoolean(!WIDGET->isFlat());
	else
		WIDGET->setFlat(!VPROP(GB_BOOLEAN));

END_PROPERTY


BEGIN_PROPERTY(CTOOLBUTTON_border)

	if (READ_PROPERTY)
		GB.ReturnBoolean(!WIDGET_TOOL->autoRaise());
	else
		WIDGET_TOOL->setAutoRaise(!VPROP(GB_BOOLEAN));

END_PROPERTY


BEGIN_PROPERTY(CTOOLBUTTON_toggle)

	if (READ_PROPERTY)
		GB.ReturnBoolean(WIDGET_TOOL->isCheckable());
	else
	{
		WIDGET_TOOL->setCheckable(VPROP(GB_BOOLEAN));
		QObject::disconnect(WIDGET_TOOL, 0, &CButton::manager, 0);
		if (VPROP(GB_BOOLEAN))
			QObject::connect(WIDGET_TOOL, SIGNAL(toggled(bool)), &CButton::manager, SLOT(clickedTool()));
		else
			QObject::connect(WIDGET_TOOL, SIGNAL(clicked()), &CButton::manager, SLOT(clickedTool()));
	}

END_PROPERTY


BEGIN_PROPERTY(CBUTTON_default)

	CWINDOW *top = CWidget::getWindow((CWIDGET *)THIS);

	if (READ_PROPERTY)
		GB.ReturnBoolean(top->defaultButton == WIDGET);
	else
		CWINDOW_set_default_button(top, WIDGET, VPROP(GB_BOOLEAN));

END_PROPERTY


BEGIN_PROPERTY(CBUTTON_cancel)

	CWINDOW *top = CWidget::getWindow((CWIDGET *)THIS);

	if (READ_PROPERTY)
		GB.ReturnBoolean(top->cancelButton == WIDGET);
	else
		CWINDOW_set_cancel_button(top, WIDGET, VPROP(GB_BOOLEAN));

END_PROPERTY

BEGIN_PROPERTY(CBUTTON_radio)

	if (READ_PROPERTY)
		GB.ReturnBoolean(THIS->radio);
	else
		THIS->radio = VPROP(GB_BOOLEAN);

END_PROPERTY

BEGIN_PROPERTY(CBUTTON_autoresize)

	if (READ_PROPERTY)
		GB.ReturnBoolean(THIS->autoresize);
	else if (THIS->autoresize != VPROP(GB_BOOLEAN))
	{
		THIS->autoresize = VPROP(GB_BOOLEAN);
		WIDGET->calcMinimumSize();
	}

END_PROPERTY

BEGIN_PROPERTY(CTOOLBUTTON_autoresize)

	if (READ_PROPERTY)
		GB.ReturnBoolean(THIS->autoresize);
	else if (THIS->autoresize != VPROP(GB_BOOLEAN))
	{
		THIS->autoresize = VPROP(GB_BOOLEAN);
		WIDGET_TOOL->calcMinimumSize();
	}

END_PROPERTY

#if 0
BEGIN_PROPERTY(CBUTTON_stretch)

	if (READ_PROPERTY)
		GB.ReturnBoolean(THIS->stretch);
	else if (THIS->stretch != VPROP(GB_BOOLEAN))
	{
		THIS->stretch = VPROP(GB_BOOLEAN);
		set_button(THIS, NULL, true);
	}

END_PROPERTY

BEGIN_PROPERTY(CTOOLBUTTON_stretch)

	if (READ_PROPERTY)
		GB.ReturnBoolean(THIS->stretch);
	else if (THIS->stretch != VPROP(GB_BOOLEAN))
	{
		THIS->stretch = VPROP(GB_BOOLEAN);
		set_tool_button(THIS, NULL, true);
	}

END_PROPERTY
#endif

#define CTOGGLEBUTTON_free CBUTTON_free
#define CTOGGLEBUTTON_text CBUTTON_text
#define CTOGGLEBUTTON_picture CBUTTON_picture
#define CTOGGLEBUTTON_border CBUTTON_border
#define CTOGGLEBUTTON_radio CBUTTON_radio
#define CTOGGLEBUTTON_stretch CBUTTON_stretch

#define CTOOLBUTTON_free CBUTTON_free
#define CTOOLBUTTON_radio CBUTTON_radio

GB_DESC CButtonDesc[] =
{
	GB_DECLARE("Button", sizeof(CBUTTON)), GB_INHERITS("Control"),

	GB_METHOD("_new", NULL, CBUTTON_new, "(Parent)Container;"),
	GB_METHOD("_free", NULL, CBUTTON_free, NULL),

	GB_PROPERTY("Text", "s", CBUTTON_text),
	GB_PROPERTY("Caption", "s", CBUTTON_text),
	GB_PROPERTY("Picture", "Picture", CBUTTON_picture),

	GB_PROPERTY("Border", "b", CBUTTON_border),
	GB_PROPERTY("Default", "b", CBUTTON_default),
	GB_PROPERTY("Cancel", "b", CBUTTON_cancel),
	GB_PROPERTY("Value", "b", CBUTTON_value),
	GB_PROPERTY("AutoResize", "b", CBUTTON_autoresize),

	BUTTON_DESCRIPTION,

	GB_EVENT("Click", NULL, NULL, &EVENT_Click),

	GB_END_DECLARE
};

GB_DESC CToggleButtonDesc[] =
{
	GB_DECLARE("ToggleButton", sizeof(CBUTTON)), GB_INHERITS("Control"),

	GB_METHOD("_new", NULL, CTOGGLEBUTTON_new, "(Parent)Container;"),
	GB_METHOD("_free", NULL, CTOGGLEBUTTON_free, NULL),

	GB_PROPERTY("Text", "s", CTOGGLEBUTTON_text),
	GB_PROPERTY("Caption", "s", CTOGGLEBUTTON_text),
	GB_PROPERTY("Picture", "Picture", CTOGGLEBUTTON_picture),
	GB_PROPERTY("Value", "b", CTOGGLEBUTTON_value),
	//GB_PROPERTY("Flat", "b", CBUTTON_flat),
	GB_PROPERTY("Border", "b", CTOGGLEBUTTON_border),
	GB_PROPERTY("Radio", "b", CTOGGLEBUTTON_radio),
	GB_PROPERTY("AutoResize", "b", CBUTTON_autoresize),

	TOGGLEBUTTON_DESCRIPTION,

	GB_EVENT("Click", NULL, NULL, &EVENT_ClickToggle),

	GB_END_DECLARE
};


GB_DESC CToolButtonDesc[] =
{
	GB_DECLARE("ToolButton", sizeof(CBUTTON)), GB_INHERITS("Control"),

	GB_METHOD("_new", NULL, CTOOLBUTTON_new, "(Parent)Container;"),
	GB_METHOD("_free", NULL, CTOOLBUTTON_free, NULL),

	GB_PROPERTY("Text", "s", CTOOLBUTTON_text),
	GB_PROPERTY("Caption", "s", CTOOLBUTTON_text),
	GB_PROPERTY("Picture", "Picture", CTOOLBUTTON_picture),
	GB_PROPERTY("Value", "b", CTOOLBUTTON_value),
	GB_PROPERTY("Toggle", "b", CTOOLBUTTON_toggle),
	GB_PROPERTY("Border", "b", CTOOLBUTTON_border),
	GB_PROPERTY("Radio", "b", CTOOLBUTTON_radio),
	GB_PROPERTY("AutoResize", "b", CTOOLBUTTON_autoresize),

	TOOLBUTTON_DESCRIPTION,

	GB_EVENT("Click", NULL, NULL, &EVENT_ClickTool),

	GB_END_DECLARE
};



/** class MyPushButton *****************************************************/

MyPushButton::MyPushButton(QWidget *parent) :
	QPushButton(parent)
{
	calcMinimumSize();
	top = 0;
}

MyPushButton::~MyPushButton()
{
	if (top)
	{
		CWINDOW_set_default_button(top, this, false);
		CWINDOW_set_cancel_button(top, this, false);
	}
}

/*QSize MyPushButton::sizeHint(void) const
{
	return QSize(width(), height());
}*/

void MyPushButton::changeEvent(QEvent *e)
{
	QPushButton::changeEvent(e);
	if (e->type() == QEvent::FontChange || e->type() == QEvent::StyleChange)
		calcMinimumSize();
}

void MyPushButton::calcMinimumSize()
{
	CBUTTON *_object = (CBUTTON *)CWidget::getReal(this);
	QSize size;

	if (!THIS || CWIDGET_test_flag(THIS, WF_DESIGN_LEADER))
		return;

	if (text().length() > 0)
	{
		QFontMetrics fm = fontMetrics();
		setMinimumHeight(fm.lineSpacing() + 4);
	}
	else
		setMinimumHeight(0);

	setMinimumWidth(0);
	if (THIS->autoresize)
	{
		size = sizeHint();
		CWIDGET_resize(THIS, size.width(), height());
		setMinimumWidth(size.width());
	}

	//qDebug("%p: %s: %d", this, text().latin1(), minimumHeight());
}

/*void MyPushButton::resizeEvent(QResizeEvent *e)
{
	set_button((CBUTTON *)CWidget::get(this), NULL, true);
}*/

/*void MyPushButton::paintEvent(QPaintEvent *)
{
	CBUTTON *_object = (CBUTTON *)CWidget::get(this);
	QStylePainter p(this);
	QStyleOptionToolButton opt;
	initStyleOption(&opt);
	if (THIS->picture)
		opt.iconSize = THIS->picture->pixmap->size();
	p.drawComplexControl(QStyle::CC_PushButton, opt);
}*/


/** class MyToolButton *****************************************************/

MyToolButton::MyToolButton(QWidget *parent) :
	QToolButton(parent)
{
}

MyToolButton::~MyToolButton()
{
}

void MyToolButton::changeEvent(QEvent *e)
{
	QToolButton::changeEvent(e);
	if (e->type() == QEvent::FontChange || e->type() == QEvent::StyleChange)
		calcMinimumSize();
}

void MyToolButton::calcMinimumSize()
{
	CBUTTON *_object = (CBUTTON *)CWidget::get(this);
	QSize size;

	if (!THIS || CWIDGET_test_flag(THIS, WF_DESIGN))
		return;

	if (text().length() > 0)
	{
		QFontMetrics fm = fontMetrics();
		setMinimumHeight(fm.lineSpacing() + 4);
	}
	else
		setMinimumHeight(0);

	setMinimumWidth(0);
	if (THIS->autoresize)
	{
		size = sizeHint();
		CWIDGET_resize(THIS, size.width(), height());
		setMinimumWidth(size.width());
	}
}

/*void MyToolButton::resizeEvent(QResizeEvent *e)
{
	//set_tool_button((CBUTTON *)CWidget::get(this), NULL, true);
}*/

/*void MyToolButton::paintEvent(QPaintEvent *)
{
	CBUTTON *_object = (CBUTTON *)CWidget::get(this);
	QStylePainter p(this);
	QStyleOptionToolButton opt;
	initStyleOption(&opt);
	if (THIS->picture)
		opt.iconSize = THIS->picture->pixmap->size();
	p.drawComplexControl(QStyle::CC_ToolButton, opt);
}*/


/* Class CButton */

CButton CButton::manager;

void CButton::onlyMe(CBUTTON *_object)
{
	QWidget *parent = WIDGET->parentWidget();
	QObjectList list = parent->children();
	int i;
	QObject *o;
	CBUTTON *other;

	for (i = 0; i < list.count(); i++)
	{
		o = list.at(i);
		if (!o->isWidgetType())
			continue;
		other = (CBUTTON *)CWidget::get(o);
		if (other == THIS)
			continue;
		if (other->widget.ob.klass != THIS->widget.ob.klass)
			continue;
		if (!other->radio)
			continue;
		o->blockSignals(true);
		/*if (qobject_cast<MyPushButton *>(o))
			((MyPushButton *)o)->setChecked(false);
		else
			((MyToolButton *)o)->setChecked(false);*/
		(qobject_cast<QAbstractButton *>(o))->setChecked(false);
		o->blockSignals(false);
	}
}

void CButton::clicked(void)
{
	RAISE_EVENT_ACTION(EVENT_Click);
}

void CButton::clickedToggle(void)
{
	GET_SENDER();

	if (THIS->radio)
	{
		if (WIDGET->isChecked())
			onlyMe(THIS);
		else
		{
			WIDGET->setChecked(true);
			return;
		}
	}

	RAISE_EVENT_ACTION(EVENT_ClickToggle);
}

void CButton::clickedTool(void)
{
	GET_SENDER();

	if (THIS->radio)
	{
		if (WIDGET_TOOL->isChecked())
			onlyMe(THIS);
		else
		{
			WIDGET_TOOL->setChecked(true);
			return;
		}
	}

	RAISE_EVENT_ACTION(EVENT_ClickTool);
}
