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 "dasheditor.h"
25 
26 #include <algorithm>
27 
28 #include <QApplication>
29 #include <QCursor>
30 #include <QDoubleSpinBox>
31 #include <QEvent>
32 #include <QLabel>
33 #include <QMouseEvent>
34 #include <QPaintEvent>
35 #include <QPainter>
36 #include <QPixmap>
37 #include <QPolygon>
38 #include <QSignalBlocker>
39 #include <QToolTip>
40 
41 #include "scpainter.h"
42 #include "fpoint.h"
43 #include "iconmanager.h"
44 
DashPreview(QWidget * pa)45 DashPreview::DashPreview(QWidget *pa) : QFrame(pa)
46 {
47 	setFrameShape( QFrame::Panel );
48 	setFrameShadow( QFrame::Sunken );
49 	setLineWidth( 2 );
50 	setMinimumSize(QSize(200, 35));
51 	setMaximumSize(QSize(3000, 35));
52 	setMouseTracking(true);
53 
54 	m_dashValues.clear();
55 	m_dashValues.append(4.0);
56 	m_dashValues.append(2.0);
57 }
58 
paintEvent(QPaintEvent * e)59 void DashPreview::paintEvent(QPaintEvent *e)
60 {
61 	if (m_onlySelect)
62 		m_stops.clear();
63 
64 	int pWidth = width() - 20;
65 	QImage pixm(pWidth, 10, QImage::Format_ARGB32_Premultiplied);
66 
67 	ScPainter *p = new ScPainter(&pixm, pWidth, 10);
68 	p->clear(QColor(128, 128, 128));
69 	double startX = 0.0;
70 	p->setLineWidth(0);
71 	p->setFillMode(ScPainter::Solid);
72 	p->setBrush(Qt::black);
73 	for (int i = 0; i < m_dashValues.count(); i++)
74 	{
75 		if (i % 2 == 0)
76 			p->setBrush(Qt::black);
77 		else
78 			p->setBrush(Qt::white);
79 		double w = m_dashValues[i] * 10;
80 		p->drawRect(startX, 0, w, 10);
81 		startX += w;
82 		if (m_onlySelect)
83 			m_stops.append(startX);
84 	}
85 	p->setPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
86 	p->setFillMode(ScPainter::None);
87 	p->drawRect(0, 0, pWidth, 10);
88 	p->end();
89 	delete p;
90 
91 	QPainter pw;
92 	pw.begin(this);
93 	pw.drawImage(10, 5, pixm);
94 	for (int i = 0; i < m_stops.count(); ++i)
95 	{
96 		double center = m_stops[i] + 10;
97 		pw.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
98 		if (m_currentStop == i)
99 		{
100 			emit currStep(m_dashValues[m_currentStop]);
101 			pw.setBrush(Qt::red);
102 		}
103 		else
104 			pw.setBrush(Qt::blue);
105 		QPolygon cr;
106 		cr.setPoints(3, qRound(center), 16, qRound(center-4), 29, qRound(center+4), 29);
107 		pw.drawPolygon(cr);
108 	}
109 	pw.end();
110 
111 	QFrame::paintEvent(e);
112 	m_onlySelect = true;
113 }
114 
mousePressEvent(QMouseEvent * m)115 void DashPreview::mousePressEvent(QMouseEvent *m)
116 {
117 	QRect fpo;
118 	m_moveTimer.start();
119 	m_mousePressed = true;
120 	m_currentStop = -1;
121 
122 	m->accept();
123 	qApp->setOverrideCursor(QCursor(Qt::ArrowCursor));
124 
125 	for (int i = 0; i < m_stops.count(); ++i)
126 	{
127 		fpo = QRect(static_cast<int>(m_stops[i]) + 6, 16, 8, 13);
128 		if (fpo.contains(m->pos()))
129 		{
130 			m_currentStop = i;
131 			emit currStep(m_dashValues[m_currentStop]);
132 			repaint();
133 			return;
134 		}
135 	}
136 }
137 
mouseReleaseEvent(QMouseEvent * m)138 void DashPreview::mouseReleaseEvent(QMouseEvent *m)
139 {
140 	m->accept();
141 	qApp->restoreOverrideCursor();
142 	if ((m_mousePressed) && (m_stops.count() > 2) && (m_outside || m->y() > 30))
143 	{
144 		m_stops.removeAt(m_currentStop);
145 		m_dashValues.clear();
146 		double startX = 0.0;
147 		for (int i = 0; i < m_stops.count(); ++i)
148 		{
149 			double w = m_stops[i] / 10.0 - startX;
150 			m_dashValues.append(w);
151 			startX += w;
152 		}
153 		m_currentStop = 0;
154 		m_onlySelect = true;
155 		m_mousePressed = false;
156 		repaint();
157 		emit currStep(m_dashValues[m_currentStop]);
158 		emit dashChanged();
159 		return;
160 	}
161 	if ((m->y() < height()) && (m->y() > 16) && (m->x() > 9) && (m->x() < width() - 9))
162 	{
163 		if (m_currentStop != -1)
164 		{
165 			if (m_moveTimer.elapsed() < 250)
166 			{
167 				m_mousePressed = false;
168 				return;
169 			}
170 			m_stops[m_currentStop] = m->x() - 10;
171 		}
172 		else
173 		{
174 			if (m_dashValues.count() < 10)
175 				m_stops.append(m->x() - 10);
176 			std::sort(m_stops.begin(), m_stops.end());
177 			m_currentStop = 0;
178 			for (int i = 0; i < m_stops.count(); ++i)
179 			{
180 				QRect fpo = QRect(static_cast<int>(m_stops[i]) + 6, 16, 8, 13);
181 				if (fpo.contains(m->pos()))
182 				{
183 					m_currentStop = i;
184 					break;
185 				}
186 			}
187 		}
188 		m_dashValues.clear();
189 		double startX = 0.0;
190 		for (int i = 0; i < m_stops.count(); ++i)
191 		{
192 			double w = m_stops[i] / 10.0 - startX;
193 			m_dashValues.append(w);
194 			startX += w;
195 		}
196 		m_onlySelect = true;
197 		repaint();
198 		emit currStep(m_dashValues[m_currentStop]);
199 		emit dashChanged();
200 	}
201 	m_mousePressed = false;
202 }
203 
mouseMoveEvent(QMouseEvent * m)204 void DashPreview::mouseMoveEvent(QMouseEvent *m)
205 {
206 	m->accept();
207 
208 	QRect fpo;
209 	if ((!m_mousePressed) && (m->y() < height()) && (m->y() > 16) && (m->x() > 9) && (m->x() < width() - 9) && (m_dashValues.count() < 10))
210 	{
211 		setCursor(IconManager::instance().loadCursor("AddPoint.png", 1, 1));
212 		for (int i = 0; i < m_stops.count(); ++i)
213 		{
214 			fpo = QRect(static_cast<int>(m_stops[i]) + 6, 16, 8, 13);
215 			if (fpo.contains(m->pos()))
216 			{
217 				setCursor(QCursor(Qt::SizeHorCursor));
218 				return;
219 			}
220 		}
221 	}
222 	if ((m_mousePressed) && (m->y() < height()) && (m->y() > 16) && (m->x() > 9) && (m->x() < width() - 9) && (m_currentStop != -1))
223 	{
224 		qApp->changeOverrideCursor(QCursor(Qt::SizeHorCursor));
225 		if (m_currentStop > 1)
226 		{
227 			if (static_cast<int>(m_stops[m_currentStop - 1] + 10) + 2 >= m->x())
228 				return;
229 		}
230 		if (m_currentStop < static_cast<int>(m_stops.count() - 2))
231 		{
232 			if (static_cast<int>(m_stops[m_currentStop + 1] + 10) - 2 < m->x())
233 				return;
234 		}
235 		m_stops[m_currentStop] = m->x() - 10;
236 		m_dashValues.clear();
237 		double startX = 0.0;
238 		for (int i = 0; i < m_stops.count(); ++i)
239 		{
240 			double w = m_stops[i] / 10.0 - startX;
241 			m_dashValues.append(w);
242 			startX += w;
243 		}
244 		m_onlySelect = true;
245 		repaint();
246 		startX = 0.0;
247 		for (int i = 0; i < m_currentStop; ++i)
248 		{
249 			startX += m_stops[i] / 10.0 - startX;
250 		}
251 		emit currStep(m_stops[m_currentStop] / 10.0 - startX);
252 	}
253 	if ((m_mousePressed) && (m_outside || m->y() > 30) && (m_currentStop >= 0) && (m_stops.count() > 2))
254 		qApp->changeOverrideCursor(IconManager::instance().loadCursor("DelPoint.png", 1, 1));
255 }
256 
leaveEvent(QEvent *)257 void DashPreview::leaveEvent(QEvent*)
258 {
259 	if (m_mousePressed)
260 	{
261 		if ((m_currentStop >= 0) && (m_stops.count() > 2))
262 			qApp->changeOverrideCursor(IconManager::instance().loadCursor("DelPoint.png", 1, 1));
263 		else
264 			qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
265 	}
266 	m_outside = true;
267 }
268 
enterEvent(QEvent *)269 void DashPreview::enterEvent(QEvent*)
270 {
271 	m_outside = false;
272 }
273 
setActStep(double t)274 void DashPreview::setActStep(double t)
275 {
276 	if (m_currentStop == -1)
277 		return;
278 	m_dashValues[m_currentStop] = t;
279 	m_onlySelect = true;
280 	repaint();
281 	emit dashChanged();
282 }
283 
setDashValues(const QVector<double> & vals)284 void DashPreview::setDashValues(const QVector<double>& vals)
285 {
286 	m_dashValues = vals;
287 	if ((m_currentStop >= vals.count()) || (m_currentStop == -1))
288 		m_currentStop = 0;
289 	m_onlySelect = true;
290 	if (m_dashValues.count() != 0)
291 	{
292 		if ((m_currentStop >= vals.count()) || (m_currentStop == -1))
293 			emit currStep(m_dashValues[0]);
294 		else
295 			emit currStep(m_dashValues[m_currentStop]);
296 	}
297 	update();
298 }
299 
DashEditor(QWidget * pa)300 DashEditor::DashEditor(QWidget *pa) : QFrame(pa)
301 {
302 	setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum));
303 	setFrameShape( QFrame::Panel );
304 	setLineWidth( 1 );
305 	QGridLayout *gridLayout = new QGridLayout(this);
306 	gridLayout->setSpacing(3);
307 	gridLayout->setContentsMargins(6, 6, 6, 6);
308 
309 	Preview = new DashPreview(this);
310 	gridLayout->addWidget(Preview, 0, 0, 1, 2);
311 
312 	Position = new QDoubleSpinBox( this );
313 	Position->setDecimals(1);
314 	Position->setMinimum(0);
315 	Position->setMaximum(100);
316 	Position->setSingleStep(0.1);
317 	Position->setValue(0);
318 	Desc = new QLabel( this );
319 
320 	Offset = new QDoubleSpinBox( this );
321 	Offset->setDecimals(1);
322 	Offset->setMinimum(0);
323 	Offset->setMaximum(100);
324 	Offset->setSingleStep(0.1);
325 	Offset->setValue(0);
326 	Desc2 = new QLabel( this );
327 	languageChange();
328 
329 	gridLayout->addWidget(Desc, 1, 0, 1, 1);
330 	gridLayout->addWidget(Position, 1, 1, 1, 1);
331 	gridLayout->addWidget(Desc2, 2, 0, 1, 1);
332 	gridLayout->addWidget(Offset, 2, 1, 1, 1);
333 
334 	connect(Position, SIGNAL(valueChanged(double)), Preview, SLOT(setActStep(double)));
335 	connect(Offset, SIGNAL(valueChanged(double)), this, SIGNAL(dashChanged()));
336 	connect(Preview, SIGNAL(currStep(double)), this, SLOT(setPos(double)));
337 	connect(Preview, SIGNAL(dashChanged()), this, SIGNAL(dashChanged()));
338 }
339 
setPos(double p)340 void DashEditor::setPos(double p)
341 {
342 	QSignalBlocker blocker(Position);
343 	Position->setValue(p);
344 }
345 
setDashValues(QVector<double> vals,double linewidth,double offset)346 void DashEditor::setDashValues(QVector<double> vals, double linewidth, double offset)
347 {
348 	QVector<double> tmp;
349 	for (int i = 0; i < vals.count(); i++)
350 		tmp.append(vals[i] / linewidth);
351 	Preview->setDashValues(tmp);
352 
353 	disconnect(Offset, SIGNAL(valueChanged(double)), this, SIGNAL(dashChanged()));
354 	Offset->setValue(offset / linewidth);
355 	connect(Offset, SIGNAL(valueChanged(double)), this, SIGNAL(dashChanged()));
356 }
357 
getDashValues(double linewidth)358 QVector<double> DashEditor::getDashValues(double linewidth)
359 {
360 	auto dashValues = Preview->dashValues();
361 	for (int i = 0; i < dashValues.count(); i++)
362 		dashValues[i] *= linewidth;
363 	return dashValues;
364 }
365 
changeEvent(QEvent * e)366 void DashEditor::changeEvent(QEvent *e)
367 {
368 	if (e->type() == QEvent::LanguageChange)
369 		languageChange();
370 	else
371 		QWidget::changeEvent(e);
372 }
373 
languageChange()374 void DashEditor::languageChange()
375 {
376 	Desc->setText( tr( "Value:" ) );
377 	Desc2->setText( tr( "Offset:" ) );
378 }
379