#include "drawtools.h"

#include "alignedtextitem.h"
#include "ui_drawtools.h"

#include <QClipboard>
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QGraphicsLineItem>
#include <QImageReader>
#include <QLabel>
#include <QLineEdit>
#include <QMouseEvent>


_DTSizeItem::_DTSizeItem(): QGraphicsObject() {
	cur_item   = nullptr;
	grid       = 10.;
	in_process = can_drag = false;
	setData(bvidItemSelection, true);
	for (int i = 0; i < 8; ++i) {
		// qDebug() << &(rects[i]);
		rects[i].setData(bvidItemSelection, true);
		rects[i].setData(bvidDTHandle, true);
		rects[i].setFlag(QGraphicsItem::ItemIgnoresTransformations);
		rects[i].setZValue(10.);
		rects[i].setAcceptHoverEvents(true);
		rects[i].setRect(-5, -5, 10, 10);
		rects[i].setPen(QPen(Qt::darkBlue));
		rects[i].setBrush(QBrush(QColor(64, 64, 255, 128)));
	}
}


_DTSizeItem::~_DTSizeItem() {
	assignObject(nullptr);
	// qDebug() << "!!!";
}


void _DTSizeItem::assignObject(QGraphicsItem * item) {
	if (cur_item) {
		cur_item->removeSceneEventFilter(this);
	}
	cur_item = item;
	if (!cur_item) {
		for (int i = 0; i < 8; ++i) {
			rects[i].hide();
			rects[i].setParentItem(nullptr);
			rects[i].removeSceneEventFilter(this);
		}
		hide();
		return;
	}
	if (cur_item->scene()) {
		if (!cur_item->scene()->views().isEmpty()) {
			grid = qobject_cast<BlockView *>(cur_item->scene()->views()[0])->gridStep();
		}
	}
	QGraphicsRectItem * irect   = qgraphicsitem_cast<QGraphicsRectItem *>(cur_item);
	QGraphicsEllipseItem * iell = qgraphicsitem_cast<QGraphicsEllipseItem *>(cur_item);
	QGraphicsLineItem * iline   = qgraphicsitem_cast<QGraphicsLineItem *>(cur_item);
	if (irect || iell || iline) {
		resizeHandles();
		is_line = qgraphicsitem_cast<QGraphicsLineItem *>(cur_item);
		for (int i = 0; i < (is_line ? 2 : 8); ++i) {
			rects[i].setParentItem(cur_item);
			rects[i].installSceneEventFilter(this);
			rects[i].show();
		}
		show();
	}
	cur_item->installSceneEventFilter(this);
	moveRects();
}


void _DTSizeItem::moveRects() {
	if (!cur_item) return;
	QRectF rect = itemRect(cur_item);
	QPointF tl = rect.topLeft(), tr = rect.topRight(), bl = rect.bottomLeft(), br = rect.bottomRight();
	if (is_line) {
		rects[0].setPos(tl);
		rects[0].setData(2001, int(Qt::SizeAllCursor));
		rects[1].setPos(br);
		rects[1].setData(2001, int(Qt::SizeAllCursor));
	} else {
		rects[0].setPos(tl);
		rects[0].setData(2001, int(Qt::SizeFDiagCursor));
		rects[1].setPos((tl + tr) / 2.);
		rects[1].setData(2001, int(Qt::SizeVerCursor));
		rects[2].setPos(tr);
		rects[2].setData(2001, int(Qt::SizeBDiagCursor));
		rects[3].setPos((tr + br) / 2.);
		rects[3].setData(2001, int(Qt::SizeHorCursor));
		rects[4].setPos(br);
		rects[4].setData(2001, int(Qt::SizeFDiagCursor));
		rects[5].setPos((br + bl) / 2.);
		rects[5].setData(2001, int(Qt::SizeVerCursor));
		rects[6].setPos(bl);
		rects[6].setData(2001, int(Qt::SizeBDiagCursor));
		rects[7].setPos((bl + tl) / 2.);
		rects[7].setData(2001, int(Qt::SizeHorCursor));
	}
}


void _DTSizeItem::applyRect() {
	if (!cur_item) return;
	QGraphicsRectItem * irect   = qgraphicsitem_cast<QGraphicsRectItem *>(cur_item);
	QGraphicsEllipseItem * iell = qgraphicsitem_cast<QGraphicsEllipseItem *>(cur_item);
	QGraphicsLineItem * iline   = qgraphicsitem_cast<QGraphicsLineItem *>(cur_item);
	if (irect) irect->setRect(nrect);
	if (iell) iell->setRect(nrect);
	if (iline) iline->setLine(QLineF(nrect.topLeft(), nrect.bottomRight()));
}


void _DTSizeItem::doubleClick() {
	QGraphicsSimpleTextItem * itext = qgraphicsitem_cast<QGraphicsSimpleTextItem *>(cur_item);
	AlignedTextItem * iatext        = qgraphicsitem_cast<AlignedTextItem *>(cur_item);
	QGraphicsPixmapItem * ipixmap   = qgraphicsitem_cast<QGraphicsPixmapItem *>(cur_item);
	if (itext || iatext) {
		QMetaObject::invokeMethod(
			this,
			[this]() { textEditRequest(); },
			Qt::QueuedConnection);
	}
	if (ipixmap) {
		QMetaObject::invokeMethod(
			this,
			[this]() { pixmapEditRequest(); },
			Qt::QueuedConnection);
	}
}


void _DTSizeItem::resizeHandles() {
	double sz = fontHeight() / 3.;
	QRectF r(-sz, -sz, sz * 2, sz * 2);
	for (int i = 0; i < 8; ++i) {
		rects[i].setRect(r);
	}
}


QRectF _DTSizeItem::itemRect(const QGraphicsItem *) const {
	if (!cur_item) return QRectF();
	QGraphicsRectItem * irect   = qgraphicsitem_cast<QGraphicsRectItem *>(cur_item);
	QGraphicsEllipseItem * iell = qgraphicsitem_cast<QGraphicsEllipseItem *>(cur_item);
	QGraphicsLineItem * iline   = qgraphicsitem_cast<QGraphicsLineItem *>(cur_item);
	if (irect) return irect->rect();
	if (iell) return iell->rect();
	if (iline) return QRectF(iline->line().p1(), iline->line().p2());
	return QRectF();
}


QRectF _DTSizeItem::boundingRect() const {
	QRectF ret = rects[0].boundingRect().translated(rects[0].pos());
	for (int i = 1; i < 8; ++i) {
		ret |= rects[i].boundingRect().translated(rects[i].pos());
	}
	return ret;
}


bool _DTSizeItem::sceneEventFilter(QGraphicsItem * watched, QEvent * event) {
	QGraphicsSceneMouseEvent * me = (QGraphicsSceneMouseEvent *)event;
	if (watched == cur_item) {
		if (event->type() == QEvent::Close) {
			assignObject(nullptr);
			return true;
		}
		if (event->type() == QEvent::GraphicsSceneMouseDoubleClick) {
			doubleClick();
			return true;
		}
		return QGraphicsItem::sceneEventFilter(watched, event);
	}
	if (!cur_item) {
		return QGraphicsItem::sceneEventFilter(watched, event);
	}
	view_ = nullptr;
	switch (event->type()) {
	case QEvent::GraphicsSceneHoverEnter:
		if (watched->scene())
			if (!watched->scene()->views().isEmpty()) view_ = watched->scene()->views()[0];
		if (view_) view_->setCursor(Qt::CursorShape(watched->data(2001).toInt()));
		break;
	case QEvent::GraphicsSceneHoverLeave:
		if (watched->scene())
			if (!watched->scene()->views().isEmpty()) view_ = watched->scene()->views()[0];
		if (view_) view_->unsetCursor();
		break;
	case QEvent::GraphicsSceneMousePress:
		can_drag = (me->buttons() == Qt::LeftButton);
		if (in_process) {
			nrect = cur_item->data(2000).toRectF();
			applyRect();
			moveRects();
		}
		in_process = false;
		pp         = quantize(me->scenePos(), grid);
		cur_item->setData(2000, itemRect(cur_item));
		return true;
	case QEvent::GraphicsSceneMouseMove:
		if (me->buttons().testFlag(Qt::LeftButton)) {
			sp = quantize(me->scenePos(), grid);
			if (pp != sp && can_drag) {
				in_process = true;
				nrect      = itemRect(cur_item);
				if (is_line) {
					if (watched == &(rects[0])) nrect.setTopLeft(rects[0].pos() + (sp - pp));
					if (watched == &(rects[1])) nrect.setBottomRight(rects[1].pos() + (sp - pp));
				} else {
					if (watched == &(rects[0])) nrect.setTopLeft(rects[0].pos() + (sp - pp));
					if (watched == &(rects[1])) nrect.setTop(rects[1].pos().y() + (sp - pp).y());
					if (watched == &(rects[2])) nrect.setTopRight(rects[2].pos() + (sp - pp));
					if (watched == &(rects[3])) nrect.setRight(rects[3].pos().x() + (sp - pp).x());
					if (watched == &(rects[4])) nrect.setBottomRight(rects[4].pos() + (sp - pp));
					if (watched == &(rects[5])) nrect.setBottom(rects[5].pos().y() + (sp - pp).y());
					if (watched == &(rects[6])) nrect.setBottomLeft(rects[6].pos() + (sp - pp));
					if (watched == &(rects[7])) nrect.setLeft(rects[7].pos().x() + (sp - pp).x());
					nrect = nrect.normalized();
				}
				pp = sp;
				applyRect();
				moveRects();
			}
		}
		return true;
	case QEvent::GraphicsSceneMouseRelease:
		if (in_process) emit sizeChanged();
		in_process = false;
		can_drag   = false;
		return true;
	default: break;
	}
	return QGraphicsItem::sceneEventFilter(watched, event);
}


DrawTools::DrawTools(BlockView * parent)
	: QWidget(parent)
	, actions_Z_up(this)
	, actions_Z_top(this)
	, actions_Z_down(this)
	, actions_Z_bottom(this) {
	widget_props = new QWidget();
	ui           = new Ui::DrawTools();
	ui->setupUi(widget_props);
	ui->labelPen->setIconSizeAutoScale(1.5);
	ui->labelBrush->setIconSizeAutoScale(1.5);
	widget_props->setEnabled(false);
	int fh    = qMax<int>(fontHeight(this), 22);
	int thick = lineThickness(this);
	QSize sz(fh * 2.5, fh);
	ui->comboLineStyle->setIconSize(sz);
	for (int i = 0; i < 6; ++i) {
		QPixmap pix(sz);
		pix.fill();
		QPainter p(&pix);
		p.setPen(QPen(Qt::black, thick, (Qt::PenStyle)i));
		p.drawLine(0, pix.height() / 2, pix.width(), pix.height() / 2);
		p.end();
		ui->comboLineStyle->addItem(QIcon(pix), "");
	}
#ifdef Q_OS_MACOS
	setAlignCompact(true);
#else
	setAlignCompact(false);
#endif
	menu_hor.addActions(QList<QAction *>() << ui->actionLeft << ui->actionHCenter << ui->actionRight);
	menu_ver.addActions(QList<QAction *>() << ui->actionTop << ui->actionVCenter << ui->actionBottom);
	ui->buttonAlignHor->setMenu(&menu_hor);
	ui->buttonAlignVer->setMenu(&menu_ver);
	new_type = -1;
	new_item = cur_item = nullptr;
	view_               = nullptr;
	resize_enabled      = true;
	text_dlg.setLayout(new QBoxLayout(QBoxLayout::TopToBottom));
	QDialogButtonBox * bbox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
	connect(bbox, SIGNAL(accepted()), &text_dlg, SLOT(accept()));
	connect(bbox, SIGNAL(rejected()), &text_dlg, SLOT(reject()));
	text_dlg.layout()->addWidget(&text_edit);
	text_dlg.layout()->addWidget(bbox);
	actions_Z_up.setIcon(QIcon(":/icons/z-up.png"));
	actions_Z_up.setEnabled(false);
	actions_Z_top.setIcon(QIcon(":/icons/z-top.png"));
	actions_Z_top.setEnabled(false);
	actions_Z_down.setIcon(QIcon(":/icons/z-down.png"));
	actions_Z_down.setEnabled(false);
	actions_Z_bottom.setIcon(QIcon(":/icons/z-bottom.png"));
	actions_Z_bottom.setEnabled(false);
	actions_add << newAction(QIcon(":/icons/draw-rectangle.png"), 1) << newAction(QIcon(":/icons/draw-ellipse.png"), 2)
				<< newAction(QIcon(":/icons/draw-line.png"), 4) << newAction(QIcon(":/icons/draw-text.png"), 0)
				<< newAction(QIcon(":/icons/view-preview.png"), 3);
	buttons_align << ui->buttonAlignTL << ui->buttonAlignTC << ui->buttonAlignTR << ui->buttonAlignCL << ui->buttonAlignCC
				  << ui->buttonAlignCR << ui->buttonAlignBL << ui->buttonAlignBC << ui->buttonAlignBR;
	foreach(QAction * a, actions_add) {
		connect(a, SIGNAL(toggled(bool)), this, SLOT(toggleNewItem(bool)));
	}
	foreach(QToolButton * b, buttons_align) {
		connect(b, SIGNAL(clicked(bool)), this, SLOT(alignClicked()));
	}
	connect(ui->buttonImage, SIGNAL(clicked(bool)), this, SLOT(buttonImage_clicked()));
	connect(ui->buttonImagePaste, SIGNAL(clicked(bool)), this, SLOT(buttonImagePaste_clicked()));
	connect(ui->buttonFont, SIGNAL(clicked(bool)), this, SLOT(buttonFont_clicked()));
	connect(ui->buttonTextEdit, SIGNAL(clicked(bool)), this, SLOT(buttonTextEdit_clicked()));
	connect(ui->spinWidth, SIGNAL(valueChanged(double)), this, SLOT(propertyChanged()));
	connect(ui->spinWidth, SIGNAL(editingFinished()), this, SLOT(changeFinished()));
	connect(ui->spinHeight, SIGNAL(valueChanged(double)), this, SLOT(propertyChanged()));
	connect(ui->spinHeight, SIGNAL(editingFinished()), this, SLOT(changeFinished()));
	connect(ui->spinThick, SIGNAL(valueChanged(double)), this, SLOT(propertyChanged()));
	connect(ui->spinThick, SIGNAL(editingFinished()), this, SLOT(changeFinished()));
	connect(ui->spinScale, SIGNAL(valueChanged(double)), this, SLOT(propertyChanged()));
	connect(ui->spinScale, SIGNAL(editingFinished()), this, SLOT(changeFinished()));
	connect(ui->comboText, SIGNAL(editTextChanged(QString)), this, SLOT(propertyChanged()));
	connect(ui->comboText->lineEdit(), SIGNAL(editingFinished()), this, SLOT(changeFinished()));
	connect(ui->comboLineStyle, SIGNAL(currentIndexChanged(int)), this, SLOT(comboLineStyleChanged()));
	connect(ui->colorButtonPen, SIGNAL(colorChanged(QColor)), this, SLOT(propertyChanged()));
	connect(ui->colorButtonPen, SIGNAL(colorChanged(QColor)), this, SLOT(changeFinished()));
	connect(ui->colorButtonBrush, SIGNAL(colorChanged(QColor)), this, SLOT(propertyChanged()));
	connect(ui->colorButtonBrush, SIGNAL(colorChanged(QColor)), this, SLOT(changeFinished()));
	connect(ui->actionTop, SIGNAL(triggered(bool)), this, SLOT(actionTop_triggered(bool)));
	connect(ui->actionVCenter, SIGNAL(triggered(bool)), this, SLOT(actionVCenter_triggered(bool)));
	connect(ui->actionBottom, SIGNAL(triggered(bool)), this, SLOT(actionBottom_triggered(bool)));
	connect(ui->actionLeft, SIGNAL(triggered(bool)), this, SLOT(actionLeft_triggered(bool)));
	connect(ui->actionHCenter, SIGNAL(triggered(bool)), this, SLOT(actionHCenter_triggered(bool)));
	connect(ui->actionRight, SIGNAL(triggered(bool)), this, SLOT(actionRight_triggered(bool)));
	connect(ui->groupShowLogic, SIGNAL(toggled(bool)), this, SLOT(decorVisibleLogicChanged()));
	connect(ui->checkVLEnabled, SIGNAL(toggled(bool)), this, SLOT(decorVisibleLogicChanged()));
	connect(ui->checkVLHovered, SIGNAL(toggled(bool)), this, SLOT(decorVisibleLogicChanged()));
	connect(ui->checkVLSelected, SIGNAL(toggled(bool)), this, SLOT(decorVisibleLogicChanged()));
	connect(ui->checkVLInverse, SIGNAL(toggled(bool)), this, SLOT(decorVisibleLogicChanged()));
	connect(&font_dlg, SIGNAL(currentFontChanged(QFont)), this, SLOT(propertyChanged()));
	connect(&size_item, SIGNAL(sizeChanged()), this, SLOT(sizeChanged()));
	connect(&size_item, SIGNAL(textEditRequest()), this, SLOT(buttonTextEdit_clicked()));
	connect(&size_item, SIGNAL(pixmapEditRequest()), this, SLOT(buttonImage_clicked()));
	connect(&actions_Z_up, SIGNAL(triggered(bool)), this, SLOT(actionZ_triggered()));
	connect(&actions_Z_top, SIGNAL(triggered(bool)), this, SLOT(actionZ_triggered()));
	connect(&actions_Z_down, SIGNAL(triggered(bool)), this, SLOT(actionZ_triggered()));
	connect(&actions_Z_bottom, SIGNAL(triggered(bool)), this, SLOT(actionZ_triggered()));
	setBlockView(parent);
	retranslate();
}


DrawTools::~DrawTools() {
	size_item.assignObject(nullptr);
}


void DrawTools::retranslate() {
	QStringList styles;
	styles << tr("NoPen") << tr("Solid") << tr("Dash") << tr("Dot") << tr("Dash-Dot") << tr("Dash-Dot-Dot");
	for (int i = 0; i < styles.size(); i++) {
		ui->comboLineStyle->setItemText(i, styles[i]);
	}
	text_dlg.setWindowTitle(tr("Edit text"));
	actions_Z_up.setText(tr("Bring\nforward"));
	actions_Z_top.setText(tr("Bring\nto front"));
	actions_Z_down.setText(tr("Send\nbackward"));
	actions_Z_bottom.setText(tr("Send\nto back"));
	actions_add[0]->setText(tr("Draw\nRectangle"));
	actions_add[1]->setText(tr("Draw\nEllipse"));
	actions_add[2]->setText(tr("Draw\nLine"));
	actions_add[3]->setText(tr("Draw\nText"));
	actions_add[4]->setText(tr("Draw\nImage"));
}


void DrawTools::setBlockView(BlockView * v) {
	if (view_) view_->viewport()->removeEventFilter(this);
	disconnect(this, SLOT(selectionChanged()));
	view_ = v;
	if (!view_) return;
	view_->addItem(&size_item);
	view_->viewport()->installEventFilter(this);
	connect(view_->scene(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
}


void DrawTools::setAlignCompact(bool yes) {
	ui->widgetAlign2->setVisible(yes);
	ui->widgetAlign9->setVisible(!yes);
}


bool DrawTools::eventFilter(QObject * o, QEvent * e) {
	QMouseEvent * me = (QMouseEvent *)e;
	QPointF sp;
	if (e->type() == QEvent::FontChange || e->type() == QEvent::Polish) {
		ui->labelPen->setMinimumSize(preferredIconSize(1.5, widget_props));
	}
	if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseMove) {
		sp = quantize(view_->mapToScene(me->pos()), view_->gridStep());
	}
	QRectF mr;
	switch (e->type()) {
	case QEvent::MouseButtonPress:
		if (new_type < 0) break;
		if (new_item) {
			delete new_item;
			new_item = nullptr;
			if (!me->modifiers().testFlag(Qt::ControlModifier)) {
				foreach(QAction * a, actions_add) {
					a->setChecked(false);
				}
				new_type = -1;
				return true;
			}
		}
		new_item = nullptr;
		pp       = sp;
		switch (new_type) {
		case 0:
			new_item = new AlignedTextItem();
			qgraphicsitem_cast<AlignedTextItem *>(new_item)->setText("Text");
			qgraphicsitem_cast<AlignedTextItem *>(new_item)->setPos(sp);
			break;
		case 1: new_item = new QGraphicsRectItem(); break;
		case 2: new_item = new QGraphicsEllipseItem(); break;
		case 3:
			new_item = new QGraphicsPixmapItem(QPixmap(":/icons/view-preview.png"));
			qgraphicsitem_cast<QGraphicsPixmapItem *>(new_item)->setPos(
				sp - QPointF(new_item->boundingRect().width() / 2, new_item->boundingRect().height() / 2));
			break;
		case 4: new_item = new QGraphicsLineItem(QLineF(sp, sp)); break;
		};
		if (new_item) {
			if (new_type == 1 || new_type == 2) {
				qgraphicsitem_cast<QAbstractGraphicsShapeItem *>(new_item)->setBrush(Qt::white);
			}
			new_item->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable);
			new_item->setData(bvidBlockDecor, true);
			emit itemCreated(new_item);
			return true;
		}
		break;
	case QEvent::MouseMove:
		if (me->buttons().testFlag(Qt::LeftButton)) {
			if (new_item) {
				mr = new_item->mapRectFromScene(QRectF(pp, sp).normalized());
				switch (new_type) {
				case 0: qgraphicsitem_cast<AlignedTextItem *>(new_item)->setPos(sp); break;
				case 1: qgraphicsitem_cast<QGraphicsRectItem *>(new_item)->setRect(mr); break;
				case 2: qgraphicsitem_cast<QGraphicsEllipseItem *>(new_item)->setRect(mr); break;
				case 3:
					qgraphicsitem_cast<QGraphicsPixmapItem *>(new_item)->setPos(
						sp - QPointF(new_item->boundingRect().width() / 2, new_item->boundingRect().height() / 2));
					break;
				case 4: qgraphicsitem_cast<QGraphicsLineItem *>(new_item)->setLine(QLineF(pp, sp)); break;
				};
				return true;
			}
		}
		break;
	case QEvent::MouseButtonRelease:
		if (new_item) {
			if (new_item->boundingRect().isEmpty()) {
				delete new_item;
			} else {
				emit itemAddConfirm(new_item);
				if (view_) {
					view_->selectNone();
					new_item->setSelected(true);
				}
			}
			new_item = nullptr;
			if (!me->modifiers().testFlag(Qt::ControlModifier)) {
				foreach(QAction * a, actions_add) {
					a->setChecked(false);
				}
				new_type = -1;
			}
			return true;
		}
		break;
	default: break;
	}
	return QObject::eventFilter(o, e);
}


void DrawTools::changeEvent(QEvent * e) {
	QWidget::changeEvent(e);
	switch (e->type()) {
	case QEvent::LanguageChange:
		ui->retranslateUi(this);
		retranslate();
		break;
	default: break;
	}
}


QComboBox * DrawTools::textEditCombo() const {
	return ui->comboText;
}


QAction * DrawTools::newAction(const QIcon & icon, int type) {
	QAction * ret = new QAction(icon, QString(), this);
	ret->setCheckable(true);
	ret->setData(type);
	return ret;
}


void DrawTools::toggleNewItem(bool on) {
	QAction * sa = (QAction *)sender();
	foreach(QAction * a, actions_add) {
		if (a != sa) a->setChecked(false);
	}
	if (!on) {
		new_type = -1;
		view_->unsetCursor();
		return;
	}
	new_type = sa->data().toInt();
	view_->setCursor(Qt::CrossCursor);
}


void DrawTools::alignClicked() {
	QToolButton * sb = (QToolButton *)sender();
	foreach(QToolButton * b, buttons_align) {
		if (b != sb) b->setChecked(false);
	}
	sb->setChecked(true);
	align       = Qt::Alignment();
	QString als = sb->objectName().right(2).toLower();
	if (als[0] == 't') align |= Qt::AlignTop;
	if (als[0] == 'c') align |= Qt::AlignVCenter;
	if (als[0] == 'b') align |= Qt::AlignBottom;
	if (als[1] == 'l') align |= Qt::AlignLeft;
	if (als[1] == 'c') align |= Qt::AlignHCenter;
	if (als[1] == 'r') align |= Qt::AlignRight;
	propertyChanged();
}


void DrawTools::setToolButtonsEnabled(bool pen, bool brush, bool wid_hei) {
	ui->labelPen->setEnabled(pen);
	ui->colorButtonPen->setEnabled(pen);
	ui->labelBrush->setEnabled(brush);
	ui->colorButtonBrush->setEnabled(brush);
	ui->spinWidth->setEnabled(wid_hei);
	ui->spinHeight->setEnabled(wid_hei);
	ui->labelWidth->setEnabled(wid_hei);
	ui->labelHeight->setEnabled(wid_hei);
	ui->labelPen->setVisible(pen);
	ui->colorButtonPen->setVisible(pen);
	ui->labelBrush->setVisible(brush);
	ui->colorButtonBrush->setVisible(brush);
	ui->spinWidth->setVisible(wid_hei);
	ui->spinHeight->setVisible(wid_hei);
	ui->labelWidth->setVisible(wid_hei);
	ui->labelHeight->setVisible(wid_hei);
}


void DrawTools::blockPropSignals(bool block_) {
	ui->spinWidth->blockSignals(block_);
	ui->spinHeight->blockSignals(block_);
	ui->spinThick->blockSignals(block_);
	ui->comboText->blockSignals(block_);
	ui->comboLineStyle->blockSignals(block_);
	ui->colorButtonPen->blockSignals(block_);
	ui->colorButtonBrush->blockSignals(block_);
	ui->actionTop->blockSignals(block_);
	ui->actionVCenter->blockSignals(block_);
	ui->actionBottom->blockSignals(block_);
	ui->actionHCenter->blockSignals(block_);
	ui->actionLeft->blockSignals(block_);
	ui->actionRight->blockSignals(block_);
	for (auto * b: buttons_align)
		b->blockSignals(block_);
	ui->groupShowLogic->blockSignals(block_);
	ui->checkVLEnabled->blockSignals(block_);
	ui->checkVLHovered->blockSignals(block_);
	ui->checkVLSelected->blockSignals(block_);
	ui->checkVLInverse->blockSignals(block_);
}


void DrawTools::actionAlignTrigger(bool vert, Qt::AlignmentFlag value) {
	blockPropSignals(true);
	if (vert)
		foreach(QAction * a, menu_ver.actions())
			a->setChecked(false);
	else
		foreach(QAction * a, menu_hor.actions())
			a->setChecked(false);
	align = align & (vert ? Qt::AlignHorizontal_Mask : Qt::AlignVertical_Mask);
	align |= value;
	qobject_cast<QAction *>(sender())->setChecked(true);
	blockPropSignals(false);
	propertyChanged();
}


void DrawTools::emitZAvailabe(QGraphicsItem * item) {
	BlockView * view = nullptr;
	if (item)
		if (item->scene())
			if (!item->scene()->views().isEmpty()) view = qobject_cast<BlockView *>(item->scene()->views()[0]);
	if (!view) {
		moveZUpAvailable(false);
		moveZDownAvailable(false);
		return;
	}
	QList<QGraphicsItem *> dl;
	if (!item->parentItem()) {
		dl = view->decors();
	} else {
		if (item->parentItem()->data(bvidType).toInt() == bvitBlock) {
			dl = qgraphicsitem_cast<BlockItem *>(item->parentItem())->decors_;
		}
	}
	if (dl.size() <= 1) {
		moveZUpAvailable(false);
		moveZDownAvailable(false);
		return;
	}
	int ind = dl.indexOf(item);
	if (ind < 0) {
		moveZUpAvailable(false);
		moveZDownAvailable(false);
	} else {
		moveZUpAvailable(ind < dl.size() - 1);
		moveZDownAvailable(ind > 0);
	}
}


void DrawTools::selectionChanged() {
	cur_item = nullptr;
	size_item.assignObject(nullptr);
	if (!view_) {
		emitZAvailabe();
		return;
	}
	QList<QGraphicsItem *> sil = view_->scene()->selectedItems();
	if (sil.size() != 1) {
		emitZAvailabe();
		widget_props->setEnabled(false);
		return;
	}
	widget_props->setEnabled(true);
	if (!sil.isEmpty()) cur_item = sil[0];
	if (!cur_item) {
		ui->groupShowLogic->setEnabled(false);
		emitZAvailabe();
		return;
	}
	QGraphicsSimpleTextItem * itext = qgraphicsitem_cast<QGraphicsSimpleTextItem *>(cur_item);
	AlignedTextItem * iatext        = qgraphicsitem_cast<AlignedTextItem *>(cur_item);
	QGraphicsPixmapItem * ipixmap   = qgraphicsitem_cast<QGraphicsPixmapItem *>(cur_item);
	QGraphicsRectItem * irect       = qgraphicsitem_cast<QGraphicsRectItem *>(cur_item);
	QGraphicsEllipseItem * iell     = qgraphicsitem_cast<QGraphicsEllipseItem *>(cur_item);
	QGraphicsLineItem * iline       = qgraphicsitem_cast<QGraphicsLineItem *>(cur_item);
	bool is_decor                   = false;
	blockPropSignals(true);
	if (itext) {
		is_decor = true;
		ui->stackedProperties->setCurrentIndex(0);
		ui->comboText->setEditText(itext->text());
		ui->colorButtonPen->setColor(itext->brush().color());
		font_dlg.blockSignals(true);
		font_dlg.setCurrentFont(itext->font());
		font_dlg.blockSignals(false);
		setToolButtonsEnabled(true, false, false);
		ui->widgetAlign2->setEnabled(false);
		ui->widgetAlign9->setEnabled(false);
		size_item.assignObject(itext);
	} else if (iatext) {
		is_decor = true;
		ui->stackedProperties->setCurrentIndex(0);
		ui->comboText->setEditText(iatext->text());
		ui->colorButtonPen->setColor(iatext->brush().color());
		font_dlg.blockSignals(true);
		font_dlg.setCurrentFont(iatext->font());
		font_dlg.blockSignals(false);
		setToolButtonsEnabled(true, false, false);
		foreach(QAction * a, menu_hor.actions())
			a->setChecked(false);
		foreach(QAction * a, menu_ver.actions())
			a->setChecked(false);
		align = iatext->alignment();
		QString als;
		if (align.testFlag(Qt::AlignTop)) {
			als += "T";
			ui->actionTop->setChecked(true);
		}
		if (align.testFlag(Qt::AlignVCenter)) {
			als += "C";
			ui->actionVCenter->setChecked(true);
		}
		if (align.testFlag(Qt::AlignBottom)) {
			als += "B";
			ui->actionBottom->setChecked(true);
		}
		if (align.testFlag(Qt::AlignLeft)) {
			als += "L";
			ui->actionLeft->setChecked(true);
		}
		if (align.testFlag(Qt::AlignHCenter)) {
			als += "C";
			ui->actionHCenter->setChecked(true);
		}
		if (align.testFlag(Qt::AlignRight)) {
			als += "R";
			ui->actionRight->setChecked(true);
		}
		foreach(QToolButton * b, buttons_align) {
			b->setChecked(false);
		}
		foreach(QToolButton * b, buttons_align) {
			if (b->objectName().endsWith(als)) {
				b->setChecked(true);
				break;
			}
		}
		ui->widgetAlign2->setEnabled(true);
		ui->widgetAlign9->setEnabled(true);
		size_item.assignObject(iatext);
	} else if (ipixmap) {
		is_decor = true;
		ui->stackedProperties->setCurrentIndex(2);
		ui->spinScale->setValue(sqrt(ipixmap->transform().determinant()));
		setToolButtonsEnabled(false, false, false);
		size_item.assignObject(ipixmap);
	} else if (irect || iell) {
		is_decor = true;
		ui->stackedProperties->setCurrentIndex(1);
		QAbstractGraphicsShapeItem * ishape = nullptr;
		if (irect) {
			ishape = irect;
			ui->spinWidth->setValue(irect->rect().width());
			ui->spinHeight->setValue(irect->rect().height());
		}
		if (iell) {
			ishape = iell;
			ui->spinWidth->setValue(iell->rect().width());
			ui->spinHeight->setValue(iell->rect().height());
		}
		if (ishape) {
			ui->colorButtonPen->setColor(ishape->pen().color());
			ui->colorButtonBrush->setColor(ishape->brush().color());
			ui->spinThick->setValue(ishape->pen().widthF());
			ui->comboLineStyle->setCurrentIndex(qMin<int>((int)ishape->pen().style(), ui->comboLineStyle->count() - 1));
			setToolButtonsEnabled(true, true, true);
			if (resize_enabled) size_item.assignObject(ishape);
		}
	} else if (iline) {
		is_decor = true;
		ui->stackedProperties->setCurrentIndex(1);
		ui->colorButtonPen->setColor(iline->pen().color());
		ui->spinThick->setValue(iline->pen().widthF());
		ui->comboLineStyle->setCurrentIndex(qMin<int>((int)iline->pen().style(), ui->comboLineStyle->count() - 1));
		setToolButtonsEnabled(true, false, false);
		if (resize_enabled) size_item.assignObject(iline);
	} else {
		ui->stackedProperties->setCurrentIndex(3);
		widget_props->setEnabled(false);
	}
	ui->groupShowLogic->setEnabled(is_decor);
	if (is_decor) {
		BlockviewDecorShowLogics slf(cur_item->data(bvidDecorShowLogic).toUInt());
		ui->groupShowLogic->setChecked(slf != bvdslAlways);
		ui->checkVLEnabled->setChecked(slf.testFlag(bvdslEnabled));
		ui->checkVLHovered->setChecked(slf.testFlag(bvdslHovered));
		ui->checkVLSelected->setChecked(slf.testFlag(bvdslSelected));
		ui->checkVLInverse->setChecked(slf.testFlag(bvdslInverse));
	}
	emitZAvailabe(cur_item);
	blockPropSignals(false);
}


void DrawTools::sizeChanged() {
	blockPropSignals(true);
	QGraphicsRectItem * irect   = qgraphicsitem_cast<QGraphicsRectItem *>(cur_item);
	QGraphicsEllipseItem * iell = qgraphicsitem_cast<QGraphicsEllipseItem *>(cur_item);
	if (irect || iell) {
		if (irect) {
			ui->spinWidth->setValue(irect->rect().width());
			ui->spinHeight->setValue(irect->rect().height());
		}
		if (iell) {
			ui->spinWidth->setValue(iell->rect().width());
			ui->spinHeight->setValue(iell->rect().height());
		}
	}
	blockPropSignals(false);
	changeFinished();
}


void DrawTools::propertyChanged() {
	if (!cur_item) return;
	QGraphicsSimpleTextItem * itext = qgraphicsitem_cast<QGraphicsSimpleTextItem *>(cur_item);
	AlignedTextItem * iatext        = qgraphicsitem_cast<AlignedTextItem *>(cur_item);
	QGraphicsPixmapItem * ipixmap   = qgraphicsitem_cast<QGraphicsPixmapItem *>(cur_item);
	QGraphicsRectItem * irect       = qgraphicsitem_cast<QGraphicsRectItem *>(cur_item);
	QGraphicsEllipseItem * iell     = qgraphicsitem_cast<QGraphicsEllipseItem *>(cur_item);
	QGraphicsLineItem * iline       = qgraphicsitem_cast<QGraphicsLineItem *>(cur_item);
	if (itext) {
		QRectF obr = itext->boundingRect();
		itext->setFont(font_dlg.currentFont());
		itext->setText(ui->comboText->currentText());
		QRectF nbr = itext->boundingRect();
		QSizeF ds  = (obr.size() - nbr.size()) / 2.;
		itext->setPos(itext->pos() + QPointF(ds.width(), ds.height()));
		itext->setBrush(ui->colorButtonPen->color());
	} else if (iatext) {
		iatext->setFont(font_dlg.currentFont());
		iatext->setText(ui->comboText->currentText());
		iatext->setBrush(ui->colorButtonPen->color());
		iatext->setAlignment(align);
	} else if (ipixmap) {
		QTransform t = ipixmap->transform();
		double det   = sqrt(t.determinant());
		QSizeF os    = ipixmap->boundingRect().size() * det;
		if (det != 0.) t.scale(1. / det, 1. / det);
		det = ui->spinScale->value();
		t.scale(det, det);
		ipixmap->setTransform(t);
		QSizeF ns = ipixmap->boundingRect().size() * det;
		QSizeF ds = (os - ns) / 2.;
		ipixmap->setPos(ipixmap->pos() + QPointF(ds.width(), ds.height()));
	} else if (irect || iell) {
		QAbstractGraphicsShapeItem * ishape = nullptr;
		if (irect) {
			ishape = irect;
			irect->setRect(QRectF(irect->rect().topLeft(), QSizeF(ui->spinWidth->value(), ui->spinHeight->value())));
		}
		if (iell) {
			ishape = iell;
			iell->setRect(QRectF(iell->rect().topLeft(), QSizeF(ui->spinWidth->value(), ui->spinHeight->value())));
		}
		if (ishape) {
			ishape->setPen(QPen(ui->colorButtonPen->color(), ui->spinThick->value(), (Qt::PenStyle)ui->comboLineStyle->currentIndex()));
			ishape->setBrush(ui->colorButtonBrush->color());
			if (resize_enabled) size_item.assignObject(ishape);
		}
	} else if (iline) {
		iline->setPen(QPen(ui->colorButtonPen->color(), ui->spinThick->value(), (Qt::PenStyle)ui->comboLineStyle->currentIndex()));
		if (resize_enabled) size_item.assignObject(iline);
	}
}


void DrawTools::comboLineStyleChanged() {
	if (!cur_item) return;
	QGraphicsRectItem * irect   = qgraphicsitem_cast<QGraphicsRectItem *>(cur_item);
	QGraphicsEllipseItem * iell = qgraphicsitem_cast<QGraphicsEllipseItem *>(cur_item);
	QGraphicsLineItem * iline   = qgraphicsitem_cast<QGraphicsLineItem *>(cur_item);
	if (irect || iell) {
		QAbstractGraphicsShapeItem * ishape = nullptr;
		if (irect) ishape = irect;
		if (iell) ishape = iell;
		if (ishape) {
			QPen p(ishape->pen());
			p.setStyle((Qt::PenStyle)ui->comboLineStyle->currentIndex());
			ishape->setPen(p);
			changeFinished();
		}
	} else if (iline) {
		QPen p(iline->pen());
		p.setStyle((Qt::PenStyle)ui->comboLineStyle->currentIndex());
		iline->setPen(p);
		changeFinished();
	}
}


void DrawTools::decorVisibleLogicChanged() {
	if (!cur_item) return;
	uint f = 0;
	if (ui->groupShowLogic->isChecked()) {
		if (ui->checkVLEnabled->isChecked()) f |= bvdslEnabled;
		if (ui->checkVLHovered->isChecked()) f |= bvdslHovered;
		if (ui->checkVLSelected->isChecked()) f |= bvdslSelected;
		if (ui->checkVLInverse->isChecked()) f |= bvdslInverse;
	}
	cur_item->setData(bvidDecorShowLogic, f);
}


void DrawTools::buttonImage_clicked() {
	QGraphicsPixmapItem * pi = qgraphicsitem_cast<QGraphicsPixmapItem *>(cur_item);
	if (!pi) return;
	QList<QByteArray> sif(QImageReader::supportedImageFormats());
	QString f;
	foreach(const QByteArray & i, sif) {
		if (!f.isEmpty()) f += " ";
		f += "*.";
		f += i;
	}
	QString ret = QFileDialog::getOpenFileName(0, tr("Select image"), prev_dir, QString("Images(%1)").arg(f));
	if (ret.isEmpty()) return;
	QImage im(ret);
	if (im.isNull()) return;
	prev_dir   = ret;
	QRectF obr = pi->boundingRect();
	pi->setPixmap(QPixmap::fromImage(im));
	QRectF nbr = pi->boundingRect();
	QSizeF ds  = (obr.size() - nbr.size()) / 2.;
	pi->setPos(pi->pos() + QPointF(ds.width(), ds.height()));
	changeFinished();
}


void DrawTools::buttonImagePaste_clicked() {
	QGraphicsPixmapItem * pi = qgraphicsitem_cast<QGraphicsPixmapItem *>(cur_item);
	if (!pi) return;
	QPixmap pm = QApplication::clipboard()->pixmap();
	if (pm.isNull()) return;
	QRectF obr = pi->boundingRect();
	pi->setPixmap(pm);
	QRectF nbr = pi->boundingRect();
	QSizeF ds  = (obr.size() - nbr.size()) / 2.;
	pi->setPos(pi->pos() + QPointF(ds.width(), ds.height()));
	changeFinished();
}


void DrawTools::buttonFont_clicked() {
	if (!cur_item) return;
	QGraphicsSimpleTextItem * ti = qgraphicsitem_cast<QGraphicsSimpleTextItem *>(cur_item);
	AlignedTextItem * ati        = qgraphicsitem_cast<AlignedTextItem *>(cur_item);
	if (!ti && !ati) return;
	QFont font_prev;
	if (ti) font_prev = ti->font();
	if (ati) font_prev = ati->font();
	font_dlg.blockSignals(true);
	font_dlg.setCurrentFont(font_prev);
	font_dlg.blockSignals(false);
	if (font_dlg.exec() == QDialog::Rejected) {
		font_dlg.setCurrentFont(font_prev);
	} else {
		changeFinished();
	}
}


void DrawTools::buttonTextEdit_clicked() {
	text_dlg.setWindowIcon(QApplication::activeWindow()->windowIcon());
	text_edit.setPlainText(ui->comboText->lineEdit()->text());
	text_edit.selectAll();
	text_edit.setFocus();
	if (text_dlg.exec() == QDialog::Rejected) return;
	ui->comboText->lineEdit()->setText(text_edit.toPlainText());
	propertyChanged();
	changeFinished();
}


void DrawTools::actionZ_triggered() {
	if (!cur_item) return;
	if (cur_item->data(bvidType).toInt() == bvitDecor) {
		BlockView * view = nullptr;
		if (cur_item->scene())
			if (!cur_item->scene()->views().isEmpty()) {
				view = qobject_cast<BlockView *>(cur_item->scene()->views()[0]);
			}
		if (!view) return;
		QGraphicsScene * scene    = view->scene();
		QList<QGraphicsItem *> dl = view->decors();
		scene->blockSignals(true);
		foreach(QGraphicsItem * d, dl)
			scene->removeItem(d);
		int ind = dl.indexOf(cur_item);
		dl.removeAt(ind);
		if (sender() == &actions_Z_up) dl.insert(ind + 1, cur_item);
		if (sender() == &actions_Z_top) dl.append(cur_item);
		if (sender() == &actions_Z_down) dl.insert(ind - 1, cur_item);
		if (sender() == &actions_Z_bottom) dl.prepend(cur_item);
		foreach(QGraphicsItem * d, dl)
			scene->addItem(d);
		scene->blockSignals(false);
	}
	if (cur_item->data(bvidBlockDecor).toBool()) {
		BlockItem * bi = qgraphicsitem_cast<BlockItem *>(cur_item->parentItem());
		if (!bi) return;
		QList<QGraphicsItem *> dl = bi->decors_;
		foreach(QGraphicsItem * d, dl)
			d->setParentItem(nullptr);
		int ind = dl.indexOf(cur_item);
		dl.removeAt(ind);
		if (sender() == &actions_Z_up) dl.insert(ind + 1, cur_item);
		if (sender() == &actions_Z_top) dl.append(cur_item);
		if (sender() == &actions_Z_down) dl.insert(ind - 1, cur_item);
		if (sender() == &actions_Z_bottom) dl.prepend(cur_item);
		bi->decors_ = dl;
		foreach(QGraphicsItem * d, dl)
			d->setParentItem(bi);
	}
	size_item.assignObject(cur_item);
	emitZAvailabe(cur_item);
	emit itemZChanged(cur_item);
}


void DrawTools::setResizeHandlesEnabled(bool on) {
	resize_enabled = on;
	if (!on) {
		size_item.assignObject(nullptr);
		return;
	}
	if (cur_item && on) propertyChanged();
}
