Blob Blame Raw


#include "toonzqt/styleeditor.h"

// TnzQt includes
#include "toonzqt/gutil.h"
#include "toonzqt/filefield.h"
#include "historytypes.h"

// TnzLib includes
#include "toonz/txshlevel.h"
#include "toonz/stylemanager.h"
#include "toonz/txshlevelhandle.h"
#include "toonz/toonzfolders.h"
#include "toonz/cleanupcolorstyles.h"
#include "toonz/palettecontroller.h"
#include "toonz/imagestyles.h"
#include "toonz/txshsimplelevel.h" //iwsw
#include "toonz/levelproperties.h" //iwsw

// TnzCore includes
#include "tconvert.h"
#include "tfiletype.h"
#include "tsystem.h"
#include "tundo.h"
#include "tcolorstyles.h"
#include "tpalette.h"
#include "tpixel.h"
#include "tvectorimage.h"
#include "trasterimage.h"
#include "tlevel_io.h"
#include "tofflinegl.h"
#include "tropcm.h"
#include "tvectorrenderdata.h"
#include "tsimplecolorstyles.h"
#include "tvectorbrushstyle.h"

// Qt includes
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QPainter>
#include <QButtonGroup>
#include <QMouseEvent>
#include <QLabel>
#include <QCheckBox>
#include <QPushButton>
#include <QRadioButton>
#include <QComboBox>
#include <QScrollArea>
#include <QStackedWidget>
#include <QStyleOptionSlider>
#include <QToolTip>
#include <QSplitter>

using namespace StyleEditorGUI;

//*****************************************************************************
//    UndoPaletteChange  definition
//*****************************************************************************

namespace
{

class UndoPaletteChange : public TUndo
{
	TPaletteHandle *m_paletteHandle;
	TPaletteP m_palette;

	int m_styleId;
	const TColorStyleP m_oldColor, m_newColor;

	std::wstring m_oldName, m_newName;

	bool m_oldEditedFlag, m_newEditedFlag;

	int m_frame;

public:
	UndoPaletteChange(TPaletteHandle *paletteHandle, int styleId,
					  const TColorStyle &oldColor, const TColorStyle &newColor)
		: m_paletteHandle(paletteHandle), m_palette(paletteHandle->getPalette()), m_styleId(styleId), m_oldColor(oldColor.clone()), m_newColor(newColor.clone()), m_oldName(oldColor.getName()), m_newName(newColor.getName()), m_frame(m_palette->getFrame()), m_oldEditedFlag(oldColor.getIsEditedFlag()), m_newEditedFlag(newColor.getIsEditedFlag()) {}

	void undo() const
	{
		m_palette->setStyle(m_styleId, m_oldColor->clone());
		m_palette->getStyle(m_styleId)->setIsEditedFlag(m_oldEditedFlag);
		m_palette->getStyle(m_styleId)->setName(m_oldName);

		if (m_palette->isKeyframe(m_styleId, m_frame))
			m_palette->setKeyframe(m_styleId, m_frame);

		//don't change the dirty flag. because m_palette may not the current palette when undo executed
		m_paletteHandle->notifyColorStyleChanged(false, false);
	}

	void redo() const
	{
		m_palette->setStyle(m_styleId, m_newColor->clone());
		m_palette->getStyle(m_styleId)->setIsEditedFlag(m_newEditedFlag);
		m_palette->getStyle(m_styleId)->setName(m_newName);

		if (m_palette->isKeyframe(m_styleId, m_frame))
			m_palette->setKeyframe(m_styleId, m_frame);

		//don't change the dirty flag. because m_palette may not the current palette when undo executed
		m_paletteHandle->notifyColorStyleChanged(false, false);
	}

	// imprecise - depends on the style
	int getSize() const { return sizeof(*this) + 2 * sizeof(TColorStyle *); }

	QString getHistoryString()
	{
		return QObject::tr("Change Style   Palette : %1  Style#%2  [R%3 G%4 B%5] -> [R%6 G%7 B%8]")
			.arg(QString::fromStdWString(m_palette->getPaletteName()))
			.arg(QString::number(m_styleId))
			.arg(m_oldColor->getMainColor().r)
			.arg(m_oldColor->getMainColor().g)
			.arg(m_oldColor->getMainColor().b)
			.arg(m_newColor->getMainColor().r)
			.arg(m_newColor->getMainColor().g)
			.arg(m_newColor->getMainColor().b);
	}

	int getHistoryType()
	{
		return HistoryType::Palette;
	}
};

} // namespace

//*****************************************************************************
//    ColorModel  implementation
//*****************************************************************************

const int ChannelMaxValues[] = {255, 255, 255, 255, 359, 100, 100};
const int ChannelPairMaxValues[][2] =
	{{255, 255}, {255, 255}, {255, 255}, {255, 255}, {100, 100}, {359, 100}, {359, 100}};

ColorModel::ColorModel()
{
	memset(m_channels, 0, sizeof m_channels);
}

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

void ColorModel::rgb2hsv()
{
	QColor converter(m_channels[0], m_channels[1], m_channels[2]);
	m_channels[4] = tmax(converter.hue(), 0); // hue() ritorna -1 per colori acromatici
	m_channels[5] = converter.saturation() * 100 / 255;
	m_channels[6] = converter.value() * 100 / 255;
}

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

void ColorModel::hsv2rgb()
{
	QColor converter = QColor::fromHsv(
		m_channels[4],
		m_channels[5] * 255 / 100,
		m_channels[6] * 255 / 100);

	m_channels[0] = converter.red();
	m_channels[1] = converter.green();
	m_channels[2] = converter.blue();
}

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

void ColorModel::setTPixel(const TPixel32 &pix)
{
	QColor color(pix.r, pix.g, pix.b, pix.m);
	m_channels[0] = color.red();
	m_channels[1] = color.green();
	m_channels[2] = color.blue();
	m_channels[3] = color.alpha();
	m_channels[4] = tmax(color.hue(), 0); // hue() ritorna -1 per colori acromatici
	m_channels[5] = color.saturation() * 100 / 255;
	m_channels[6] = color.value() * 100 / 255;
}

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

TPixel32 ColorModel::getTPixel() const
{
	return TPixel32(m_channels[0], m_channels[1], m_channels[2], m_channels[3]);
}

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

void ColorModel::setValue(ColorChannel channel, int value)
{
	assert(0 <= (int)channel && (int)channel < 7);
	assert(0 <= value && value <= ChannelMaxValues[channel]);
	m_channels[(int)channel] = value;
	if (channel >= eHue)
		hsv2rgb();
	else if (channel <= eBlue)
		rgb2hsv();
}

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

void ColorModel::setValues(ColorChannel channel, int v, int u)
{
	assert(0 <= (int)channel && (int)channel < 7);
	switch (channel) {
	case eRed:
		setValue(eGreen, v);
		setValue(eBlue, u);
		break;
	case eGreen:
		setValue(eRed, v);
		setValue(eBlue, u);
		break;
	case eBlue:
		setValue(eRed, v);
		setValue(eGreen, u);
		break;
	case eHue:
		setValue(eSaturation, v);
		setValue(eValue, u);
		break;
	case eSaturation:
		setValue(eHue, v);
		setValue(eValue, u);
		break;
	case eValue:
		setValue(eHue, v);
		setValue(eSaturation, u);
		break;
	}
}

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

int ColorModel::getValue(ColorChannel channel) const
{
	assert(0 <= (int)channel && (int)channel < 7);
	return m_channels[(int)channel];
}

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

void ColorModel::getValues(ColorChannel channel, int &u, int &v)
{
	switch (channel) {
	case eRed:
		u = getValue(eGreen);
		v = getValue(eBlue);
		break;
	case eGreen:
		u = getValue(eRed);
		v = getValue(eBlue);
		break;
	case eBlue:
		u = getValue(eRed);
		v = getValue(eGreen);
		break;
	case eHue:
		u = getValue(eSaturation);
		v = getValue(eValue);
		break;
	case eSaturation:
		u = getValue(eHue);
		v = getValue(eValue);
		break;
	case eValue:
		u = getValue(eHue);
		v = getValue(eSaturation);
		break;
	}
}

//-----------------------------------------------------------------------------
namespace
{
//-----------------------------------------------------------------------------

class RedShadeMaker
{
	const ColorModel &m_color;

public:
	RedShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int value) const
	{
		return QColor(value, m_color.g(), m_color.b()).rgba();
	}
};

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

class GreenShadeMaker
{
	const ColorModel &m_color;

public:
	GreenShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int value) const
	{
		return QColor(m_color.r(), value, m_color.b()).rgba();
	}
};

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

class BlueShadeMaker
{
	const ColorModel &m_color;

public:
	BlueShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int value) const
	{
		return QColor(m_color.r(), m_color.g(), value).rgba();
	}
};

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

class AlphaShadeMaker
{
	const ColorModel &m_color;

public:
	AlphaShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int value) const
	{
		return QColor(m_color.r(), m_color.g(), m_color.b(), value).rgba();
	}
};

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

class HueShadeMaker
{
	const ColorModel &m_color;

public:
	HueShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int value) const
	{
		return QColor::fromHsv(359 * value / 255, m_color.s() * 255 / 100, m_color.v() * 255 / 100).rgba();
	}
};

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

class SaturationShadeMaker
{
	const ColorModel &m_color;

public:
	SaturationShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int value) const
	{
		return QColor::fromHsv(m_color.h(), value, m_color.v() * 255 / 100).rgba();
	}
};

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

class ValueShadeMaker
{
	const ColorModel &m_color;

public:
	ValueShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int value) const
	{
		return QColor::fromHsv(m_color.h(), m_color.s() * 255 / 100, value).rgba();
	}
};

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

class RedGreenShadeMaker
{
	const ColorModel &m_color;

public:
	RedGreenShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int u, int v) const
	{
		return QColor(u, v, m_color.b()).rgba();
	}
};

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

class RedBlueShadeMaker
{
	const ColorModel &m_color;

public:
	RedBlueShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int u, int v) const
	{
		return QColor(u, m_color.g(), v).rgba();
	}
};

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

class GreenBlueShadeMaker
{
	const ColorModel &m_color;

public:
	GreenBlueShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int u, int v) const
	{
		return QColor(m_color.r(), u, v).rgba();
	}
};

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

class SaturationValueShadeMaker
{
	const ColorModel &m_color;

public:
	SaturationValueShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int u, int v) const
	{
		return QColor::fromHsv(m_color.h(), u, v).rgba();
	}
};

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

class HueValueShadeMaker
{
	const ColorModel &m_color;

public:
	HueValueShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int u, int v) const
	{
		return QColor::fromHsv(359 * u / 255, m_color.s() * 255 / 100, v).rgba();
	}
};

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

class HueSaturationShadeMaker
{
	const ColorModel &m_color;

public:
	HueSaturationShadeMaker(const ColorModel &color) : m_color(color) {}
	inline QRgb shade(int u, int v) const
	{
		return QColor::fromHsv(359 * u / 255, v, m_color.v() * 255 / 100).rgba();
	}
};

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

template <class ShadeMaker>
QPixmap makeLinearShading(
	const ShadeMaker &shadeMaker,
	int size,
	bool isVertical)
{
	assert(size > 0);
	QPixmap bgPixmap;
	int i, dx, dy, w = 1, h = 1;
	int x = 0, y = 0;
	if (isVertical) {
		dx = 0;
		dy = -1;
		h = size;
		y = size - 1;
	} else {
		dx = 1;
		dy = 0;
		w = size;
	}
	QImage image(w, h, QImage::Format_ARGB32);
	for (i = 0; i < size; i++) {
		int v = 255 * i / (size - 1);
		image.setPixel(x, y, shadeMaker.shade(v));
		x += dx;
		y += dy;
	}
	return QPixmap::fromImage(image);
}

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

QPixmap makeLinearShading(
	const ColorModel &color,
	ColorChannel channel,
	int size,
	bool isVertical)
{
	switch (channel) {
	case eRed:
		if (isVertical)
			return makeLinearShading(RedShadeMaker(color), size, isVertical);
		else
			return QPixmap(":Resources/grad_r.png").scaled(size, 1);
	case eGreen:
		if (isVertical)
			return makeLinearShading(GreenShadeMaker(color), size, isVertical);
		else
			return QPixmap(":Resources/grad_g.png").scaled(size, 1);
	case eBlue:
		if (isVertical)
			return makeLinearShading(BlueShadeMaker(color), size, isVertical);
		else
			return QPixmap(":Resources/grad_b.png").scaled(size, 1);
	case eAlpha:
		if (isVertical)
			return makeLinearShading(AlphaShadeMaker(color), size, isVertical);
		else
			return QPixmap(":Resources/grad_m.png").scaled(size, 1);
	case eHue:
		return makeLinearShading(HueShadeMaker(color), size, isVertical);
	case eSaturation:
		return makeLinearShading(SaturationShadeMaker(color), size, isVertical);
	case eValue:
		return makeLinearShading(ValueShadeMaker(color), size, isVertical);
	default:
		assert(0);
	}
	return QPixmap();
}

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

template <class ShadeMaker>
QPixmap makeSquareShading(const ShadeMaker &shadeMaker, int size)
{
	assert(size > 0);
	QPixmap bgPixmap;
	QImage image(size, size, QImage::Format_RGB32);
	int i, j;
	for (j = 0; j < size; j++) {
		int u = 255 - (255 * j / (size - 1));
		for (i = 0; i < size; i++) {
			int v = 255 * i / (size - 1);
			image.setPixel(i, j, shadeMaker.shade(v, u));
		}
	}
	return QPixmap::fromImage(image);
}

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

QPixmap makeSquareShading(
	const ColorModel &color,
	ColorChannel channel,
	int size)
{
	switch (channel) {
	case eRed:
		return makeSquareShading(GreenBlueShadeMaker(color), size);
	case eGreen:
		return makeSquareShading(RedBlueShadeMaker(color), size);
	case eBlue:
		return makeSquareShading(RedGreenShadeMaker(color), size);
	case eHue:
		return makeSquareShading(SaturationValueShadeMaker(color), size);
	case eSaturation:
		return makeSquareShading(HueValueShadeMaker(color), size);
	case eValue:
		return makeSquareShading(HueSaturationShadeMaker(color), size);
	default:
		assert(0);
	}
	return QPixmap();
}

//-----------------------------------------------------------------------------
} // namespace
//-----------------------------------------------------------------------------

//*****************************************************************************
//    HexagonalColorWheel  implementation
//*****************************************************************************

HexagonalColorWheel::HexagonalColorWheel(QWidget *parent)
	: QGLWidget(parent), m_bgColor(128, 128, 128) //defaul value in case this value does not set in the style sheet
												  //, m_ghibli3DLutUtil(0)//iwsw commented out temporarily
{
	setObjectName("HexagonalColorWheel");
	setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	setFocusPolicy(Qt::NoFocus);
	m_currentWheel = none;

	//iwsw commented out temporarily
	/*
	if(Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && Ghibli3DLutUtil::m_isValid)
	{
	m_ghibli3DLutUtil = new Ghibli3DLutUtil();
	m_ghibli3DLutUtil->setInvert();
	}
	*/
}

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

HexagonalColorWheel::~HexagonalColorWheel()
{
	//iwsw commented out temporarily
	/*
	if(m_ghibli3DLutUtil)
	{
	m_ghibli3DLutUtil->onEnd();
	delete m_ghibli3DLutUtil;
	}
	*/
}

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

void HexagonalColorWheel::initializeGL()
{
	qglClearColor(getBGColor());

	//iwsw commented out temporarily
	/*
	if(Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && m_ghibli3DLutUtil)
	m_ghibli3DLutUtil->onInit();
	*/
}

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

void HexagonalColorWheel::resizeGL(int width, int height)
{
	float d = (width - 5.0f) / 2.5f;
	bool isHorizontallyLong = ((d * 1.732f) < height) ? false : true;

	if (isHorizontallyLong) {
		m_triEdgeLen = (float)height / 1.732f;
		m_triHeight = (float)height / 2.0f;
		m_wheelPosition.setX(((float)width - (m_triEdgeLen * 2.5f + 5.0f)) / 2.0f);
		m_wheelPosition.setY(0.0f);
	} else {
		m_triEdgeLen = d;
		m_triHeight = m_triEdgeLen * 0.866f;
		m_wheelPosition.setX(0.0f);
		m_wheelPosition.setY(((float)height - (m_triHeight * 2.0f)) / 2.0f);
	}

	//set all vertices positions
	m_wp[0].setX(m_triEdgeLen);
	m_wp[0].setY(m_triHeight);
	m_wp[1].setX(m_triEdgeLen * 0.5f);
	m_wp[1].setY(0.0f);
	m_wp[2].setX(0.0f);
	m_wp[2].setY(m_triHeight);
	m_wp[3].setX(m_triEdgeLen * 0.5f);
	m_wp[3].setY(m_triHeight * 2.0f);
	m_wp[4].setX(m_triEdgeLen * 1.5f);
	m_wp[4].setY(m_triHeight * 2.0f);
	m_wp[5].setX(m_triEdgeLen * 2.0f);
	m_wp[5].setY(m_triHeight);
	m_wp[6].setX(m_triEdgeLen * 1.5f);
	m_wp[6].setY(0.0f);

	m_leftp[0].setX(m_wp[6].x() + 5.0f);
	m_leftp[0].setY(0.0f);
	m_leftp[1].setX(m_leftp[0].x() + m_triEdgeLen);
	m_leftp[1].setY(m_triHeight * 2.0f);
	m_leftp[2].setX(m_leftp[1].x());
	m_leftp[2].setY(0.0f);

	//GL settings
	glViewport(0, 0, width, height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0.0, (GLdouble)width, (GLdouble)height, 0.0, 1.0, -1.0);

	//iwsw commented out temporarily
	/*
	if(Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && m_ghibli3DLutUtil)
	m_ghibli3DLutUtil->onResize(width,height);
	*/
}

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

void HexagonalColorWheel::paintGL()
{
	//call ClearColor() here in order to update bg color when the stylesheet is switched
	qglClearColor(getBGColor());

	glMatrixMode(GL_MODELVIEW);

	//iwsw commented out temporarily
	/*
	if(Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && m_ghibli3DLutUtil)
	m_ghibli3DLutUtil->startDraw();
	*/

	glClear(GL_COLOR_BUFFER_BIT);

	float v = (float)m_color.getValue(eValue) / 100.0f;

	glPushMatrix();

	//draw hexagonal color wheel
	glTranslatef(m_wheelPosition.rx(), m_wheelPosition.ry(), 0.0f);
	glBegin(GL_TRIANGLE_FAN);
	glColor3f(v, v, v);
	glVertex2f(m_wp[0].x(), m_wp[0].y());

	glColor3f(0.0f, v, 0.0f);
	glVertex2f(m_wp[1].x(), m_wp[1].y());
	glColor3f(0.0f, v, v);
	glVertex2f(m_wp[2].x(), m_wp[2].y());
	glColor3f(0.0f, 0.0f, v);
	glVertex2f(m_wp[3].x(), m_wp[3].y());
	glColor3f(v, 0.0f, v);
	glVertex2f(m_wp[4].x(), m_wp[4].y());
	glColor3f(v, 0.0f, 0.0f);
	glVertex2f(m_wp[5].x(), m_wp[5].y());
	glColor3f(v, v, 0.0f);
	glVertex2f(m_wp[6].x(), m_wp[6].y());
	glColor3f(0.0f, v, 0.0f);
	glVertex2f(m_wp[1].x(), m_wp[1].y());
	glEnd();

	QColor leftCol = QColor().fromHsv(m_color.getValue(eHue), 255, 255);

	//draw triangle color picker
	glBegin(GL_TRIANGLES);
	glColor3f(leftCol.redF(), leftCol.greenF(), leftCol.blueF());
	glVertex2f(m_leftp[0].x(), m_leftp[0].y());
	glColor3f(0.0f, 0.0f, 0.0f);
	glVertex2f(m_leftp[1].x(), m_leftp[1].y());
	glColor3f(1.0f, 1.0f, 1.0f);
	glVertex2f(m_leftp[2].x(), m_leftp[2].y());
	glEnd();

	//draw small quad at current color position
	drawCurrentColorMark();

	glPopMatrix();

	//iwsw commented out temporarily
	/*
	if(Preferences::instance()->isDoColorCorrectionByUsing3DLutEnabled() && m_ghibli3DLutUtil)
	m_ghibli3DLutUtil->endDraw();
	*/
}

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

void HexagonalColorWheel::drawCurrentColorMark()
{
	int h;
	float s, v;

	//show hue in a counterclockwise fashion
	h = 360 - m_color.getValue(eHue);

	s = (float)m_color.getValue(eSaturation) / 100.0f;
	v = (float)m_color.getValue(eValue) / 100.0f;

	// d is a distance from a center of the wheel
	float d, phi;
	phi = (float)(h % 60 - 30) / 180.0f * 3.1415f;
	d = s * m_triHeight / cosf(phi);

	//set marker color
	if (v > 0.4f)
		glColor3f(0.0f, 0.0f, 0.0f);
	else
		glColor3f(1.0f, 1.0f, 1.0f);

	//draw marker (in the wheel)
	glPushMatrix();
	glTranslatef(m_wp[0].x(), m_wp[0].y(), 0.1f);
	glRotatef(h, 0.0, 0.0, 1.0);
	glTranslatef(d, 0.0f, 0.0f);
	glRotatef(-h, 0.0, 0.0, 1.0);
	glBegin(GL_LINE_LOOP);
	glVertex2f(-3, -3);
	glVertex2f(3, -3);
	glVertex2f(3, 3);
	glVertex2f(-3, 3);
	glEnd();
	glPopMatrix();

	//draw marker (in the triangle)
	glPushMatrix();
	glTranslatef(m_leftp[1].x(), m_leftp[1].y(), 0.1f);
	glTranslatef(-m_triEdgeLen * v * s, -m_triHeight * v * 2.0f, 0.0f);
	glBegin(GL_LINE_LOOP);
	glVertex2f(-3, -3);
	glVertex2f(3, -3);
	glVertex2f(3, 3);
	glVertex2f(-3, 3);
	glEnd();
	glPopMatrix();
}

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

void HexagonalColorWheel::mousePressEvent(QMouseEvent *event)
{

	if (~event->buttons() & Qt::LeftButton)
		return;

	// check whether the mouse cursor is in the wheel or in the triangle (or nothing).

	QPolygonF wheelPolygon;
	// in the case of the wheel
	wheelPolygon << m_wp[1] << m_wp[2] << m_wp[3] << m_wp[4] << m_wp[5] << m_wp[6];
	wheelPolygon.translate(m_wheelPosition);
	if (wheelPolygon.toPolygon().containsPoint(event->pos(), Qt::OddEvenFill)) {
		m_currentWheel = leftWheel;
		clickLeftWheel(event->pos());
		return;
	}

	wheelPolygon.clear();
	// in the case of the triangle
	wheelPolygon << m_leftp[0] << m_leftp[1] << m_leftp[2];
	wheelPolygon.translate(m_wheelPosition);
	if (wheelPolygon.toPolygon().containsPoint(event->pos(), Qt::OddEvenFill)) {
		m_currentWheel = rightTriangle;
		clickRightTriangle(event->pos());
		return;
	}

	//... or, in the case of nothing
	m_currentWheel = none;
}

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

void HexagonalColorWheel::mouseMoveEvent(QMouseEvent *event)
{
	// change the behavior according to the current touching wheel
	switch (m_currentWheel) {
	case none:
		break;
	case leftWheel:
		clickLeftWheel(event->pos());
		break;
	case rightTriangle:
		clickRightTriangle(event->pos());
		break;
	}
}

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

void HexagonalColorWheel::mouseReleaseEvent(QMouseEvent *event)
{
	m_currentWheel = none;
	emit colorChanged(m_color, false);
}

//-----------------------------------------------------------------------------
/*! compute hue and saturation position. saturation value must be clamped
*/
void HexagonalColorWheel::clickLeftWheel(const QPoint &pos)
{
	QLineF p(m_wp[0] + m_wheelPosition, QPointF(pos));
	QLineF horizontal(0, 0, 1, 0);
	float theta = (p.dy() < 0) ? p.angle(horizontal) : 360 - p.angle(horizontal);
	float phi = theta;
	while (phi >= 60.0f)
		phi -= 60.0f;
	phi -= 30.0f;
	// d is a length from center to edge of the wheel when saturation = 100
	float d = m_triHeight / cosf(phi / 180.0f * 3.1415f);

	int h = (int)theta;
	if (h > 359)
		h = 359;
	//clamping
	int s = (int)(tmin(p.length() / d, 1.0) * 100.0f);

	m_color.setValues(eValue, h, s);

	emit colorChanged(m_color, true);
}

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

void HexagonalColorWheel::clickRightTriangle(const QPoint &pos)
{
	int s, v;
	QPointF p = m_leftp[1] + m_wheelPosition - QPointF(pos);
	if (p.ry() <= 0.0f) {
		s = 0;
		v = 0;
	} else {
		float v_ratio = tmin((float)(p.ry() / (m_triHeight * 2.0f)), 1.0f);
		float s_f = p.rx() / (m_triEdgeLen * v_ratio);
		v = (int)(v_ratio * 100.0f);
		s = (int)(tmin(tmax(s_f, 0.0f), 1.0f) * 100.0f);
	}
	m_color.setValues(eHue, s, v);
	emit colorChanged(m_color, true);
}

//*****************************************************************************
//    SquaredColorWheel  implementation
//*****************************************************************************

SquaredColorWheel::SquaredColorWheel(QWidget *parent)
	: QWidget(parent), m_channel(eRed), m_color()
{
}

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

void SquaredColorWheel::paintEvent(QPaintEvent *)
{
	QPainter p(this);
	// calcolo lo sfondo
	int size = width();

	QPixmap bgPixmap = makeSquareShading(m_color, m_channel, size);

	if (!bgPixmap.isNull())
		p.drawTiledPixmap(0, 0, size, size, bgPixmap);

	int u = 0, v = 0;
	m_color.getValues(m_channel, u, v);
	int x = u * width() / ChannelPairMaxValues[m_channel][0];
	int y = (ChannelPairMaxValues[m_channel][1] - v) * height() / ChannelPairMaxValues[m_channel][1];

	if (m_color.v() > 127)
		p.setPen(Qt::black);
	else
		p.setPen(Qt::white);
	p.drawRect(x - 1, y - 1, 3, 3);
}

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

void SquaredColorWheel::click(const QPoint &pos)
{
	int u = ChannelPairMaxValues[m_channel][0] * pos.x() / width();
	int v = ChannelPairMaxValues[m_channel][1] * (height() - pos.y()) / height();
	u = tcrop(u, 0, ChannelPairMaxValues[m_channel][0]);
	v = tcrop(v, 0, ChannelPairMaxValues[m_channel][1]);
	m_color.setValues(m_channel, u, v);
	update();
	emit colorChanged(m_color, true);
}

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

void SquaredColorWheel::mousePressEvent(QMouseEvent *event)
{
	if (event->buttons() & Qt::LeftButton)
		click(event->pos());
}

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

void SquaredColorWheel::mouseMoveEvent(QMouseEvent *event)
{
	if (event->buttons() & Qt::LeftButton)
		click(event->pos());
}

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

void SquaredColorWheel::mouseReleaseEvent(QMouseEvent *event)
{
	emit colorChanged(m_color, false);
}

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

void SquaredColorWheel::setColor(const ColorModel &color)
{
	m_color = color;
}

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

void SquaredColorWheel::setChannel(int channel)
{
	assert(0 <= channel && channel < 7);
	m_channel = (ColorChannel)channel;
	update();
}

//*****************************************************************************
//    ColorSlider  implementation
//*****************************************************************************

ColorSlider::ColorSlider(Qt::Orientation orientation, QWidget *parent)
	: QSlider(orientation, parent), m_channel(eRed), m_color()
{
	setFocusPolicy(Qt::NoFocus);

	setOrientation(orientation);
	setMinimum(0);
	setMaximum(ChannelMaxValues[m_channel]);

	setMinimumHeight(7);
	setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);

	// Attenzione: necessario per poter individuare l'oggetto nel file di definizione dello stile
	setObjectName("colorSlider");
}

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

void ColorSlider::setChannel(ColorChannel channel)
{
	if (m_channel == channel)
		return;
	m_channel = channel;
	setMaximum(ChannelMaxValues[m_channel]);
}

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

void ColorSlider::setColor(const ColorModel &color)
{
	m_color = color;
}

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

void ColorSlider::paintEvent(QPaintEvent *event)
{
	QPainter p(this);

	int x = rect().x();
	int y = rect().y();
	int w = width();
	int h = height();

	bool isVertical = orientation() == Qt::Vertical;

	if (!isVertical)
		h -= 5;

	QPixmap bgPixmap =
		makeLinearShading(m_color, m_channel, isVertical ? h : w, isVertical);

	if (m_channel == eAlpha) {
		static QPixmap checkboard(":Resources/backg.png");
		p.drawTiledPixmap(x, y, w, h, checkboard);
	}

	if (!bgPixmap.isNull()) {
		p.drawTiledPixmap(x, y, w, h, bgPixmap);
		p.setPen(Qt::white);
		p.drawLine(x, y + h, x + w, y + h);
	}

	/*!
	   Bug in Qt 4.3: The vertical Slider cannot be styled due to a bug.
	   In this case we draw "manually" the slider handle at correct position
	*/
	if (isVertical) {
		int pos = QStyle::sliderPositionFromValue(minimum(), maximum(), value(), h - 9, true);
		static QPixmap vHandlePixmap(":Resources/v_chandle.png");
		p.drawPixmap(0, pos, vHandlePixmap);
	} else {
		static QPixmap hHandleUpPm(":Resources/h_chandleUp.png");
		static QPixmap hHandleDownPm(":Resources/h_chandleDown.png");
		static QPixmap hHandleCenterPm(":Resources/h_chandleCenter.png");
		int pos = QStyle::sliderPositionFromValue(0, maximum(), value(), width() - hHandleCenterPm.width(), false);
		p.drawPixmap(pos, 0, hHandleUpPm);
		p.drawPixmap(pos, height() - hHandleDownPm.height(), hHandleDownPm);
		p.drawPixmap(pos,
					 hHandleUpPm.height(),
					 hHandleCenterPm.width(),
					 height() - hHandleUpPm.height() - hHandleDownPm.height(),
					 hHandleCenterPm);
	}
};

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

void ColorSlider::mousePressEvent(QMouseEvent *event)
{
	// vogliamo che facendo click sullo slider, lontano dall'handle
	// l'handle salti subito nella posizione giusta invece di far partire
	// l'autorepeat.
	//
	// cfr. qslider.cpp:429: sembra che questo comportamento si possa ottenere
	// anche con SH_Slider_AbsoluteSetButtons. Ma non capisco come si possa fare
	// per definire quest hint
	QStyleOptionSlider opt;
	initStyleOption(&opt);
	const QRect handleRect =
		style()->subControlRect(
			QStyle::CC_Slider, &opt,
			QStyle::SC_SliderHandle, this);
	if (!handleRect.contains(event->pos())) {
		const QPoint handleCenter = handleRect.center();
		const QRect grooveRect = style()->subControlRect(
			QStyle::CC_Slider, &opt,
			QStyle::SC_SliderGroove, this);
		int pos, span;
		bool upsideDown = false;
		if (opt.orientation == Qt::Vertical) {
			upsideDown = true;
			int handleSize = handleRect.height();
			pos = event->pos().y() - handleSize / 2;
			span = grooveRect.height() - handleSize;
		} else {
			int handleSize = QPixmap(":Resources/h_chandleCenter.png").width();
			pos = event->pos().x() - handleSize / 2;
			span = grooveRect.width() - handleSize;
		}
		int value = QStyle::sliderValueFromPosition(minimum(), maximum(), pos, span, upsideDown);
		setValue(value);
	}
	QSlider::mousePressEvent(event);
}

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

void ColorSlider::mouseReleaseEvent(QMouseEvent *event)
{
	emit sliderReleased();
}

//*****************************************************************************
//    ArrowButton  implementation
//*****************************************************************************

ArrowButton::ArrowButton(QWidget *parent, Qt::Orientation orientation, bool isFirstArrow)
	: QToolButton(parent), m_orientaion(orientation), m_isFirstArrow(isFirstArrow), m_timerId(0), m_firstTimerId(0)
{
	setFixedSize(10, 10);
	setObjectName("StyleEditorArrowButton");
	bool isVertical = orientation == Qt::Vertical;
	if (m_isFirstArrow) {
		if (isVertical)
			setIcon(createQIconPNG("arrow_up"));
		else
			setIcon(createQIconPNG("arrow_left"));
	} else {
		if (isVertical)
			setIcon(createQIconPNG("arrow_down"));
		else
			setIcon(createQIconPNG("arrow_right"));
	}
	connect(this, SIGNAL(pressed()), this, SLOT(onPressed()));
	connect(this, SIGNAL(released()), this, SLOT(onRelease()));
}

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

void ArrowButton::timerEvent(QTimerEvent *event)
{
	if (m_firstTimerId != 0) {
		killTimer(m_firstTimerId);
		m_firstTimerId = 0;
		m_timerId = startTimer(10);
	}
	notifyChanged();
}

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

void ArrowButton::notifyChanged()
{
	bool isVertical = m_orientaion == Qt::Vertical;
	if ((m_isFirstArrow && !isVertical) || (!m_isFirstArrow && isVertical))
		emit remove();
	else
		emit add();
}

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

void ArrowButton::onPressed()
{
	notifyChanged();
	assert(m_timerId == 0 && m_firstTimerId == 0);
	m_firstTimerId = startTimer(500);
}

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

void ArrowButton::onRelease()
{
	if (m_firstTimerId != 0) {
		killTimer(m_firstTimerId);
		m_firstTimerId = 0;
	} else if (m_timerId != 0) {
		killTimer(m_timerId);
		m_timerId = 0;
	}
}

//*****************************************************************************
//    ColorSliderBar  implementation
//*****************************************************************************

ColorSliderBar::ColorSliderBar(QWidget *parent, Qt::Orientation orientation)
	: QWidget(parent)
{
	bool isVertical = orientation == Qt::Vertical;

	ArrowButton *first = new ArrowButton(this, orientation, true);
	connect(first, SIGNAL(remove()), this, SLOT(onRemove()));
	connect(first, SIGNAL(add()), this, SLOT(onAdd()));

	m_colorSlider = new ColorSlider(orientation, this);
	if (isVertical)
		m_colorSlider->setMaximumWidth(22);

	ArrowButton *last = new ArrowButton(this, orientation, false);
	connect(last, SIGNAL(add()), this, SLOT(onAdd()));
	connect(last, SIGNAL(remove()), this, SLOT(onRemove()));

	connect(m_colorSlider, SIGNAL(valueChanged(int)), this, SIGNAL(valueChanged(int)));
	connect(m_colorSlider, SIGNAL(sliderReleased()), this, SIGNAL(valueChanged()));

	QBoxLayout *layout;
	if (!isVertical)
		layout = new QHBoxLayout(this);
	else
		layout = new QVBoxLayout(this);

	layout->setSpacing(0);
	layout->setMargin(0);
	layout->addWidget(first, 0, Qt::AlignCenter);
	layout->addWidget(m_colorSlider, 1);
	layout->addWidget(last, 0, Qt::AlignCenter);
	setLayout(layout);
}

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

void ColorSliderBar::onRemove()
{
	int value = m_colorSlider->value();
	if (value <= m_colorSlider->minimum())
		return;
	m_colorSlider->setValue(value - 1);
}

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

void ColorSliderBar::onAdd()
{
	int value = m_colorSlider->value();
	if (value >= m_colorSlider->maximum())
		return;
	m_colorSlider->setValue(value + 1);
}

//*****************************************************************************
//    ChannelLineEdit  implementation
//*****************************************************************************

void ChannelLineEdit::mousePressEvent(QMouseEvent *e)
{
	IntLineEdit::mousePressEvent(e);

	if (!m_isEditing) {
		selectAll();
		m_isEditing = true;
	}
}

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

void ChannelLineEdit::focusOutEvent(QFocusEvent *e)
{
	IntLineEdit::focusOutEvent(e);

	m_isEditing = false;
}

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

void ChannelLineEdit::paintEvent(QPaintEvent *e)
{
	IntLineEdit::paintEvent(e);

	if (m_isEditing) {
		QPainter p(this);
		p.setPen(Qt::yellow);
		p.drawRect(rect().adjusted(0, 0, -1, -1));
	}
}

//*****************************************************************************
//    ColorChannelControl  implementation
//*****************************************************************************

ColorChannelControl::ColorChannelControl(
	ColorChannel channel, QWidget *parent)
	: QWidget(parent), m_channel(channel), m_value(0), m_signalEnabled(true)
{
	setFocusPolicy(Qt::NoFocus);

	static const char *names[] = {"R", "G", "B", "M", "H", "S", "V"};
	assert(0 <= (int)m_channel && (int)m_channel < 7);
	QString text = names[(int)m_channel];
	m_label = new QLabel(text, this);

	int minValue = 0;
	int maxValue = 0;
	if (m_channel < 4) // RGBA
		maxValue = 255;
	else if (m_channel == 4) // H
		maxValue = 359;
	else // SV
		maxValue = 100;

	m_field = new ChannelLineEdit(this, 0, minValue, maxValue);
	m_slider = new ColorSlider(Qt::Horizontal, this);

	//buttons to increment/decrement the values by 1
	QPushButton *addButton = new QPushButton(this);
	QPushButton *subButton = new QPushButton(this);

	m_slider->setValue(0);
	m_slider->setChannel(m_channel);

	m_label->setObjectName("colorSliderLabel");
	m_label->setFixedWidth(11);
	m_label->setMinimumHeight(7);
	m_label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);

	m_field->setObjectName("colorSliderField");
	m_field->setFixedWidth(fontMetrics().width('0') * 6 + 5);
	m_field->setMinimumHeight(7);

	addButton->setObjectName("colorSliderAddButton");
	subButton->setObjectName("colorSliderSubButton");
	addButton->setFixedWidth(18);
	subButton->setFixedWidth(18);
	addButton->setMinimumHeight(7);
	subButton->setMinimumHeight(7);
	addButton->setFlat(true);
	subButton->setFlat(true);
	addButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
	subButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
	addButton->setAutoRepeat(true);
	subButton->setAutoRepeat(true);
	addButton->setAutoRepeatInterval(25);
	subButton->setAutoRepeatInterval(25);
	addButton->setFocusPolicy(Qt::NoFocus);
	subButton->setFocusPolicy(Qt::NoFocus);

	QHBoxLayout *mainLayout = new QHBoxLayout(this);
	mainLayout->setMargin(0);
	mainLayout->setSpacing(1);
	{
		mainLayout->addWidget(m_label, 0);
		mainLayout->addSpacing(2);
		mainLayout->addWidget(m_field, 0);
		mainLayout->addSpacing(2);
		mainLayout->addWidget(subButton, 0);
		mainLayout->addWidget(m_slider, 1);
		mainLayout->addWidget(addButton, 0);
	}
	setLayout(mainLayout);

	bool ret = connect(m_field, SIGNAL(editingFinished()), this, SLOT(onFieldChanged()));
	ret = ret && connect(m_slider, SIGNAL(valueChanged(int)), this, SLOT(onSliderChanged(int)));
	ret = ret && connect(m_slider, SIGNAL(sliderReleased()), this, SLOT(onSliderReleased()));
	ret = ret && connect(addButton, SIGNAL(clicked()), this, SLOT(onAddButtonClicked()));
	ret = ret && connect(subButton, SIGNAL(clicked()), this, SLOT(onSubButtonClicked()));
	assert(ret);
}

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

void ColorChannelControl::onAddButtonClicked()
{
	m_slider->setValue(m_slider->value() + 1);
}

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

void ColorChannelControl::onSubButtonClicked()
{
	m_slider->setValue(m_slider->value() - 1);
}

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

void ColorChannelControl::setColor(const ColorModel &color)
{
	m_color = color;
	m_slider->setColor(color);
	int value = color.getValue(m_channel);
	if (m_value != value) {
		bool signalEnabled = m_signalEnabled;
		m_signalEnabled = false;
		m_value = value;
		m_field->setText(QString::number(value));
		m_slider->setValue(value);
		m_signalEnabled = signalEnabled;
	}
}

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

void ColorChannelControl::onFieldChanged()
{
	int value = m_field->text().toInt();
	if (m_value == value)
		return;
	m_value = value;
	m_slider->setValue(value);
	if (m_signalEnabled) {
		m_color.setValue(m_channel, value);
		emit colorChanged(m_color, false);
	}
}

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

void ColorChannelControl::onSliderChanged(int value)
{
	if (m_value == value)
		return;
	m_value = value;
	m_field->setText(QString::number(value));
	if (m_signalEnabled) {
		m_color.setValue(m_channel, value);
		emit colorChanged(m_color, true);
	}
}

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

void ColorChannelControl::onSliderReleased()
{
	emit colorChanged(m_color, false);
}

//*****************************************************************************
//    StyleEditorPage  implementation
//*****************************************************************************

StyleEditorPage::StyleEditorPage(QWidget *parent)
	: QFrame(parent)
{
	setFocusPolicy(Qt::NoFocus);

	// It is necessary for the style sheets
	setObjectName("styleEditorPage");
	setFrameStyle(QFrame::StyledPanel);
}

//*****************************************************************************
//    ColorParameterSelector  implementation
//*****************************************************************************

ColorParameterSelector::ColorParameterSelector(QWidget *parent)
	: QWidget(parent), m_index(-1), m_chipSize(21, 21), m_chipOrigin(0, 1), m_chipDelta(21, 0)
{
}

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

void ColorParameterSelector::paintEvent(QPaintEvent *event)
{
	if (m_colors.empty())
		return;
	QPainter p(this);
	int i;
	QRect currentChipRect = QRect();
	for (i = 0; i < (int)m_colors.size(); i++) {
		QRect chipRect(m_chipOrigin + i * m_chipDelta, m_chipSize);
		p.fillRect(chipRect, m_colors[i]);
		if (i == m_index)
			currentChipRect = chipRect;
	}
	// Current index border
	if (!currentChipRect.isEmpty()) {
		p.setPen(QColor(199, 202, 50));
		p.drawRect(currentChipRect.adjusted(0, 0, -1, -1));
		p.setPen(Qt::white);
		p.drawRect(currentChipRect.adjusted(1, 1, -2, -2));
		p.setPen(Qt::black);
		p.drawRect(currentChipRect.adjusted(2, 2, -3, -3));
	}
}

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

void ColorParameterSelector::setStyle(const TColorStyle &style)
{
	int count = style.getColorParamCount();
	if (count <= 1) {
		clear();
		return;
	}
	if (m_colors.size() != count) {
		m_index = 0;
		m_colors.resize(count);
	}
	int i;
	for (i = 0; i < count; i++) {
		TPixel32 color = style.getColorParamValue(i);
		m_colors[i] = QColor(color.r, color.g, color.b, color.m);
	}
	update();
}

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

void ColorParameterSelector::clear()
{
	if (m_colors.size() != 0)
		m_colors.clear();
	m_index = -1;
	update();
}

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

void ColorParameterSelector::mousePressEvent(QMouseEvent *event)
{
	QPoint pos = event->pos() - m_chipOrigin;
	int index = pos.x() / m_chipDelta.x();
	QRect chipRect(index * m_chipDelta, m_chipSize);
	if (chipRect.contains(pos)) {
		m_index = index;
		emit colorParamChanged();
		update();
	}
}

//*****************************************************************************
//    PlainColorPage  implementation
//*****************************************************************************

PlainColorPage::PlainColorPage(QWidget *parent)
	: StyleEditorPage(parent), m_color(), m_signalEnabled(true)
{
	setFocusPolicy(Qt::NoFocus);

	//m_squaredColorWheel = new SquaredColorWheel(this);

	//m_verticalSlider = new ColorSliderBar(this, Qt::Vertical);

	m_hexagonalColorWheel = new HexagonalColorWheel(this);

	/*
	QButtonGroup *channelButtonGroup = new QButtonGroup();
	int i;
	for (i = 0; i<7; i++)
	{
		if (i != (int)eAlpha)
		{
			QRadioButton *button = new QRadioButton(this);
			m_modeButtons[i] = button;
			if (i == 0) button->setChecked(true);
			channelButtonGroup->addButton(button, i);
			//slidersLayout->addWidget(button,i,0); 
			//とりあえず隠す
			m_modeButtons[i]->hide();
		}
		else
			m_modeButtons[i] = 0;

		m_channelControls[i] = new ColorChannelControl((ColorChannel)i, this);
		m_channelControls[i]->setColor(m_color);
		bool ret = connect(m_channelControls[i], SIGNAL(colorChanged(const ColorModel &, bool)),
			this, SLOT(onControlChanged(const ColorModel &, bool)));
	}
	*/
	for (int i = 0; i < 7; i++) {
		m_channelControls[i] = new ColorChannelControl((ColorChannel)i, this);
		m_channelControls[i]->setColor(m_color);
		bool ret = connect(m_channelControls[i], SIGNAL(colorChanged(const ColorModel &, bool)),
						   this, SLOT(onControlChanged(const ColorModel &, bool)));
	}

	QPushButton *wheelShowButton = new QPushButton(tr("Wheel"), this);
	QPushButton *hsvShowButton = new QPushButton(tr("HSV"), this);
	QPushButton *matteShowButton = new QPushButton(tr("Matte"), this);
	QPushButton *rgbShowButton = new QPushButton(tr("RGB"), this);

	QFrame *wheelFrame = new QFrame(this);
	QFrame *hsvFrame = new QFrame(this);
	QFrame *matteFrame = new QFrame(this);
	QFrame *rgbFrame = new QFrame(this);

	QFrame *slidersContainer = new QFrame(this);
	QSplitter *vSplitter = new QSplitter(this);

	//プロパティの設定
	//channelButtonGroup->setExclusive(true);
	wheelShowButton->setCheckable(true);
	hsvShowButton->setCheckable(true);
	matteShowButton->setCheckable(true);
	rgbShowButton->setCheckable(true);
	wheelShowButton->setMinimumWidth(30);
	hsvShowButton->setMinimumWidth(30);
	matteShowButton->setMinimumWidth(30);
	rgbShowButton->setMinimumWidth(30);

	wheelFrame->setObjectName("PlainColorPageParts");
	hsvFrame->setObjectName("PlainColorPageParts");
	matteFrame->setObjectName("PlainColorPageParts");
	rgbFrame->setObjectName("PlainColorPageParts");

	wheelShowButton->setChecked(true);
	wheelShowButton->setFocusPolicy(Qt::NoFocus);
	hsvShowButton->setChecked(true);
	hsvShowButton->setFocusPolicy(Qt::NoFocus);
	matteShowButton->setChecked(true);
	matteShowButton->setFocusPolicy(Qt::NoFocus);
	rgbShowButton->setChecked(true);
	rgbShowButton->setFocusPolicy(Qt::NoFocus);

	vSplitter->setOrientation(Qt::Vertical);
	vSplitter->setFocusPolicy(Qt::NoFocus);

	//m_verticalSlider->hide();
	//m_squaredColorWheel->hide();
	//m_ghibliColorWheel->hide();

	//layout
	QVBoxLayout *mainLayout = new QVBoxLayout();
	mainLayout->setSpacing(0);
	mainLayout->setMargin(0);
	{
		QHBoxLayout *showButtonLayout = new QHBoxLayout();
		showButtonLayout->setMargin(0);
		showButtonLayout->setSpacing(0);
		{
			showButtonLayout->addWidget(wheelShowButton, 1);
			showButtonLayout->addWidget(hsvShowButton, 1);
			showButtonLayout->addWidget(matteShowButton, 1);
			showButtonLayout->addWidget(rgbShowButton, 1);
		}
		mainLayout->addLayout(showButtonLayout);

		QHBoxLayout *wheelLayout = new QHBoxLayout();
		wheelLayout->setMargin(5);
		wheelLayout->setSpacing(0);
		{
			wheelLayout->addWidget(m_hexagonalColorWheel);
		}
		wheelFrame->setLayout(wheelLayout);
		vSplitter->addWidget(wheelFrame);

		QVBoxLayout *slidersLayout = new QVBoxLayout();
		slidersLayout->setMargin(0);
		slidersLayout->setSpacing(0);
		{
			QVBoxLayout *hsvLayout = new QVBoxLayout();
			hsvLayout->setMargin(4);
			hsvLayout->setSpacing(4);
			{
				hsvLayout->addWidget(m_channelControls[eHue]);
				hsvLayout->addWidget(m_channelControls[eSaturation]);
				hsvLayout->addWidget(m_channelControls[eValue]);
			}
			hsvFrame->setLayout(hsvLayout);
			slidersLayout->addWidget(hsvFrame, 3);

			QVBoxLayout *matteLayout = new QVBoxLayout();
			matteLayout->setMargin(4);
			matteLayout->setSpacing(4);
			{
				matteLayout->addWidget(m_channelControls[eAlpha]);
			}
			matteFrame->setLayout(matteLayout);
			slidersLayout->addWidget(matteFrame, 1);

			QVBoxLayout *rgbLayout = new QVBoxLayout();
			rgbLayout->setMargin(4);
			rgbLayout->setSpacing(4);
			{
				rgbLayout->addWidget(m_channelControls[eRed]);
				rgbLayout->addWidget(m_channelControls[eGreen]);
				rgbLayout->addWidget(m_channelControls[eBlue]);
			}
			rgbFrame->setLayout(rgbLayout);
			slidersLayout->addWidget(rgbFrame, 3);
		}
		slidersContainer->setLayout(slidersLayout);
		vSplitter->addWidget(slidersContainer);
		mainLayout->addWidget(vSplitter, 1);
	}
	setLayout(mainLayout);

	QList<int> list;
	list << rect().height() / 2 << rect().height() / 2;
	vSplitter->setSizes(list);

	//connect(m_squaredColorWheel, SIGNAL(colorChanged(const ColorModel &, bool)),
	//	this, SLOT(onWheelChanged(const ColorModel &, bool)));
	connect(m_hexagonalColorWheel, SIGNAL(colorChanged(const ColorModel &, bool)),
			this, SLOT(onWheelChanged(const ColorModel &, bool)));
	//m_verticalSlider->setMaximumSize(20,150);
	//connect(m_verticalSlider, SIGNAL(valueChanged(int)), this, SLOT(onWheelSliderChanged(int)));
	//connect(m_verticalSlider, SIGNAL(valueChanged()), this, SLOT(onWheelSliderReleased()));
	//connect( m_verticalSlider,		SIGNAL(sliderReleased()),	this, SLOT(onWheelSliderReleased()));
	//connect(channelButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(setWheelChannel(int)));

	//Show/Hideトグルボタン
	connect(wheelShowButton, SIGNAL(toggled(bool)), wheelFrame, SLOT(setVisible(bool)));
	connect(hsvShowButton, SIGNAL(toggled(bool)), hsvFrame, SLOT(setVisible(bool)));
	connect(matteShowButton, SIGNAL(toggled(bool)), matteFrame, SLOT(setVisible(bool)));
	connect(rgbShowButton, SIGNAL(toggled(bool)), rgbFrame, SLOT(setVisible(bool)));
}

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

void PlainColorPage::resizeEvent(QResizeEvent *)
{
	int w = width();
	int h = height();

	int parentW = parentWidget()->width();
}

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

void PlainColorPage::updateControls()
{

	int i;
	for (i = 0; i < 7; i++) {
		m_channelControls[i]->setColor(m_color);
		m_channelControls[i]->update();
	}
	/*
	m_squaredColorWheel->setColor(m_color);
	m_squaredColorWheel->update();
	*/

	m_hexagonalColorWheel->setColor(m_color);
	m_hexagonalColorWheel->update();

	/*
  bool signalsBlocked = m_verticalSlider->blockSignals(true);
	m_verticalSlider->setColor(m_color);
  int value = m_color.getValue(m_verticalSlider->getChannel());
  m_verticalSlider->setValue(value);
	m_verticalSlider->update();
  m_verticalSlider->blockSignals(signalsBlocked);
  */
}

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

void PlainColorPage::setColor(const TColorStyle &style, int colorParameterIndex)
{
	TPixel32 newPixel = style.getColorParamValue(colorParameterIndex);
	if (m_color.getTPixel() == newPixel)
		return;
	bool oldSignalEnabled = m_signalEnabled;
	m_signalEnabled = false;
	m_color.setTPixel(newPixel);
	updateControls();
	m_signalEnabled = oldSignalEnabled;
}

//-----------------------------------------------------------------------------
/*
void PlainColorPage::setWheelChannel(int channel)
{
	assert(0<=channel && channel<7);
	m_squaredColorWheel->setChannel(channel);
  bool signalsBlocked = m_verticalSlider->signalsBlocked();
	m_verticalSlider->blockSignals(true);
	m_verticalSlider->setChannel((ColorChannel)channel);
  m_verticalSlider->setRange(0,ChannelMaxValues[channel]);
  m_verticalSlider->setValue(m_color.getValue((ColorChannel)channel));
  m_verticalSlider->update();
  m_verticalSlider->blockSignals(signalsBlocked);
}
*/
//-----------------------------------------------------------------------------

void PlainColorPage::onControlChanged(const ColorModel &color, bool isDragging)
{
	if (!(m_color == color)) {
		m_color = color;
		updateControls();
	}

	if (m_signalEnabled)
		emit colorChanged(m_color, isDragging);
}

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

void PlainColorPage::onWheelChanged(const ColorModel &color, bool isDragging)
{
	if (!(m_color == color)) {
		m_color = color;
		updateControls();
	}
	if (m_signalEnabled)
		emit colorChanged(m_color, isDragging);
}

//-----------------------------------------------------------------------------
/*
void PlainColorPage::onWheelSliderChanged(int value)
{
	if(m_color.getValue(m_verticalSlider->getChannel()) == value) return;
	m_color.setValue(m_verticalSlider->getChannel(), value);
  updateControls();
  if(m_signalEnabled)
    emit colorChanged(m_color, true);
}
*/
//-----------------------------------------------------------------------------
/*
void PlainColorPage::onWheelSliderReleased()
{
  emit colorChanged(m_color, false);
}
*/

//*****************************************************************************
//    StyleChooserPage  implementation
//*****************************************************************************

TFilePath StyleChooserPage::m_rootPath;

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

StyleChooserPage::StyleChooserPage(QWidget *parent)
	: StyleEditorPage(parent), m_chipOrigin(5, 3), m_chipSize(25, 25), m_chipPerRow(0), m_currentIndex(-1)
{
}

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

void StyleChooserPage::paintEvent(QPaintEvent *)
{
	if (loadIfNeeded())
		computeSize();

	QPainter p(this);
	//p.setRenderHint(QPainter::SmoothPixmapTransform);
	if (m_chipPerRow == 0 || getChipCount() == 0)
		return;

	int w = parentWidget()->width();
	int chipLx = m_chipSize.width(), chipLy = m_chipSize.height();
	int nX = m_chipPerRow;
	int nY = (getChipCount() + m_chipPerRow - 1) / m_chipPerRow;
	int x0 = m_chipOrigin.x();
	int y0 = m_chipOrigin.y();
	int i, j;
	QRect currentIndexRect = QRect();
	int count = 0;
	for (i = 0; i < nY; i++)
		for (j = 0; j < nX; j++) {
			QRect rect(x0 + chipLx * j + 2, y0 + chipLy * i + 2, chipLx, chipLy);

			drawChip(p, rect, count);
			p.setPen(Qt::black);
			p.drawRect(rect);

			if (m_currentIndex == count)
				currentIndexRect = rect;

			count++;
			if (count >= getChipCount())
				break;
		}

	if (!currentIndexRect.isEmpty()) {
		// Draw the curentIndex border
		p.setPen(Qt::white);
		p.drawRect(currentIndexRect);
		p.setPen(QColor(199, 202, 50));
		p.drawRect(currentIndexRect.adjusted(1, 1, -1, -1));
		p.setPen(Qt::white);
		p.drawRect(currentIndexRect.adjusted(2, 2, -2, -2));
		p.setPen(Qt::black);
		p.drawRect(currentIndexRect.adjusted(3, 3, -3, -3));
	}
}

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

void StyleChooserPage::computeSize()
{
	int w = width();
	m_chipPerRow = (w - 15) / m_chipSize.width();
	int rowCount = 0;
	if (m_chipPerRow != 0)
		rowCount = (getChipCount() + m_chipPerRow - 1) / m_chipPerRow;
	setMinimumSize(5 * m_chipSize.width(), rowCount * m_chipSize.height() + 10);
	update();
}

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

int StyleChooserPage::posToIndex(const QPoint &pos) const
{
	if (m_chipPerRow == 0)
		return -1;

	int x = (pos.x() - m_chipOrigin.x() - 2) / m_chipSize.width();
	if (x >= m_chipPerRow)
		return -1;

	int y = (pos.y() - m_chipOrigin.y() - 2) / m_chipSize.height();

	int index = x + m_chipPerRow * y;
	if (index < 0 || index >= getChipCount())
		return -1;

	return index;
}

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

void StyleChooserPage::mousePressEvent(QMouseEvent *event)
{
	QPoint pos = event->pos();
	int currentIndex = posToIndex(pos);
	if (currentIndex < 0)
		return;
	m_currentIndex = currentIndex;
	onSelect(currentIndex);

	update();
}

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

void StyleChooserPage::mouseReleaseEvent(QMouseEvent *event)
{
}

//-----------------------------------------------------------------------------
//TOGLIERE
void StyleChooserPage::setRootPath(const TFilePath &rootPath)
{
	m_rootPath = rootPath;
}

//*****************************************************************************
//    CustomStyleChooser  definition
//*****************************************************************************

class CustomStyleChooserPage : public StyleChooserPage
{
public:
	CustomStyleChooserPage(QWidget *parent = 0)
		: StyleChooserPage(parent)
	{
	}

	static CustomStyleManager *styleManager();

	bool event(QEvent *e);

	void showEvent(QShowEvent *)
	{
		connect(styleManager(), SIGNAL(patternAdded()), this, SLOT(computeSize()));
		styleManager()->loadItems();
	}
	void hideEvent(QHideEvent *)
	{
		disconnect(styleManager(), SIGNAL(patternAdded()), this, SLOT(computeSize()));
	}
	bool loadIfNeeded() { return false; } // serve?
	/*
    if(!m_loaded) {loadItems(); m_loaded=true;return true;}
    else return false;
  }
	*/

	int getChipCount() const { return styleManager()->getPatternCount(); }

	void drawChip(QPainter &p, QRect rect, int index)
	{
		assert(0 <= index && index < getChipCount());
		CustomStyleManager::PatternData pattern =
			styleManager()->getPattern(index);
		p.drawImage(rect, *pattern.m_image);
	}
	void onSelect(int index);
};

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

CustomStyleManager *CustomStyleChooserPage::styleManager()
{
	static const QString filters("*.pli *.tif *.png *.tga *.tiff *.sgi *.rgb *.pct *.pic");
	static CustomStyleManager theManager(TFilePath("custom styles"), filters);
	return &theManager;
}

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

bool CustomStyleChooserPage::event(QEvent *e)
{
	//Intercept tooltip events
	if (e->type() != QEvent::ToolTip)
		return StyleChooserPage::event(e);

	//see StyleChooserPage::paintEvent
	CustomStyleManager *manager = styleManager();
	QHelpEvent *he = static_cast<QHelpEvent *>(e);

	int chipIdx = posToIndex(he->pos()), chipCount = manager->getPatternCount();
	if (chipIdx < 0 || chipIdx >= chipCount)
		return false;

	CustomStyleManager::PatternData pattern = manager->getPattern(chipIdx);
	QToolTip::showText(he->globalPos(), QString::fromStdString(pattern.m_patternName));

	return true;
}

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

void CustomStyleChooserPage::onSelect(int index)
{
	if (index < 0 || index >= getChipCount())
		return;

	CustomStyleManager::PatternData pattern =
		styleManager()->getPattern(index);

	if (m_currentIndex < 0)
		return;

	string name = pattern.m_patternName;
	if (pattern.m_isVector) {
		TVectorImagePatternStrokeStyle cs(name);
		emit styleSelected(cs);
	} else {
		TRasterImagePatternStrokeStyle cs(name);
		emit styleSelected(cs);
	}
}

//*****************************************************************************
//    VectorBrushStyleChooser  definition
//*****************************************************************************

class VectorBrushStyleChooserPage : public StyleChooserPage
{
public:
	VectorBrushStyleChooserPage(QWidget *parent = 0)
		: StyleChooserPage(parent)
	{
		m_chipSize = QSize(60, 25);
	}

	static CustomStyleManager *styleManager();

	bool event(QEvent *e);

	void showEvent(QShowEvent *)
	{
		connect(styleManager(), SIGNAL(patternAdded()), this, SLOT(computeSize()));
		styleManager()->loadItems();
	}
	void hideEvent(QHideEvent *)
	{
		disconnect(styleManager(), SIGNAL(patternAdded()), this, SLOT(computeSize()));
	}
	bool loadIfNeeded() { return false; }

	int getChipCount() const { return styleManager()->getPatternCount() + 1; }

	void drawChip(QPainter &p, QRect rect, int index);
	void onSelect(int index);
};

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

CustomStyleManager *VectorBrushStyleChooserPage::styleManager()
{
	static CustomStyleManager theManager(TFilePath("vector brushes"), "*.pli", QSize(60, 25));
	return &theManager;
}

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

bool VectorBrushStyleChooserPage::event(QEvent *e)
{
	//Intercept tooltip events
	if (e->type() != QEvent::ToolTip)
		return StyleChooserPage::event(e);

	//see StyleChooserPage::paintEvent
	CustomStyleManager *manager = styleManager();
	QHelpEvent *he = static_cast<QHelpEvent *>(e);

	int chipIdx = posToIndex(he->pos()), chipCount = getChipCount();
	if (chipIdx < 0 || chipIdx >= chipCount)
		return false;

	if (chipIdx > 0) {
		CustomStyleManager::PatternData pattern = manager->getPattern(chipIdx - 1);
		QToolTip::showText(he->globalPos(), QString::fromStdString(pattern.m_patternName));
	} else
		QToolTip::showText(he->globalPos(), tr("Plain color"));

	return true;
}

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

void VectorBrushStyleChooserPage::drawChip(QPainter &p, QRect rect, int index)
{
	if (index == 0) {
		static QImage noSpecialStyleImage(":Resources/no_vectorbrush.png");
		p.drawImage(rect, noSpecialStyleImage);
	} else {
		assert(0 <= index && index < getChipCount());
		CustomStyleManager::PatternData pattern =
			styleManager()->getPattern(index - 1);
		p.drawImage(rect, *pattern.m_image);
	}
}

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

void VectorBrushStyleChooserPage::onSelect(int index)
{
	if (index < 0 || index >= getChipCount())
		return;

	if (index > 0) {
		--index;

		CustomStyleManager::PatternData pattern =
			styleManager()->getPattern(index);

		if (m_currentIndex < 0)
			return;

		string name = pattern.m_patternName;
		assert(pattern.m_isVector);
		if (!pattern.m_isVector)
			return;

		TVectorBrushStyle cs(name);
		emit styleSelected(cs);
	} else {
		TSolidColorStyle cs(TPixel32::Black);
		emit styleSelected(cs);
	}
}

//*****************************************************************************
//    TextureStyleChooser  definition
//*****************************************************************************

struct Texture {
	TRasterP m_raster;
	QString m_name;
};

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

class TextureStyleChooserPage : public StyleChooserPage
{
	static vector<Texture> m_textures;
	static bool m_loaded;

public:
	TextureStyleChooserPage(QWidget *parent = 0)
		: StyleChooserPage(parent)
	{
	}

	bool loadIfNeeded()
	{
		if (!m_loaded) {
			loadItems();
			m_loaded = true;
			return true;
		} else
			return false;
	}

	int getChipCount() const { return m_textures.size(); }

	static void loadTexture(const TFilePath &fp);
	static void loadItems();

	void drawChip(QPainter &p, QRect rect, int index)
	{
		assert(0 <= index && index < getChipCount());
		p.drawImage(rect, rasterToQImage(m_textures[index].m_raster));
	}

	void onSelect(int index);

	bool event(QEvent *e);
};

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

vector<Texture> TextureStyleChooserPage::m_textures;
bool TextureStyleChooserPage::m_loaded(false);

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

void TextureStyleChooserPage::loadTexture(const TFilePath &fp)
{
	if (fp == TFilePath()) {
		TRaster32P ras(25, 25);
		TTextureStyle::fillCustomTextureIcon(ras);
		//ras->fill(TPixel::Blue);
		Texture customText = {
			ras,
			QString("")};

		m_textures.push_back(customText);
		return;
	}

	TRasterP ras;
	TImageReader::load(fp, ras);
	if (!ras || ras->getLx() < 2 || ras->getLy() < 2)
		return;

	TRaster32P ras32 = ras;
	if (!ras32)
		return;

	TDimension d(2, 2);
	while (d.lx < 256 && d.lx * 2 <= ras32->getLx())
		d.lx *= 2;
	while (d.ly < 256 && d.ly * 2 <= ras32->getLy())
		d.ly *= 2;

	TRaster32P texture;
	if (d == ras32->getSize())
		texture = ras32;
	else {
		texture = TRaster32P(d);
		TScale sc((double)texture->getLx() / ras32->getLx(), (double)texture->getLy() / ras32->getLy());
		TRop::resample(texture, ras32, sc);
	}

	Texture text = {
		texture,
		QString::fromStdWString(fp.getLevelNameW())};

	m_textures.push_back(text);
}

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

void TextureStyleChooserPage::loadItems()
{
	m_textures.clear();
	if (getRootPath() == TFilePath())
		return;
	TFilePath texturePath = getRootPath() + "textures";
	TFilePathSet fps;
	try {
		fps = TSystem::readDirectory(texturePath);
	} catch (...) {
		return;
	}
	if (fps.empty())
		return;
	int count = 0;
	for (TFilePathSet::iterator it = fps.begin(); it != fps.end(); it++)
		if (TFileType::getInfo(*it) == TFileType::RASTER_IMAGE) {
			try {
				loadTexture(*it);
				++count;
			} catch (...) {
			}
		}
	loadTexture(TFilePath()); //custom texture
}

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

void TextureStyleChooserPage::onSelect(int index)
{
	assert(0 <= index && index < (int)m_textures.size());

	TTextureStyle style(m_textures[index].m_raster,
						TFilePath(m_textures[index].m_name.toStdWString()));
	emit styleSelected(style);
}

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

bool TextureStyleChooserPage::event(QEvent *e)
{
	if (e->type() == QEvent::ToolTip) {
		QHelpEvent *helpEvent = dynamic_cast<QHelpEvent *>(e);
		QString toolTip;
		QPoint pos = helpEvent->pos();
		int index = posToIndex(pos);
		if (index >= 0 && index < (int)m_textures.size()) {
			toolTip = m_textures[index].m_name;
			QToolTip::showText(helpEvent->globalPos(), toolTip != QString() ? toolTip : "Custom Texture");
		}
		e->accept();
	}
	return StyleChooserPage::event(e);
}

//*****************************************************************************
//    SpecialStyleChooser  definition
//*****************************************************************************

class SpecialStyleChooserPage : public StyleChooserPage
{

	static vector<pair<int, QImage *>> m_customStyles;
	static bool m_loaded;

public:
	SpecialStyleChooserPage(QWidget *parent = 0, const TFilePath &rootDir = TFilePath())
		: StyleChooserPage(parent)
	{
	}

	bool loadIfNeeded()
	{
		if (!m_loaded) {
			loadItems();
			m_loaded = true;
			return true;
		} else
			return false;
	}
	int getChipCount() const { return m_customStyles.size(); }

	void loadItems();

	void drawChip(QPainter &p, QRect rect, int index);
	void onSelect(int index);
	bool event(QEvent *e);
};

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

vector<pair<int, QImage *>> SpecialStyleChooserPage::m_customStyles;
bool SpecialStyleChooserPage::m_loaded(false);

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

void SpecialStyleChooserPage::loadItems()
{
	vector<int> tags;
	TColorStyle::getAllTags(tags);

	int chipCount = 0;

	for (int j = 0; j < (int)tags.size(); j++) {
		int tagId = tags[j];
		if (tagId == 3 ||	// solid color
			tagId == 4 ||	// texture
			tagId == 100 ||  // obsolete imagepattern id
			tagId == 2000 || // imagepattern
			tagId == 2800 || // imagepattern
			tagId == 2001 || // cleanup
			tagId == 2002 || // ??
			tagId == 3000	// vector brush
			)
			continue;

		TColorStyle *style = TColorStyle::create(tagId);
		if (style->isRasterStyle()) {
			delete style;
			continue;
		}
		TDimension chipSize(getChipSize().width(), getChipSize().height());
		QImage *image = new QImage(rasterToQImage(style->getIcon(chipSize), false));
		m_customStyles.push_back(std::make_pair(tagId, image));
		delete style;
	}
}

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

void SpecialStyleChooserPage::drawChip(QPainter &p, QRect rect, int index)
{
	if (index == 0) {
		static QImage noSpecialStyleImage(":Resources/no_specialstyle.png");
		p.drawImage(rect, noSpecialStyleImage);
	} else {
		int j = index - 1;
		if (0 <= j && j < (int)m_customStyles.size())
			p.drawImage(rect, *m_customStyles[j].second);
		else
			p.fillRect(rect, QBrush(QColor(255, 0, 0)));
	}
}

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

void SpecialStyleChooserPage::onSelect(int index)
{
	assert(0 <= index && index < (int)m_customStyles.size());
	TColorStyle *cs = 0;
	if (m_currentIndex < 0)
		return;
	if (index == 0)
		cs = new TSolidColorStyle(TPixel32::Black);
	else {
		int j = index - 1;
		assert(0 <= j && j < (int)m_customStyles.size());
		int tagId = m_customStyles[j].first;
		cs = TColorStyle::create(tagId);
	}
	emit styleSelected(*cs);
}

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

bool SpecialStyleChooserPage::event(QEvent *e)
{
	if (e->type() == QEvent::ToolTip) {
		QHelpEvent *helpEvent = dynamic_cast<QHelpEvent *>(e);
		QString toolTip;
		QPoint pos = helpEvent->pos();
		int index = posToIndex(pos);
		if (index == 0)
			toolTip = tr("Plain color");
		else {
			int j = index - 1;
			if (0 <= j && j < (int)m_customStyles.size()) {
				int tagId = m_customStyles[j].first;
				TColorStyle *cs = TColorStyle::create(tagId);
				if (cs) {
					toolTip = cs->getDescription();
					delete cs;
				}
			}
		}
		if (toolTip != "")
			QToolTip::showText(helpEvent->globalPos(), toolTip);
		else
			QToolTip::hideText();
		e->accept();
	}
	return StyleChooserPage::event(e);
}

//=============================================================================
// SettingBox
//-----------------------------------------------------------------------------
/*
SettingBox::SettingBox(QWidget *parent, int index)
: QWidget(parent)
, m_index(index)
, m_style(0)
{
	QHBoxLayout* hLayout = new QHBoxLayout(this);
	hLayout->setSpacing(5);
	hLayout->setMargin(0);
	hLayout->addSpacing(10);
	m_name = new QLabel(this);
	m_name->setFixedSize(82,20);
	m_name->setStyleSheet("border: 0px;");
	hLayout->addWidget(m_name,0);
	m_doubleField = new DoubleField(this, true);
	hLayout->addWidget(m_doubleField,1);
	hLayout->addSpacing(10);
	bool ret = connect(m_doubleField, SIGNAL(valueChanged(bool)), this, SLOT(onValueChanged(bool)));
  assert(ret);
	setLayout(hLayout);
	setFixedHeight(22);
}

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

void SettingBox::setParameters(TColorStyle* cs)
{
	if(!cs)
	{
		m_style = cs;
		return;
	}
	if(cs->getParamCount() == 0 || m_index<0 || cs->getParamCount()<=m_index)
		return;
	QString paramName = cs->getParamNames(m_index);
	m_name->setText(paramName);
   double newValue = cs->getParamValue(TColorStyle::double_tag(), m_index);
	double value = m_doubleField->getValue();
	m_style = cs;
	if(value != newValue)
	{
		double min=0, max=1;
		cs->getParamRange(m_index,min,max);
		m_doubleField->setValues(newValue, min, max);
	}
	TCleanupStyle* cleanupStyle = dynamic_cast<TCleanupStyle*>(cs);
	if(paramName == "Contrast" && cleanupStyle)
	{
		if(!cleanupStyle->isContrastEnabled())
			m_doubleField->setEnabled(false);
		else
			m_doubleField->setEnabled(true);
	}
	update();
}

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

void SettingBox::setColorStyleParam(double value, bool isDragging)
{
  TColorStyle* style = m_style;
  assert(style && m_index < style->getParamCount());

  double min = 0.0, max = 1.0;
  style->getParamRange(m_index, min, max);

  style->setParamValue(m_index, tcrop(value, min, max));

  emit valueChanged(*style, isDragging);
}

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

void SettingBox::onValueChanged(bool isDragging)
{
	if(!m_style || m_style->getParamCount() == 0)
		return;

	double value = m_doubleField->getValue();
	if(isDragging && m_style->getParamValue(TColorStyle::double_tag(), m_index) == value)
		return;

	setColorStyleParam(value, isDragging);
}
*/

//*****************************************************************************
//    SettingsPage  implementation
//*****************************************************************************

SettingsPage::SettingsPage(QWidget *parent)
	: QScrollArea(parent), m_updating(false)
{
	bool ret = true;

	setObjectName("styleEditorPage"); // It is necessary for the styleSheet
	setFrameStyle(QFrame::StyledPanel);

	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	setWidgetResizable(true);

	// Build the scrolled widget
	QFrame *paramsContainer = new QFrame(this);
	setWidget(paramsContainer);

	QVBoxLayout *paramsContainerLayout = new QVBoxLayout(this);
	paramsContainer->setLayout(paramsContainerLayout);

	// Add a vertical layout to store the "autofill" checkbox widgets
	{
		m_autopaintToggleBox = new QWidget(this);
		//box->setFixedHeight(22);
		paramsContainerLayout->addWidget(m_autopaintToggleBox);

		QHBoxLayout *hLayout = new QHBoxLayout;
		m_autopaintToggleBox->setLayout(hLayout);

		hLayout->setSpacing(5);
		hLayout->setMargin(0);
		hLayout->addSpacing(98);

		m_autoFillCheckBox = new QCheckBox;
		hLayout->addWidget(m_autoFillCheckBox);

		QLabel *label = new QLabel(StyleEditorGUI::SettingsPage::tr("Autopaint for Lines"));
		hLayout->addWidget(label);

		hLayout->addStretch();

		ret = connect(m_autoFillCheckBox, SIGNAL(stateChanged(int)),
					  this, SLOT(onAutofillChanged()));
		assert(ret);
	}

	// Prepare the style parameters layout
	m_paramsLayout = new QGridLayout;
	paramsContainerLayout->addLayout(m_paramsLayout);

	paramsContainerLayout->addStretch();
}

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

void SettingsPage::enableAutopaintToggle(bool enabled)
{
	m_autopaintToggleBox->setVisible(enabled);
}

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

void SettingsPage::setStyle(const TColorStyleP &editedStyle)
{
	struct locals {
		inline static void clearLayout(QLayout *layout)
		{
			QLayoutItem *item;
			while ((item = layout->takeAt(0)) != 0) {
				delete item->layout();
				delete item->spacerItem();
				delete item->widget();
				delete item;
			}
		}
	}; // locals

	// NOTE: Layout reubilds must be avoided whenever possible. In particular, be warned that this
	// function may be invoked when signals emitted from this function are still "flying"...

	bool clearLayout = m_editedStyle && !(editedStyle && typeid(*m_editedStyle) == typeid(*editedStyle));
	bool buildLayout = editedStyle && !(m_editedStyle && typeid(*m_editedStyle) == typeid(*editedStyle));

	m_editedStyle = editedStyle;

	if (clearLayout)
		locals::clearLayout(m_paramsLayout);

	if (buildLayout) {
		assert(m_paramsLayout->count() == 0);

		// Assign new settings widgets - one label/editor for each parameter
		bool ret = true;

		int p, pCount = editedStyle->getParamCount();
		for (p = 0; p != pCount; ++p) {
			// Assign label
			QLabel *label = new QLabel(editedStyle->getParamNames(p));
			m_paramsLayout->addWidget(label, p, 0);

			// Assign parameter
			switch (editedStyle->getParamType(p)) {
			case TColorStyle::BOOL: {
				QCheckBox *checkBox = new QCheckBox;
				m_paramsLayout->addWidget(checkBox, p, 1);

				ret = QObject::connect(checkBox, SIGNAL(toggled(bool)), this, SLOT(onValueChanged())) && ret;
			}

				CASE TColorStyle::INT:
				{
					DVGui::IntField *intField = new DVGui::IntField;
					m_paramsLayout->addWidget(intField, p, 1);

					int min, max;
					m_editedStyle->getParamRange(p, min, max);

					intField->setRange(min, max);

					ret = QObject::connect(intField, SIGNAL(valueChanged(bool)), this, SLOT(onValueChanged(bool))) && ret;
				}

				CASE TColorStyle::ENUM:
				{
					QComboBox *comboBox = new QComboBox;
					m_paramsLayout->addWidget(comboBox, p, 1);

					QStringList items;
					m_editedStyle->getParamRange(p, items);

					comboBox->addItems(items);

					ret = QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onValueChanged())) && ret;
				}

				CASE TColorStyle::DOUBLE:
				{
					DVGui::DoubleField *doubleField = new DVGui::DoubleField;
					m_paramsLayout->addWidget(doubleField, p, 1);

					double min, max;
					m_editedStyle->getParamRange(p, min, max);

					doubleField->setRange(min, max);

					ret = QObject::connect(doubleField, SIGNAL(valueChanged(bool)), this, SLOT(onValueChanged(bool))) && ret;
				}

				CASE TColorStyle::FILEPATH:
				{
					DVGui::FileField *fileField = new DVGui::FileField;
					m_paramsLayout->addWidget(fileField, p, 1);

					QStringList extensions;
					m_editedStyle->getParamRange(p, extensions);

					fileField->setFileMode(QFileDialog::AnyFile);
					fileField->setFilters(extensions);

					fileField->setPath(QString::fromStdWString(
						editedStyle->getParamValue(TColorStyle::TFilePath_tag(), p).getWideString()));

					ret = QObject::connect(fileField, SIGNAL(pathChanged()), this, SLOT(onValueChanged())) && ret;
				}
			}

			assert(ret);
		}
	}

	updateValues();
}

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

void SettingsPage::updateValues()
{
	if (!m_editedStyle)
		return;

	struct Updating {
		SettingsPage *m_this;						// Prevent 'param changed' signals from being
		~Updating() { m_this->m_updating = false; } // sent when updating editor widgets - this is
	} updating = {(m_updating = true, this)};		// just a view REFRESH function.

	// Deal with the autofill
	m_autoFillCheckBox->setChecked(m_editedStyle->getFlags() & 1);

	int p, pCount = m_editedStyle->getParamCount();
	for (p = 0; p != pCount; ++p) {
		// Update editor values
		switch (m_editedStyle->getParamType(p)) {
		case TColorStyle::BOOL: {
			QCheckBox *checkBox = static_cast<QCheckBox *>(
				m_paramsLayout->itemAtPosition(p, 1)->widget());

			checkBox->setChecked(m_editedStyle->getParamValue(TColorStyle::bool_tag(), p));
		}

			CASE TColorStyle::INT:
			{
				DVGui::IntField *intField = static_cast<DVGui::IntField *>(
					m_paramsLayout->itemAtPosition(p, 1)->widget());

				intField->setValue(m_editedStyle->getParamValue(TColorStyle::int_tag(), p));
			}

			CASE TColorStyle::ENUM:
			{
				QComboBox *comboBox = static_cast<QComboBox *>(
					m_paramsLayout->itemAtPosition(p, 1)->widget());

				comboBox->setCurrentIndex(m_editedStyle->getParamValue(TColorStyle::int_tag(), p));
			}

			CASE TColorStyle::DOUBLE:
			{
				DVGui::DoubleField *doubleField = static_cast<DVGui::DoubleField *>(
					m_paramsLayout->itemAtPosition(p, 1)->widget());

				doubleField->setValue(m_editedStyle->getParamValue(TColorStyle::double_tag(), p));
			}

			CASE TColorStyle::FILEPATH:
			{
				DVGui::FileField *fileField = static_cast<DVGui::FileField *>(
					m_paramsLayout->itemAtPosition(p, 1)->widget());

				fileField->setPath(QString::fromStdWString(
					m_editedStyle->getParamValue(TColorStyle::TFilePath_tag(), p).getWideString()));
			}
		}
	}
}

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

void SettingsPage::onAutofillChanged()
{
	m_editedStyle->setFlags((unsigned int)(m_autoFillCheckBox->isChecked()));

	if (!m_updating)
		emit paramStyleChanged(false); // Forward the signal to the style editor
}

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

void SettingsPage::onValueChanged(bool isDragging)
{
	struct Locals {
		SettingsPage *m_this;

		int paramIndex(const QWidget *widget)
		{
			int p, pCount = m_this->m_paramsLayout->rowCount();
			for (p = 0; p != pCount; ++p)
				if (m_this->m_paramsLayout->itemAtPosition(p, 1)->widget() == widget)
					break;

			return p;
		}

	} locals = {this};

	assert(m_editedStyle);

	// Extract the parameter index
	QWidget *senderWidget = static_cast<QWidget *>(sender());
	int p = locals.paramIndex(senderWidget);

	assert(0 <= p && p < m_editedStyle->getParamCount());

	// Update the style's parameter value
	switch (m_editedStyle->getParamType(p)) {
	case TColorStyle::BOOL:
		m_editedStyle->setParamValue(p, static_cast<QCheckBox *>(senderWidget)->isChecked());

		CASE TColorStyle::INT : m_editedStyle->setParamValue(p, static_cast<DVGui::IntField *>(senderWidget)->getValue());

		CASE TColorStyle::ENUM : m_editedStyle->setParamValue(p, static_cast<QComboBox *>(senderWidget)->currentIndex());

		CASE TColorStyle::DOUBLE : m_editedStyle->setParamValue(p, static_cast<DVGui::DoubleField *>(senderWidget)->getValue());

		CASE TColorStyle::FILEPATH:
		{
			const QString &string = static_cast<DVGui::FileField *>(senderWidget)->getPath();
			m_editedStyle->setParamValue(p, TFilePath(string.toStdWString()));
		}
	}

	// Forward the signal to the style editor
	if (!m_updating)
		emit paramStyleChanged(isDragging);
}

//=============================================================================

namespace
{

QScrollArea *makeChooserPage(QWidget *chooser)
{
	QScrollArea *scrollArea = new QScrollArea();
	scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
	scrollArea->setWidgetResizable(true);
	scrollArea->setWidget(chooser);
	return scrollArea;
}

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

QScrollArea *makeChooserPageWithoutScrollBar(QWidget *chooser)
{
	QScrollArea *scrollArea = new QScrollArea();
	scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	scrollArea->setWidgetResizable(true);
	scrollArea->setWidget(chooser);
	return scrollArea;
}

} // namespace

//*****************************************************************************
//    StyleEditor  implementation
//*****************************************************************************

StyleEditor::StyleEditor(PaletteController *paletteController, QWidget *parent)
	: QWidget(parent), m_paletteController(paletteController), m_paletteHandle(paletteController->getCurrentPalette()), m_cleanupPaletteHandle(paletteController->getCurrentCleanupPalette()), m_toolBar(0), m_enabled(false), m_enabledOnlyFirstTab(false), m_enabledFirstAndLastTab(false), m_oldStyle(0), m_editedStyle(0)
{
	setFocusPolicy(Qt::NoFocus);
	//TOGLIERE
	TFilePath libraryPath = ToonzFolder::getLibraryFolder();
	setRootPath(libraryPath);

	m_styleBar = new TabBar(this);
	m_styleBar->setDrawBase(false);
	m_styleBar->setObjectName("StyleEditorTabBar");

	// This widget is used to set the background color of the tabBar
	// using the styleSheet.
	// It is also used to take 6px on the left before the tabBar
	// and to draw the two lines on the bottom size
	m_tabBarContainer = new TabBarContainter(this);
	m_colorParameterSelector = new ColorParameterSelector(this);

	m_plainColorPage = new PlainColorPage(0);
	m_textureStylePage = new TextureStyleChooserPage(0);
	m_specialStylePage = new SpecialStyleChooserPage(0);
	m_customStylePage = new CustomStyleChooserPage(0);
	m_vectorBrushesStylePage = new VectorBrushStyleChooserPage(0);
	m_settingsPage = new SettingsPage(0);

	QWidget *emptyPage = new StyleEditorPage(0);

	m_statusLabel = new QLabel("", this);

	// For the plainColorPage and the settingsPage
	// I create a "fake" QScrollArea (without ScrollingBar
	// in order to use the styleSheet to stylish its background
	QScrollArea *plainArea = makeChooserPageWithoutScrollBar(m_plainColorPage);

	QScrollArea *textureArea = makeChooserPage(m_textureStylePage);
	QScrollArea *specialArea = makeChooserPage(m_specialStylePage);
	QScrollArea *customArea = makeChooserPage(m_customStylePage);
	QScrollArea *vectorBrushesArea = makeChooserPage(m_vectorBrushesStylePage);
	QScrollArea *settingsArea = makeChooserPageWithoutScrollBar(m_settingsPage);

	m_styleChooser = new QStackedWidget(this);
	m_styleChooser->addWidget(plainArea);
	m_styleChooser->addWidget(textureArea);
	m_styleChooser->addWidget(specialArea);
	m_styleChooser->addWidget(customArea);
	m_styleChooser->addWidget(vectorBrushesArea);
	m_styleChooser->addWidget(settingsArea);
	m_styleChooser->addWidget(makeChooserPageWithoutScrollBar(emptyPage));
	m_styleChooser->setFocusPolicy(Qt::NoFocus);

	QFrame *bottomWidget = createBottomWidget();

	m_toolBar = new QToolBar(this);
	m_toolBar->setMovable(false);
	m_toolBar->setMaximumHeight(22);
	m_toolBar->addWidget(m_colorParameterSelector);

	m_colorParameterSelector->setMinimumWidth(200);
	m_colorParameterSelector->setFixedHeight(22);

	/* ------- layout ------- */
	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->setMargin(1);
	mainLayout->setSpacing(0);
	{
		QHBoxLayout *hLayout = new QHBoxLayout;
		hLayout->setMargin(0);
		{
			hLayout->addSpacing(4);
			hLayout->addWidget(m_styleBar);
			hLayout->addStretch();
		}
		m_tabBarContainer->setLayout(hLayout);

		mainLayout->addWidget(m_tabBarContainer, 0);
		mainLayout->addWidget(m_styleChooser, 1);
		mainLayout->addWidget(bottomWidget, 0);
		mainLayout->addWidget(m_statusLabel, 0);
		mainLayout->addWidget(m_toolBar, 0);
	}
	setLayout(mainLayout);

	/* ------- signal-slot connections ------- */

	bool ret = true;
	ret = ret && connect(m_styleBar, SIGNAL(currentChanged(int)), this, SLOT(setPage(int)));
	ret = ret && connect(m_colorParameterSelector, SIGNAL(colorParamChanged()), this, SLOT(onColorParamChanged()));
	ret = ret && connect(m_textureStylePage, SIGNAL(styleSelected(const TColorStyle &)),
						 this, SLOT(selectStyle(const TColorStyle &)));
	ret = ret && connect(m_specialStylePage, SIGNAL(styleSelected(const TColorStyle &)),
						 this, SLOT(selectStyle(const TColorStyle &)));
	ret = ret && connect(m_customStylePage, SIGNAL(styleSelected(const TColorStyle &)),
						 this, SLOT(selectStyle(const TColorStyle &)));
	ret = ret && connect(m_vectorBrushesStylePage, SIGNAL(styleSelected(const TColorStyle &)),
						 this, SLOT(selectStyle(const TColorStyle &)));
	ret = ret && connect(m_settingsPage, SIGNAL(paramStyleChanged(bool)), this, SLOT(onParamStyleChanged(bool)));
	ret = ret && connect(m_plainColorPage, SIGNAL(colorChanged(const ColorModel &, bool)),
						 this, SLOT(onColorChanged(const ColorModel &, bool)));
	assert(ret);

	/* ------- initial conditions ------- */
	autoCheckChanged(false);
	enable(false, false, false);
	//set to the empty page
	m_styleChooser->setCurrentIndex(6);
}

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

StyleEditor::~StyleEditor()
{
}

//-----------------------------------------------------------------------------
/*
void StyleEditor::setPaletteHandle(TPaletteHandle* paletteHandle)
{
	if(m_paletteHandle != paletteHandle)
		m_paletteHandle = paletteHandle;
	onStyleSwitched();
}
*/
//-----------------------------------------------------------------------------

QFrame *StyleEditor::createBottomWidget()
{
	QFrame *bottomWidget = new QFrame(this);
	m_autoButton = new QPushButton(tr("Auto  \nApply"));
	m_oldColor = new StyleSample(this, 42, 20);
	m_newColor = new StyleSample(this, 42, 20);
	m_applyButton = new QPushButton(tr("Apply"));

	bottomWidget->setFrameStyle(QFrame::StyledPanel);
	bottomWidget->setObjectName("bottomWidget");
	bottomWidget->setContentsMargins(0, 0, 0, 0);
	m_applyButton->setToolTip(tr("Apply changes to current style"));
	m_applyButton->setDisabled(true);
	m_applyButton->setFocusPolicy(Qt::NoFocus);

	m_autoButton->setCheckable(true);
	m_autoButton->setToolTip(tr("Automatically update style changes"));
	m_autoButton->setChecked(false);
	m_autoButton->setFocusPolicy(Qt::NoFocus);

	m_oldColor->setToolTip(tr("Return To Previous Style"));
	m_oldColor->enableClick(true);
	m_oldColor->setEnable(false);
	m_newColor->setToolTip(tr("Current Style"));
	m_newColor->setEnable(false);

	/* ------ layout ------ */
	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->setMargin(4);
	mainLayout->setSpacing(10);
	{
		QHBoxLayout *hLayout = new QHBoxLayout;
		hLayout->setMargin(0);
		hLayout->setSpacing(0);
		{
			hLayout->addWidget(m_autoButton);
			hLayout->addSpacing(2);
			hLayout->addWidget(m_newColor, 1);
			hLayout->addWidget(m_oldColor, 1);
		}
		mainLayout->addLayout(hLayout);

		QHBoxLayout *buttonsLayout = new QHBoxLayout;
		buttonsLayout->setMargin(0);
		buttonsLayout->setSpacing(5);
		{
			buttonsLayout->addWidget(m_applyButton);
		}
		mainLayout->addLayout(buttonsLayout);
	}
	bottomWidget->setLayout(mainLayout);

	/* ------ signal-slot connections ------ */
	bool ret = true;
	ret = ret && connect(m_applyButton, SIGNAL(clicked()), this, SLOT(applyButtonClicked()));
	ret = ret && connect(m_autoButton, SIGNAL(toggled(bool)), this, SLOT(autoCheckChanged(bool)));
	ret = ret && connect(m_oldColor, SIGNAL(clicked(const TColorStyle &)), this, SLOT(onOldStyleClicked(const TColorStyle &)));
	assert(ret);

	return bottomWidget;
}

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

void StyleEditor::updateTabBar()
{
	m_styleBar->clearTabBar();
	if (m_enabled && !m_enabledOnlyFirstTab && !m_enabledFirstAndLastTab) {
		m_styleBar->addSimpleTab(tr("Plain"));
		m_styleBar->addSimpleTab(tr("Texture"));
		m_styleBar->addSimpleTab(tr("Special"));
		m_styleBar->addSimpleTab(tr("Custom"));
		m_styleBar->addSimpleTab(tr("Vector Brush"));
		m_styleBar->addSimpleTab(tr("Settings"));
	} else if (m_enabled && m_enabledOnlyFirstTab && !m_enabledFirstAndLastTab)
		m_styleBar->addSimpleTab(tr("Plain"));
	else if (m_enabled && !m_enabledOnlyFirstTab && m_enabledFirstAndLastTab) {
		m_styleBar->addSimpleTab(tr("Plain"));
		m_styleBar->addSimpleTab(tr("Settings"));
	} else {
		m_styleChooser->setCurrentIndex(6);
		return;
	}
	m_tabBarContainer->layout()->update();
	m_styleChooser->setCurrentIndex(0);
}

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

void StyleEditor::showEvent(QShowEvent *)
{
	m_autoButton->setChecked(m_paletteController->isColorAutoApplyEnabled());
	onStyleSwitched();
	bool ret = true;
	ret = ret && connect(m_paletteHandle, SIGNAL(colorStyleSwitched()), SLOT(onStyleSwitched()));
	ret = ret && connect(m_paletteHandle, SIGNAL(colorStyleChanged()), SLOT(onStyleChanged()));
	ret = ret && connect(m_paletteHandle, SIGNAL(paletteSwitched()), this, SLOT(onStyleSwitched()));
	if (m_cleanupPaletteHandle)
		ret = ret && connect(m_cleanupPaletteHandle, SIGNAL(colorStyleChanged()), SLOT(onCleanupStyleChanged()));

	ret = ret && connect(m_paletteController, SIGNAL(colorAutoApplyEnabled(bool)),
						 this, SLOT(enableColorAutoApply(bool)));
	ret = ret && connect(m_paletteController, SIGNAL(colorSampleChanged(const TPixel32 &)),
						 this, SLOT(setColorSample(const TPixel32 &)));

	assert(ret);
}

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

void StyleEditor::hideEvent(QHideEvent *)
{
	disconnect(m_paletteHandle);
	if (m_cleanupPaletteHandle)
		disconnect(m_cleanupPaletteHandle);
	disconnect(m_paletteController);
}

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

void StyleEditor::onStyleSwitched()
{
	TPalette *palette = getPalette();

	if (!palette) {
		//set the current page to empty
		m_styleChooser->setCurrentIndex(6);
		enable(false);
		m_colorParameterSelector->clear();
		m_oldStyle = TColorStyleP();
		m_editedStyle = TColorStyleP();

		m_statusLabel->setText("- Style not Selected -");
		return;
	}

	int styleIndex = getStyleIndex();
	setEditedStyleToStyle(palette->getStyle(styleIndex));

	bool isStyleNull = setStyle(m_editedStyle.getPointer());
	bool isColorInField = palette->getPaletteName() == toWideString("EmptyColorFieldPalette");
	bool isValidIndex = styleIndex > 0 || isColorInField;
	bool isCleanUpPalette = palette->isCleanupPalette();

	/* ------ update the status text ------ */
	if (!isStyleNull && isValidIndex) {
		QString statusText;
		//palette type
		if (isCleanUpPalette)
			statusText = "[CLEANUP]  ";
		else if (palette->getGlobalName() != L"")
			statusText = "[STUDIO]  ";
		else
			statusText = "[LEVEL]  ";

		//palette name
		statusText += QString::fromStdWString(L" Palette : " + palette->getPaletteName());

		//style name
		statusText += QString::fromStdWString(L" | Style#");
		statusText += QString::number(styleIndex);
		statusText += QString::fromStdWString(L" : " + m_editedStyle->getName());

		m_statusLabel->setText(statusText);
	} else
		m_statusLabel->setText("- Style is Not Valid -");
	enable(!isStyleNull && isValidIndex, isColorInField, isCleanUpPalette);
}

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

void StyleEditor::onStyleChanged()
{
	TPalette *palette = getPalette();
	if (!palette)
		return;

	int styleIndex = getStyleIndex();
	assert(0 <= styleIndex && styleIndex < palette->getStyleCount());

	setEditedStyleToStyle(palette->getStyle(styleIndex));
	setOldStyleToStyle(m_editedStyle.getPointer()); //This line is needed for proper undo behavior

	m_plainColorPage->setColor(*m_editedStyle, getColorParam());
	m_colorParameterSelector->setStyle(*m_editedStyle);
	m_settingsPage->setStyle(m_editedStyle);
	m_newColor->setStyle(*m_editedStyle);
	m_oldColor->setStyle(*m_oldStyle); //This line is needed for proper undo behavior
}

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

void StyleEditor::onCleanupStyleChanged()
{
	if (!m_cleanupPaletteHandle)
		return;

	onStyleChanged();
}

//-----------------------------------------------------------------------------
//TOGLIERE
void StyleEditor::setRootPath(const TFilePath &rootPath)
{
	m_textureStylePage->setRootPath(rootPath);
}

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

void StyleEditor::copyEditedStyleToPalette(bool isDragging)
{
	TPalette *palette = getPalette();
	assert(palette);

	int styleIndex = getStyleIndex();
	assert(0 <= styleIndex && styleIndex < palette->getStyleCount());

	if (!(*m_oldStyle == *m_editedStyle) && (!isDragging || m_paletteController->isColorAutoApplyEnabled()) && m_editedStyle->getGlobalName() != L"" && m_editedStyle->getOriginalName() != L"") {
		// If the adited style is linked to the studio palette, then activate the edited flag
		m_editedStyle->setIsEditedFlag(true);
	}

	palette->setStyle(styleIndex, m_editedStyle->clone()); // Must be done *before* setting the eventual
														   // palette keyframe
	if (!isDragging) {
		if (!(*m_oldStyle == *m_editedStyle)) {
			//do not register undo if the edited color is special one (e.g. changing the ColorField in the fx settings)
			if (palette->getPaletteName() != toWideString("EmptyColorFieldPalette"))
				TUndoManager::manager()->add(new UndoPaletteChange(
					m_paletteHandle, styleIndex, *m_oldStyle, *m_editedStyle));
		}

		setOldStyleToStyle(m_editedStyle.getPointer());

		// In case the frame is a keyframe, update it
		if (palette->isKeyframe(styleIndex, palette->getFrame()))  // here
			palette->setKeyframe(styleIndex, palette->getFrame()); //

		palette->setDirtyFlag(true);
	}

	m_paletteHandle->notifyColorStyleChanged(isDragging);
}

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

void StyleEditor::onColorChanged(const ColorModel &color, bool isDragging)
{
	TPalette *palette = getPalette();
	if (!palette)
		return;

	int styleIndex = getStyleIndex();
	if (styleIndex < 0 || styleIndex > palette->getStyleCount())
		return;

	setEditedStyleToStyle(palette->getStyle(styleIndex)); // CLONES the argument

	if (m_editedStyle) // Should be styleIndex's style at this point
	{
		TPixel tColor = color.getTPixel();

		if (m_editedStyle->hasMainColor()) {
			int index = getColorParam(),
				count = m_editedStyle->getColorParamCount();

			if (0 <= index && index < count)
				m_editedStyle->setColorParamValue(index, tColor);
			else
				m_editedStyle->setMainColor(tColor);

			m_editedStyle->invalidateIcon();
		} else {
			// The argument has NO (main) COLOR. Since color data is being updated, a 'fake'
			// solid style will be created and operated on.
			TSolidColorStyle *style = new TSolidColorStyle(tColor);
			style->assignNames(m_editedStyle.getPointer());

			setEditedStyleToStyle(style); // CLONES the argument

			delete style;
		}

		m_newColor->setStyle(*m_editedStyle);
		m_colorParameterSelector->setStyle(*m_editedStyle);

#ifndef STUDENT
		if (m_autoButton->isChecked())
#endif
		{
			copyEditedStyleToPalette(isDragging);
		}
	}
}

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

void StyleEditor::enable(bool enabled, bool enabledOnlyFirstTab, bool enabledFirstAndLastTab)
{
	if (m_enabled != enabled ||
		m_enabledOnlyFirstTab != enabledOnlyFirstTab ||
		m_enabledFirstAndLastTab != enabledFirstAndLastTab) {
		m_enabled = enabled;
		m_enabledOnlyFirstTab = enabledOnlyFirstTab;
		m_enabledFirstAndLastTab = enabledFirstAndLastTab;
		updateTabBar();
		m_autoButton->setEnabled(enabled);
		m_applyButton->setDisabled(!enabled || m_autoButton->isChecked());
		m_oldColor->setEnable(enabled);
		m_newColor->setEnable(enabled);
		if (enabled == false) {
			m_oldColor->setColor(TPixel32::Transparent);
			m_newColor->setColor(TPixel32::Transparent);
		}
	}

	// lock button behavior
	TPalette *palette = getPalette();
	if (palette && enabled) {
		// when the palette is locked
		if (palette->isLocked()) {
			m_applyButton->setEnabled(false);
			m_autoButton->setChecked(false);
			m_autoButton->setEnabled(false);
		} else // when the palette is unlocked
		{
			m_applyButton->setEnabled(true);
			m_autoButton->setEnabled(true);
		}
	}
}

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

void StyleEditor::onOldStyleClicked(const TColorStyle &)
{
	if (!m_enabled)
		return;
	selectStyle(*(m_oldColor->getStyle()));
}

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

void StyleEditor::setPage(int index)
{
	if (!m_enabledFirstAndLastTab) {
		m_styleChooser->setCurrentIndex(index);
		return;
	}

	//Se sono nel caso first and last page enable e index == 1 la pagina che voglio settare e' l'ultima!
	if (index == 1)
		index = m_styleChooser->count() - 2; //2 perche' alla fine c'e' una pagina vuota
	m_styleChooser->setCurrentIndex(index);
}

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

void StyleEditor::applyButtonClicked()
{
	TPalette *palette = getPalette();
	int styleIndex = getStyleIndex();
	if (!palette || styleIndex < 0 || styleIndex > palette->getStyleCount())
		return;

	copyEditedStyleToPalette(false);
}

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

void StyleEditor::autoCheckChanged(bool value)
{

#ifndef STUDENT
	m_paletteController->enableColorAutoApply(!!value);

	if (!m_enabled)
		return;

	if (value != 0)
		m_applyButton->setDisabled(true);
	else
		m_applyButton->setDisabled(false);
#endif
}

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

void StyleEditor::enableColorAutoApply(bool enabled)
{
	if (m_autoButton->isChecked() != enabled) {
		m_autoButton->setChecked(enabled);
	}
}

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

void StyleEditor::setColorSample(const TPixel32 &color)
{
	// m_colorParameterSelector->setColor(*style);
	ColorModel cm;
	cm.setTPixel(color);
	onColorChanged(cm, true);
}

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

bool StyleEditor::setStyle(TColorStyle *currentStyle)
{
	assert(currentStyle);

	bool isStyleNull = false;

	QString gname = QString::fromStdWString(currentStyle->getGlobalName());
	//if(!gname.isEmpty() && gname == "ColorFieldSimpleColor")
	//	isStyleNull = true;
	//else
	if (!gname.isEmpty() && gname[0] != L'-') {
		currentStyle = 0;
		isStyleNull = true;
	}

	if (currentStyle) {
		m_colorParameterSelector->setStyle(*currentStyle);
		m_plainColorPage->setColor(*currentStyle, getColorParam());
		m_oldColor->setStyle(*currentStyle);
		m_newColor->setStyle(*currentStyle);

		setOldStyleToStyle(currentStyle);
	}

	// Va fatto anche se non c'e' lo style perche' svuota la pagina
	m_settingsPage->setStyle(m_editedStyle);

	return isStyleNull;
}

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

void StyleEditor::setEditedStyleToStyle(const TColorStyle *style)
{
	if (style == m_editedStyle.getPointer())
		return;

	m_editedStyle = TColorStyleP(style->clone());
}

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

void StyleEditor::setOldStyleToStyle(const TColorStyle *style)
{
	if (style == m_oldStyle.getPointer())
		return;
	m_oldStyle = TColorStyleP(style->clone());
}

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

void StyleEditor::selectStyle(const TColorStyle &newStyle)
{
	TPalette *palette = m_paletteHandle->getPalette();
	if (!palette)
		return;

	int styleIndex = m_paletteHandle->getStyleIndex();
	if (styleIndex < 0 || palette->getStyleCount() <= styleIndex)
		return;

	// Register the new previous/edited style pairs
	setOldStyleToStyle(palette->getStyle(styleIndex));
	setEditedStyleToStyle(&newStyle);

	m_editedStyle->assignNames(m_oldStyle.getPointer()); // Copy original name stored in the palette

	// For convenience's sake, copy the main color from the old color, if both have one
	if (m_oldStyle && m_oldStyle->hasMainColor() &&
		m_editedStyle && m_editedStyle->hasMainColor())
		m_editedStyle->setMainColor(m_oldStyle->getMainColor());

#ifndef STUDENT
	if (m_autoButton->isChecked())
#endif
	{
		// If the adited style is linked to the studio palette, then activate the edited flag
		if (m_editedStyle->getGlobalName() != L"" && m_editedStyle->getOriginalName() != L"")
			m_editedStyle->setIsEditedFlag(true);

		// Apply new style, if required
		TUndoManager::manager()->add(new UndoPaletteChange(
			m_paletteHandle, styleIndex, *m_oldStyle, *m_editedStyle));

		palette->setStyle(styleIndex, m_editedStyle->clone());

		m_paletteHandle->notifyColorStyleChanged(false);
		palette->setDirtyFlag(true);
	}

	// Update editor widgets
	m_newColor->setStyle(*m_editedStyle);
	m_plainColorPage->setColor(*m_editedStyle, getColorParam());
	m_colorParameterSelector->setStyle(*m_editedStyle);
	m_settingsPage->setStyle(m_editedStyle);
}

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

void StyleEditor::onColorParamChanged()
{
	TPalette *palette = getPalette();
	if (!palette)
		return;

	int styleIndex = getStyleIndex();
	if (styleIndex < 0 || palette->getStyleCount() <= styleIndex)
		return;

	m_paletteHandle->setStyleParamIndex(getColorParam());

	if (TColorStyle *currentStyle = palette->getStyle(styleIndex)) {
		setEditedStyleToStyle(currentStyle);

		m_plainColorPage->setColor(*m_editedStyle, getColorParam());
		m_settingsPage->setStyle(m_editedStyle);
	}
}

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

void StyleEditor::onParamStyleChanged(bool isDragging)
{
	TPalette *palette = getPalette();
	if (!palette)
		return;

	int styleIndex = getStyleIndex();
	if (styleIndex < 0 || styleIndex > palette->getStyleCount())
		return;

	if (m_autoButton->isChecked())
		copyEditedStyleToPalette(isDragging);

	m_editedStyle->invalidateIcon();	  // Refresh the new color icon
	m_newColor->setStyle(*m_editedStyle); //
}