1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 /***************************************************************************
8                           gradienteditor  -  description
9                              -------------------
10     begin                : Mit Mai 26 2004
11     copyright            : (C) 2004 by Franz Schmid
12     email                : Franz.Schmid@altmuehlnet.de
13  ***************************************************************************/
14 
15 /***************************************************************************
16  *                                                                         *
17  *   This program is free software; you can redistribute it and/or modify  *
18  *   it under the terms of the GNU General Public License as published by  *
19  *   the Free Software Foundation; either version 2 of the License, or     *
20  *   (at your option) any later version.                                   *
21  *                                                                         *
22  ***************************************************************************/
23 
24 #include <algorithm>
25 #include <QApplication>
26 #include <QCursor>
27 #include <QEvent>
28 #include <QMenu>
29 #include <QMouseEvent>
30 #include <QPaintEvent>
31 #include <QPainter>
32 #include <QPixmap>
33 #include <QPolygon>
34 #include <QToolTip>
35 
36 #include "fpoint.h"
37 #include "gradientpreview.h"
38 #include "iconmanager.h"
39 #include "scpainter.h"
40 
41 
GradientPreview(QWidget * pa)42 GradientPreview::GradientPreview(QWidget *pa) : QFrame(pa)
43 {
44 	setFrameShape( QFrame::Panel );
45 	setFrameShadow( QFrame::Sunken );
46 	setLineWidth( 2 );
47 	setMinimumSize(QSize(200, 70));
48 	setMaximumSize(QSize(3000, 70));
49 	setMouseTracking(true);
50 	setFocusPolicy(Qt::ClickFocus);
51 	Mpressed = false;
52 	outside = true;
53 	onlyselect = true;
54 	isEditable = true;
55 	fill_gradient = VGradient(VGradient::linear);
56 	fill_gradient.clearStops();
57 
58 	QColor color;
59 	color = QColor(255,255,255);
60 	fill_gradient.addStop( color, 0.0, 0.5, 1.0 );
61 	color = QColor(0,0,0);
62 	fill_gradient.addStop( color, 1.0, 0.5, 1.0 );
63 
64 	QList<VColorStop*> cstops = fill_gradient.colorStops();
65 	StopM.clear();
66 	contextStop = 0;
67 	ActStop = 0;
68 	for (int i = 0; i < fill_gradient.stops(); ++i)
69 	{
70 		int center = qRound(cstops.at(i)->rampPoint * (width() - 20)) + 10;
71 		StopM.append(center);
72 	}
73 }
74 
paintEvent(QPaintEvent * e)75 void GradientPreview::paintEvent(QPaintEvent *e)
76 {
77 	QList<VColorStop*> cstops = fill_gradient.colorStops();
78 	StopM.clear();
79 	for (int i = 0; i < fill_gradient.stops(); ++i)
80 	{
81 		int center = qRound(cstops.at(i)->rampPoint * (width() - 20)) + 10;
82 		StopM.append(center);
83 	}
84 	QImage pixm(width() - 20, 37, QImage::Format_ARGB32_Premultiplied);
85 	QPainter pb;
86 	QBrush b(QColor(205,205,205), IconManager::instance().loadPixmap("testfill.png"));
87 	pb.begin(&pixm);
88 	pb.fillRect(0, 0, pixm.width(), pixm.height(), b);
89 	pb.end();
90 	ScPainter *p = new ScPainter(&pixm, width() - 20, 37);
91 //	p->clear(Qt::white);
92 	p->setPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
93 	p->setFillMode(ScPainter::Gradient);
94 	p->fill_gradient = fill_gradient;
95 	p->setGradient(VGradient::linear, FPoint(0, 20), FPoint(width() - 20, 20), FPoint(0, 0), 1.0, 0.0);
96 	p->drawRect(0, 0, width() - 20, 37);
97 	p->end();
98 	delete p;
99 	QPainter pw;
100 	pw.begin(this);
101 	pw.drawImage(10, 5, pixm);
102 	if (isEditable)
103 	{
104 		for (int i = 0; i < fill_gradient.stops(); ++i)
105 		{
106 			int center = qRound(cstops.at(i)->rampPoint * (width() - 20)) + 10;
107 			pw.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
108 			if (StopM[qMax(ActStop,0)] == center)
109 				pw.setBrush(Qt::red);
110 			else
111 				pw.setBrush(Qt::blue);
112 			QPolygon cr;
113 			cr.setPoints(3, center, 43, center - 4, 56, center + 4, 56);
114 			pw.drawPolygon(cr);
115 		}
116 	}
117 	pw.end();
118 	QFrame::paintEvent(e);
119 }
120 
keyPressEvent(QKeyEvent * e)121 void GradientPreview::keyPressEvent(QKeyEvent *e)
122 {
123 	if (isEditable)
124 	{
125 		if(e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace)
126 		{
127 			if ((ActStop > 0) && (ActStop != static_cast<int>(StopM.count()-1)))
128 			{
129 				onlyselect = false;
130 				fill_gradient.removeStop(ActStop);
131 				ActStop = 0;
132 				repaint();
133 				QList<VColorStop*> cstops = fill_gradient.colorStops();
134 				emit selectedStop(cstops.at(ActStop));
135 			}
136 		}
137 	}
138 }
139 
mousePressEvent(QMouseEvent * m)140 void GradientPreview::mousePressEvent(QMouseEvent *m)
141 {
142 	QRect fpo;
143 	Mpressed = true;
144 	qApp->setOverrideCursor(QCursor(Qt::ArrowCursor));
145 	ActStop = -1;
146 	if (isEditable)
147 	{
148 		QList<VColorStop*> cstops = fill_gradient.colorStops();
149 		for (int yg = 0; yg < static_cast<int>(StopM.count()); ++yg)
150 		{
151 			fpo = QRect(static_cast<int>(StopM[yg]) - 4, 43, 8, 13);
152 			if (fpo.contains(m->pos()))
153 			{
154 				ActStop = yg;
155 				emit selectedStop(cstops.at(ActStop));
156 				repaint();
157 				onlyselect = true;
158 				return;
159 			}
160 		}
161 	}
162 }
163 
mouseReleaseEvent(QMouseEvent * m)164 void GradientPreview::mouseReleaseEvent(QMouseEvent *m)
165 {
166 	qApp->restoreOverrideCursor();
167 	QRect insideRect = QRect(10, 43, width() - 20, 13);
168 	if (isEditable)
169 	{
170 		QRect fpo;
171 		if (m->button() == Qt::LeftButton)
172 		{
173 			if ((Mpressed) && (ActStop > 0) && (ActStop != static_cast<int>(StopM.count()-1)) && (outside || !insideRect.contains(m->pos())))
174 			{
175 				onlyselect = false;
176 				fill_gradient.removeStop(ActStop);
177 				ActStop = 0;
178 				repaint();
179 				QList<VColorStop*> cstops = fill_gradient.colorStops();
180 				emit selectedStop(cstops.at(ActStop));
181 			}
182 			if ((m->y() < height()) && (m->y() > 43) && (m->x() > 0) && (m->x() < width()) && (ActStop == -1))
183 			{
184 				QList<VColorStop*> cstops = fill_gradient.colorStops();
185 				double  newStop = static_cast<double>((m->x() - 10)) / (static_cast<double>(width()) - 20);
186 				QColor  stopColor = (cstops.count() > 0) ? cstops.at(0)->color : QColor(255, 255, 255);
187 				QString stopName  = (cstops.count() > 0) ? cstops.at(0)->name  : QString("White");
188 				int     stopShade = (cstops.count() > 0) ? cstops.at(0)->shade : 100;
189 				fill_gradient.addStop(stopColor, newStop, 0.5, 1.0, stopName, stopShade);
190 				repaint();
191 				onlyselect = false;
192 				cstops = fill_gradient.colorStops();
193 				for (int yg = 0; yg < static_cast<int>(StopM.count()); ++yg)
194 				{
195 					fpo = QRect(static_cast<int>(StopM[yg]) - 4, 43, 8, 13);
196 					if (fpo.contains(m->pos()))
197 					{
198 						ActStop = yg;
199 						emit selectedStop(cstops.at(ActStop));
200 						repaint();
201 						break;
202 					}
203 				}
204 			}
205 		}
206 		else if (m->button() == Qt::RightButton)
207 		{
208 			Mpressed = false;
209 //			QList<VColorStop*> cstops = fill_gradient.colorStops();
210 			int stop = -1;
211 			for (int yg = 0; yg < static_cast<int>(StopM.count()); ++yg)
212 			{
213 				fpo = QRect(static_cast<int>(StopM[yg]) - 4, 43, 8, 13);
214 				if (fpo.contains(m->pos()))
215 				{
216 					stop = yg;
217 					break;
218 				}
219 			}
220 			contextStop = stop;
221 			mPos = m->pos();
222 			QMenu *pmen = new QMenu();
223 			setCursor(QCursor(Qt::ArrowCursor));
224 			pmen->addAction( tr("Add Stop"), this, SLOT(addStop()));
225 			if (stop != -1)
226 				pmen->addAction( tr("Remove Stop"), this, SLOT(removeStop()));
227 			pmen->exec(QCursor::pos());
228 			delete pmen;
229 		}
230 	}
231 	Mpressed = false;
232 	if ((!onlyselect) && (ActStop >= 0))
233 	{
234 		emit gradientChanged();
235 		QList<VColorStop*> cstops = fill_gradient.colorStops();
236 		emit currStep(cstops.at(ActStop)->rampPoint);
237 	}
238 }
239 
mouseMoveEvent(QMouseEvent * m)240 void GradientPreview::mouseMoveEvent(QMouseEvent *m)
241 {
242 	QRect insideRect = QRect(10, 43, width() - 20, 13);
243 	if (isEditable)
244 	{
245 		QRect fpo;
246 		qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
247 		if ((!Mpressed) && (m->y() < height()) && (m->y() > 43) && (m->x() > 9) && (m->x() < width()-9))
248 		{
249 			setCursor(IconManager::instance().loadCursor("AddPoint.png", 1, 1));
250 			for (int yg = 0; yg < static_cast<int>(StopM.count()); ++yg)
251 			{
252 				fpo = QRect(static_cast<int>(StopM[yg]) - 4, 43, 8, 13);
253 				if (fpo.contains(m->pos()))
254 				{
255 					setCursor(QCursor(Qt::SizeHorCursor));
256 					return;
257 				}
258 			}
259 		}
260 		if (m->buttons() & Qt::LeftButton)
261 		{
262 			if ((Mpressed) && (m->y() < height()) && (m->y() > 43) && (m->x() > 9) && (m->x() < width() - 9) && (ActStop != -1))
263 			{
264 				qApp->changeOverrideCursor(QCursor(Qt::SizeHorCursor));
265 				double newStop = static_cast<double>((m->x() - 10)) / (static_cast<double>(width()) - 20);
266 				if (ActStop > 1)
267 				{
268 					if (StopM[ActStop-1]+2 >= m->x())
269 						return;
270 				}
271 				if (ActStop < static_cast<int>(StopM.count()-2))
272 				{
273 					if (StopM[ActStop+1]-2 < m->x())
274 						return;
275 				}
276 				StopM[ActStop] = m->x();
277 				QList<VColorStop*> cstops = fill_gradient.colorStops();
278 				cstops.at(ActStop)->rampPoint = newStop;
279 				std::sort(cstops.begin(), cstops.end());
280 				onlyselect = false;
281 				repaint();
282 			}
283 			if ((Mpressed) && (outside || !insideRect.contains(m->pos())) && (ActStop > 0) && (ActStop != static_cast<int>(StopM.count()-1)))
284 				qApp->changeOverrideCursor(IconManager::instance().loadCursor("DelPoint.png", 1, 1));
285 		}
286 	}
287 }
288 
leaveEvent(QEvent *)289 void GradientPreview::leaveEvent(QEvent*)
290 {
291 	if (isEditable)
292 	{
293 		if (Mpressed)
294 		{
295 			if ((ActStop > 0) && (ActStop != static_cast<int>(StopM.count()-1)))
296 				qApp->changeOverrideCursor(IconManager::instance().loadCursor("DelPoint.png", 1, 1));
297 			else
298 				qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
299 		}
300 		outside = true;
301 	}
302 }
303 
enterEvent(QEvent *)304 void GradientPreview::enterEvent(QEvent*)
305 {
306 	outside = false;
307 }
308 
addStop()309 void GradientPreview::addStop()
310 {
311 	QList<VColorStop*> cstops = fill_gradient.colorStops();
312 	double  newStop = static_cast<double>((mPos.x() - 10)) / (static_cast<double>(width()) - 20);
313 	QColor  stopColor = (cstops.count() > 0) ? cstops.at(0)->color : QColor(255, 255, 255);
314 	QString stopName  = (cstops.count() > 0) ? cstops.at(0)->name  : QString("White");
315 	int     stopShade = (cstops.count() > 0) ? cstops.at(0)->shade : 100;
316 	fill_gradient.addStop(stopColor, newStop, 0.5, 1.0, stopName, stopShade);
317 	repaint();
318 	onlyselect = false;
319 	cstops = fill_gradient.colorStops();
320 	for (int yg = 0; yg < static_cast<int>(StopM.count()); ++yg)
321 	{
322 		QRect fpo = QRect(static_cast<int>(StopM[yg]) - 4, 43, 8, 13);
323 		if (fpo.contains(mPos))
324 		{
325 			ActStop = yg;
326 			emit selectedStop(cstops.at(ActStop));
327 			repaint();
328 			break;
329 		}
330 	}
331 }
332 
removeStop()333 void GradientPreview::removeStop()
334 {
335 	if ((contextStop > 0) && (contextStop != static_cast<int>(StopM.count()-1)))
336 	{
337 		onlyselect = false;
338 		fill_gradient.removeStop(contextStop);
339 		ActStop = 0;
340 		repaint();
341 		QList<VColorStop*> cstops = fill_gradient.colorStops();
342 		emit selectedStop(cstops.at(ActStop));
343 	}
344 }
345 
updateDisplay()346 void GradientPreview::updateDisplay()
347 {
348 	repaint();
349 	if (!fill_gradient.colorStops().isEmpty())
350 	{
351 		QList<VColorStop*> cstops = fill_gradient.colorStops();
352 		emit selectedStop(cstops.at(ActStop));
353 	}
354 }
355 
setActColor(const QColor & c,const QString & n,int s)356 void GradientPreview::setActColor(const QColor& c, const QString& n, int s)
357 {
358 	if (ActStop == -1)
359 		return;
360 	QList<VColorStop*> cstops = fill_gradient.colorStops();
361 	cstops.at(ActStop)->color = c;
362 	cstops.at(ActStop)->name = n;
363 	cstops.at(ActStop)->shade = s;
364 	repaint();
365 }
366 
setActTrans(double t)367 void GradientPreview::setActTrans(double t)
368 {
369 	if (ActStop == -1)
370 		return;
371 	QList<VColorStop*> cstops = fill_gradient.colorStops();
372 	cstops.at(ActStop)->opacity = t;
373 	repaint();
374 }
375 
setActStep(double t)376 void GradientPreview::setActStep(double t)
377 {
378 	if (ActStop == -1)
379 		return;
380 	QList<VColorStop*> cstops = fill_gradient.colorStops();
381 	cstops.at(ActStop)->rampPoint = t;
382 	repaint();
383 }
384 
setGradient(const VGradient & gradient)385 void GradientPreview::setGradient(const VGradient& gradient)
386 {
387 	if ((gradient.colorStops().count() == fill_gradient.colorStops().count()) && (ActStop >= 0))
388 	{
389 		int diffStops = 0;
390 		for (int i = 0; i < fill_gradient.colorStops().count(); ++i)
391 		{
392 			VColorStop* stop1 = gradient.colorStops().at(i);
393 			VColorStop* stop2 = fill_gradient.colorStops().at(i);
394 			if ((stop1->color != stop2->color) || (stop1->midPoint != stop2->midPoint) ||
395 				(stop1->name  != stop2->name)  || (stop1->opacity != stop2->opacity)   ||
396 				(stop1->rampPoint != stop2->rampPoint) || (stop1->shade != stop2->shade))
397 			{
398 				++diffStops;
399 			}
400 		}
401 		if (diffStops > 1)
402 			ActStop = 0;
403 	}
404 	if ((ActStop < 0) && (gradient.colorStops().count() > 0))
405 		ActStop = 0;
406 	if (ActStop >= gradient.colorStops().count())
407 		ActStop = 0;
408 	fill_gradient = gradient;
409 }
410 
setGradientEditable(bool val)411 void GradientPreview::setGradientEditable(bool val)
412 {
413 	isEditable = val;
414 	repaint();
415 }
416