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 #include <QLocale>
9 #include "appmodes.h"
10 #include "iconmanager.h"
11 #include "localemgr.h"
12 #include "pageitem_table.h"
13 #include "propertywidget_textcolor.h"
14 #include "scribus.h"
15 #include "scribusapp.h"
16 #include "selection.h"
17 
PropertyWidget_TextColor(QWidget * parent)18 PropertyWidget_TextColor::PropertyWidget_TextColor(QWidget* parent) : QFrame(parent)
19 {
20 	setupUi(this);
21 
22 	layout()->setAlignment(Qt::AlignLeft);
23 
24 	fillLayout->setAlignment(Qt::AlignLeft);
25 	fillColor->setPixmapType(ColorCombo::fancyPixmaps);
26 	fillIcon->setScaledContents( false );
27 
28 	strokeLayout->setAlignment(Qt::AlignLeft);
29 	strokeColor->setPixmapType(ColorCombo::fancyPixmaps);
30 	strokeIcon->setScaledContents( false );
31 
32 	backLayout->setAlignment(Qt::AlignLeft);
33 	backColor->setPixmapType(ColorCombo::fancyPixmaps);
34 	backIcon->setScaledContents( false );
35 
36 	effectsLayout->setAlignment(Qt::AlignLeft);
37 
38 	iconSetChange();
39 	languageChange();
40 
41 	strokeIcon->setEnabled(false);
42 	strokeColor->setEnabled(false);
43 	strokeShade->setEnabled(false);
44 
45 	connect(ScQApp, SIGNAL(iconSetChanged()), this, SLOT(iconSetChange()));
46 	connect(ScQApp, SIGNAL(localeChanged()), this, SLOT(localeChange()));
47 
48 }
49 
setMainWindow(ScribusMainWindow * mw)50 void PropertyWidget_TextColor::setMainWindow(ScribusMainWindow *mw)
51 {
52 	m_ScMW = mw;
53 
54 	connect(m_ScMW, SIGNAL(UpdateRequest(int)), this, SLOT(handleUpdateRequest(int)));
55 }
56 
setDoc(ScribusDoc * d)57 void PropertyWidget_TextColor::setDoc(ScribusDoc *d)
58 {
59 	if((d == (ScribusDoc*) m_doc) || (m_ScMW && m_ScMW->scriptIsRunning()))
60 		return;
61 
62 	if (m_doc)
63 	{
64 		disconnect(m_doc->m_Selection, SIGNAL(selectionChanged()), this, SLOT(handleSelectionChanged()));
65 		disconnect(m_doc             , SIGNAL(docChanged())      , this, SLOT(handleSelectionChanged()));
66 	}
67 
68 	m_doc  = d;
69 	m_item = nullptr;
70 
71 	if (m_doc.isNull())
72 	{
73 		disconnectSignals();
74 		return;
75 	}
76 
77 	updateColorList();
78 
79 	connect(m_doc->m_Selection, SIGNAL(selectionChanged()), this, SLOT(handleSelectionChanged()));
80 	connect(m_doc             , SIGNAL(docChanged())      , this, SLOT(handleSelectionChanged()));
81 }
82 
setCurrentItem(PageItem * item)83 void PropertyWidget_TextColor::setCurrentItem(PageItem *item)
84 {
85 	if (!m_ScMW || m_ScMW->scriptIsRunning())
86 		return;
87 	//CB We shouldn't really need to process this if our item is the same one
88 	//maybe we do if the item has been changed by scripter.. but that should probably
89 	//set some status if so.
90 	//FIXME: This won't work until when a canvas deselect happens, m_item must be nullptr.
91 	//if (m_item == i)
92 	//	return;
93 
94 	disconnectSignals();
95 
96 	m_item = item;
97 	if (item && m_doc.isNull())
98 		setDoc(item->doc());
99 
100 	configureWidgets();
101 
102 	if (m_item == nullptr)
103 		return;
104 	if (!m_item->isTable() && !m_item->isTextFrame() && !m_item->isPathText())
105 		return;
106 
107 	if (m_item->isTextFrame() || m_item->isPathText() || m_item->isTable())
108 	{
109 		ParagraphStyle parStyle =  m_item->itemText.defaultStyle();
110 		if (m_doc->appMode == modeEdit || m_doc->appMode == modeEditTable)
111 			m_item->currentTextProps(parStyle);
112 		updateStyle(parStyle);
113 	}
114 	connectSignals();
115 }
116 
connectSignals()117 void PropertyWidget_TextColor::connectSignals()
118 {
119 	connect(fillColor   , SIGNAL(activated(int)), this, SLOT(handleTextFill())     , Qt::UniqueConnection);
120 	connect(strokeColor , SIGNAL(activated(int)), this, SLOT(handleTextStroke())   , Qt::UniqueConnection);
121 	connect(fillShade   , SIGNAL(clicked())     , this, SLOT(handleTextShade())    , Qt::UniqueConnection);
122 	connect(strokeShade , SIGNAL(clicked())     , this, SLOT(handleTextShade())    , Qt::UniqueConnection);
123 	connect(backShade   , SIGNAL(clicked())     , this, SLOT(handleTextShade())    , Qt::UniqueConnection);
124 	connect(backColor   , SIGNAL(activated(int)), this, SLOT(handleTextBackground())     , Qt::UniqueConnection);
125 
126 	connect(textEffects, SIGNAL(State(int))      , this, SLOT(handleTypeStyle(int)), Qt::UniqueConnection);
127 	connect(textEffects->ShadowVal->Xoffset  , SIGNAL(valueChanged(double)), this, SLOT(handleShadowOffs()), Qt::UniqueConnection);
128 	connect(textEffects->ShadowVal->Yoffset  , SIGNAL(valueChanged(double)), this, SLOT(handleShadowOffs()), Qt::UniqueConnection);
129 	connect(textEffects->OutlineVal->LWidth  , SIGNAL(valueChanged(double)), this, SLOT(handleOutlineWidth()), Qt::UniqueConnection);
130 	connect(textEffects->UnderlineVal->LPos  , SIGNAL(valueChanged(double)), this, SLOT(handleUnderline()) , Qt::UniqueConnection);
131 	connect(textEffects->UnderlineVal->LWidth, SIGNAL(valueChanged(double)), this, SLOT(handleUnderline()) , Qt::UniqueConnection);
132 	connect(textEffects->StrikeVal->LPos     , SIGNAL(valueChanged(double)), this, SLOT(handleStrikeThru()), Qt::UniqueConnection);
133 	connect(textEffects->StrikeVal->LWidth   , SIGNAL(valueChanged(double)), this, SLOT(handleStrikeThru()), Qt::UniqueConnection);
134 }
135 
disconnectSignals()136 void PropertyWidget_TextColor::disconnectSignals()
137 {
138 	disconnect(fillColor   , SIGNAL(activated(int)), this, SLOT(handleTextFill()));
139 	disconnect(strokeColor , SIGNAL(activated(int)), this, SLOT(handleTextStroke()));
140 	disconnect(fillShade   , SIGNAL(clicked())     , this, SLOT(handleTextShade()));
141 	disconnect(strokeShade , SIGNAL(clicked())     , this, SLOT(handleTextShade()));
142 	disconnect(backShade   , SIGNAL(clicked())     , this, SLOT(handleTextShade()));
143 	disconnect(backColor   , SIGNAL(activated(int)), this, SLOT(handleTextBackground()));
144 
145 	disconnect(textEffects, SIGNAL(State(int))      , this, SLOT(handleTypeStyle(int)));
146 	disconnect(textEffects->ShadowVal->Xoffset  , SIGNAL(valueChanged(double)), this, SLOT(handleShadowOffs()));
147 	disconnect(textEffects->ShadowVal->Yoffset  , SIGNAL(valueChanged(double)), this, SLOT(handleShadowOffs()));
148 	disconnect(textEffects->OutlineVal->LWidth  , SIGNAL(valueChanged(double)), this, SLOT(handleOutlineWidth()));
149 	disconnect(textEffects->UnderlineVal->LPos  , SIGNAL(valueChanged(double)), this, SLOT(handleUnderline()));
150 	disconnect(textEffects->UnderlineVal->LWidth, SIGNAL(valueChanged(double)), this, SLOT(handleUnderline()));
151 	disconnect(textEffects->StrikeVal->LPos     , SIGNAL(valueChanged(double)), this, SLOT(handleStrikeThru()));
152 	disconnect(textEffects->StrikeVal->LWidth   , SIGNAL(valueChanged(double)), this, SLOT(handleStrikeThru()));
153 }
154 
configureWidgets()155 void PropertyWidget_TextColor::configureWidgets()
156 {
157 	bool enabled = false;
158 	if (m_item && m_doc)
159 	{
160 		if (m_item->isPathText() || m_item->isTextFrame() || m_item->isTable())
161 			enabled = true;
162 		if ((m_item->isGroup()) && (!m_item->isSingleSel))
163 			enabled = false;
164 		if (m_item->isOSGFrame() || m_item->isSymbol())
165 			enabled = false;
166 		if (m_doc->m_Selection->count() > 1)
167 			enabled = false;
168 	}
169 	setEnabled(enabled);
170 }
171 
handleSelectionChanged()172 void PropertyWidget_TextColor::handleSelectionChanged()
173 {
174 	if (!m_doc || !m_ScMW || m_ScMW->scriptIsRunning())
175 		return;
176 
177 	PageItem* currItem = currentItemFromSelection();
178 	setCurrentItem(currItem);
179 	updateGeometry();
180 }
181 
handleUpdateRequest(int updateFlags)182 void PropertyWidget_TextColor::handleUpdateRequest(int updateFlags)
183 {
184 	if (updateFlags & reqColorsUpdate)
185 		updateColorList();
186 }
187 
updateColorList()188 void PropertyWidget_TextColor::updateColorList()
189 {
190 	if (!m_doc || !m_ScMW || m_ScMW->scriptIsRunning())
191 		return;
192 
193 	if (m_item)
194 		disconnectSignals();
195 
196 	fillColor->setColors(m_doc->PageColors, true);
197 	strokeColor->setColors(m_doc->PageColors, false);
198 	backColor->setColors(m_doc->PageColors, true);
199 	fillColor->view()->setMinimumWidth(fillColor->view()->maximumViewportSize().width() + 24);
200 	strokeColor->view()->setMinimumWidth(strokeColor->view()->maximumViewportSize().width() + 24);
201 	backColor->view()->setMinimumWidth(backColor->view()->maximumViewportSize().width() + 24);
202 
203 	if (m_item)
204 		setCurrentItem(m_item);
205 }
206 
updateCharStyle(const CharStyle & charStyle)207 void PropertyWidget_TextColor::updateCharStyle(const CharStyle& charStyle)
208 {
209 	if (!m_ScMW || m_ScMW->scriptIsRunning())
210 		return;
211 
212 	showOutlineW  (charStyle.outlineWidth());
213 	showShadowOffset(charStyle.shadowXOffset(), charStyle.shadowYOffset());
214 	showTextColors(charStyle.strokeColor(), charStyle.fillColor(), charStyle.backColor(), charStyle.strokeShade(), charStyle.fillShade(), charStyle.backShade());
215 	showTextEffects(charStyle.effects());
216 	showStrikeThru(charStyle.strikethruOffset()  , charStyle.strikethruWidth());
217 	showUnderline (charStyle.underlineOffset(), charStyle.underlineWidth());
218 }
219 
updateStyle(const ParagraphStyle & newCurrent)220 void PropertyWidget_TextColor::updateStyle(const ParagraphStyle& newCurrent)
221 {
222 	if (!m_ScMW || m_ScMW->scriptIsRunning())
223 		return;
224 
225 	const CharStyle& charStyle = newCurrent.charStyle();
226 
227 	showOutlineW  (charStyle.outlineWidth());
228 	showShadowOffset(charStyle.shadowXOffset(), charStyle.shadowYOffset());
229 	showTextColors(charStyle.strokeColor(), charStyle.fillColor(), charStyle.backColor(), charStyle.strokeShade(), charStyle.fillShade(), charStyle.backShade());
230 	showTextEffects(charStyle.effects());
231 	showStrikeThru(charStyle.strikethruOffset()  , charStyle.strikethruWidth());
232 	showUnderline (charStyle.underlineOffset(), charStyle.underlineWidth());
233 }
234 
showOutlineW(double x)235 void PropertyWidget_TextColor::showOutlineW(double x)
236 {
237 	if (!m_ScMW || m_ScMW->scriptIsRunning())
238 		return;
239 	textEffects->OutlineVal->LWidth->showValue(x / 10.0);
240 }
241 
showShadowOffset(double x,double y)242 void PropertyWidget_TextColor::showShadowOffset(double x, double y)
243 {
244 	if (!m_ScMW || m_ScMW->scriptIsRunning())
245 		return;
246 	textEffects->ShadowVal->Xoffset->showValue(x / 10.0);
247 	textEffects->ShadowVal->Yoffset->showValue(y / 10.0);
248 }
249 
showStrikeThru(double p,double w)250 void PropertyWidget_TextColor::showStrikeThru(double p, double w)
251 {
252 	if (!m_ScMW || m_ScMW->scriptIsRunning())
253 		return;
254 	textEffects->StrikeVal->LPos->showValue(p / 10.0);
255 	textEffects->StrikeVal->LWidth->showValue(w / 10.0);
256 }
257 
showTextColors(const QString & strokeCol,const QString & fillCol,const QString & backCol,double strokeShd,double fillShd,double backShd)258 void PropertyWidget_TextColor::showTextColors(const QString& strokeCol, const QString& fillCol, const QString& backCol, double strokeShd, double fillShd, double backShd)
259 {
260 	if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
261 		return;
262 
263 	QSignalBlocker fillShadeBlocker(fillShade);
264 	QSignalBlocker strokeShadeBlocker(strokeShade);
265 	QSignalBlocker backShadeBlocker(backShade);
266 	QSignalBlocker fillColorBlocker(fillColor);
267 	QSignalBlocker strokeColorBlocker(strokeColor);
268 	QSignalBlocker backColorBlocker(backColor);
269 
270 	fillShade->setValue(qRound(fillShd));
271 	strokeShade->setValue(qRound(strokeShd));
272 	backShade->setValue(qRound(backShd));
273 
274 	if (!fillCol.isEmpty())
275 		fillColor->setCurrentColor(fillCol);
276 	if (!strokeCol.isEmpty())
277 		strokeColor->setCurrentColor(strokeCol);
278 	if (!backCol.isEmpty())
279 		backColor->setCurrentColor(backCol);
280 }
281 
showTextEffects(int s)282 void PropertyWidget_TextColor::showTextEffects(int s)
283 {
284 	if (!m_ScMW || m_ScMW->scriptIsRunning())
285 		return;
286 	strokeIcon->setEnabled(false);
287 	strokeColor->setEnabled(false);
288 	strokeShade->setEnabled(false);
289 	textEffects->setStyle(s);
290 	if ((s & 4) || (s & 256))
291 	{
292 		strokeIcon->setEnabled(true);
293 		strokeColor->setEnabled(true);
294 		strokeShade->setEnabled(true);
295 	}
296 }
297 
handleOutlineWidth()298 void PropertyWidget_TextColor::handleOutlineWidth()
299 {
300 	if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
301 		return;
302 	int x = qRound(textEffects->OutlineVal->LWidth->value() * 10.0);
303 	PageItem *i2 = m_item;
304 	if (m_doc->appMode == modeEditTable)
305 		i2 = m_item->asTable()->activeCell().textFrame();
306 	if (i2 != nullptr)
307 	{
308 		Selection tempSelection(this, false);
309 		tempSelection.addItem(i2, true);
310 		m_doc->itemSelection_SetOutlineWidth(x, &tempSelection);
311 	}
312 }
313 
handleShadowOffs()314 void PropertyWidget_TextColor::handleShadowOffs()
315 {
316 	if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
317 		return;
318 	int x = qRound(textEffects->ShadowVal->Xoffset->value() * 10.0);
319 	int y = qRound(textEffects->ShadowVal->Yoffset->value() * 10.0);
320 	PageItem *i2 = m_item;
321 	if (m_doc->appMode == modeEditTable)
322 		i2 = m_item->asTable()->activeCell().textFrame();
323 	if (i2 != nullptr)
324 	{
325 		Selection tempSelection(this, false);
326 		tempSelection.addItem(i2, true);
327 		m_doc->itemSelection_SetShadowOffsets(x, y, &tempSelection);
328 	}
329 }
330 
handleStrikeThru()331 void PropertyWidget_TextColor::handleStrikeThru()
332 {
333 	if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
334 		return;
335 	int x = qRound(textEffects->StrikeVal->LPos->value() * 10.0);
336 	int y = qRound(textEffects->StrikeVal->LWidth->value() * 10.0);
337 	PageItem *i2 = m_item;
338 	if (m_doc->appMode == modeEditTable)
339 		i2 = m_item->asTable()->activeCell().textFrame();
340 	if (i2 != nullptr)
341 	{
342 		Selection tempSelection(this, false);
343 		tempSelection.addItem(i2, true);
344 		m_doc->itemSelection_SetStrikethru(x, y, &tempSelection);
345 	}
346 }
347 
handleTextFill()348 void PropertyWidget_TextColor::handleTextFill()
349 {
350 	if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
351 		return;
352 	PageItem *i2 = m_item;
353 	if (m_doc->appMode == modeEditTable)
354 		i2 = m_item->asTable()->activeCell().textFrame();
355 	if (i2 != nullptr)
356 	{
357 		Selection tempSelection(this, false);
358 		tempSelection.addItem(i2, true);
359 		m_doc->itemSelection_SetFillColor(fillColor->currentColor(), &tempSelection);
360 	}
361 }
362 
handleTextStroke()363 void PropertyWidget_TextColor::handleTextStroke()
364 {
365 	if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
366 		return;
367 	PageItem *i2 = m_item;
368 	if (m_doc->appMode == modeEditTable)
369 		i2 = m_item->asTable()->activeCell().textFrame();
370 	if (i2 != nullptr)
371 	{
372 		Selection tempSelection(this, false);
373 		tempSelection.addItem(i2, true);
374 		m_doc->itemSelection_SetStrokeColor(strokeColor->currentColor(), &tempSelection);
375 	}
376 }
377 
handleTextBackground()378 void PropertyWidget_TextColor::handleTextBackground()
379 {
380 	if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
381 		return;
382 	PageItem *i2 = m_item;
383 	if (m_doc->appMode == modeEditTable)
384 		i2 = m_item->asTable()->activeCell().textFrame();
385 	if (i2 != nullptr)
386 	{
387 		Selection tempSelection(this, false);
388 		tempSelection.addItem(i2, true);
389 		m_doc->itemSelection_SetBackgroundColor(backColor->currentColor(), &tempSelection);
390 	}
391 }
392 
handleTextShade()393 void PropertyWidget_TextColor::handleTextShade()
394 {
395 	if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
396 		return;
397 	if (strokeShade == sender())
398 	{
399 		int b = strokeShade->getValue();
400 		PageItem *i2 = m_item;
401 		if (m_doc->appMode == modeEditTable)
402 			i2 = m_item->asTable()->activeCell().textFrame();
403 		if (i2 != nullptr)
404 		{
405 			Selection tempSelection(this, false);
406 			tempSelection.addItem(i2, true);
407 			m_doc->itemSelection_SetStrokeShade(b, &tempSelection);
408 		}
409 	}
410 	else if (fillShade == sender())
411 	{
412 		int b = fillShade->getValue();
413 		PageItem *i2 = m_item;
414 		if (m_doc->appMode == modeEditTable)
415 			i2 = m_item->asTable()->activeCell().textFrame();
416 		if (i2 != nullptr)
417 		{
418 			Selection tempSelection(this, false);
419 			tempSelection.addItem(i2, true);
420 			m_doc->itemSelection_SetFillShade(b, &tempSelection);
421 		}
422 	}
423 	else if (backShade == sender())
424 	{
425 		int b = backShade->getValue();
426 		PageItem *i2 = m_item;
427 		if (m_doc->appMode == modeEditTable)
428 			i2 = m_item->asTable()->activeCell().textFrame();
429 		if (i2 != nullptr)
430 		{
431 			Selection tempSelection(this, false);
432 			tempSelection.addItem(i2, true);
433 			m_doc->itemSelection_SetBackgroundShade(b, &tempSelection);
434 		}
435 	}
436 }
437 
handleTypeStyle(int s)438 void PropertyWidget_TextColor::handleTypeStyle(int s)
439 {
440 	if (!m_ScMW || m_ScMW->scriptIsRunning())
441 		return;
442 	PageItem *i2 = m_item;
443 	if (m_doc->appMode == modeEditTable)
444 		i2 = m_item->asTable()->activeCell().textFrame();
445 	if (i2 != nullptr)
446 	{
447 		Selection tempSelection(this, false);
448 		tempSelection.addItem(i2, true);
449 		m_doc->itemSelection_SetEffects(s, &tempSelection);
450 		m_ScMW->setStyleEffects(s);
451 	}
452 }
453 
showUnderline(double p,double w)454 void PropertyWidget_TextColor::showUnderline(double p, double w)
455 {
456 	if (!m_ScMW || m_ScMW->scriptIsRunning())
457 		return;
458 	textEffects->UnderlineVal->LPos->showValue(p / 10.0);
459 	textEffects->UnderlineVal->LWidth->showValue(w / 10.0);
460 }
461 
handleUnderline()462 void PropertyWidget_TextColor::handleUnderline()
463 {
464 	if ((m_doc) && (m_item))
465 	{
466 		int x = qRound(textEffects->UnderlineVal->LPos->value() * 10.0);
467 		int y = qRound(textEffects->UnderlineVal->LWidth->value() * 10.0);
468 		PageItem *i2 = m_item;
469 		if (m_doc->appMode == modeEditTable)
470 			i2 = m_item->asTable()->activeCell().textFrame();
471 		if (i2 != nullptr)
472 		{
473 			Selection tempSelection(this, false);
474 			tempSelection.addItem(i2, true);
475 			m_doc->itemSelection_SetUnderline(x, y, &tempSelection);
476 		}
477 	}
478 }
479 
changeEvent(QEvent * e)480 void PropertyWidget_TextColor::changeEvent(QEvent *e)
481 {
482 	if (e->type() == QEvent::LanguageChange)
483 	{
484 		languageChange();
485 		return;
486 	}
487 	QWidget::changeEvent(e);
488 }
489 
iconSetChange()490 void PropertyWidget_TextColor::iconSetChange()
491 {
492 	IconManager& iconManager = IconManager::instance();
493 
494 	fillIcon->setPixmap(iconManager.loadPixmap("16/color-fill.png"));
495 	fillShadeLabel->setPixmap(iconManager.loadPixmap("shade.png"));
496 
497 	strokeIcon->setPixmap(iconManager.loadPixmap("16/color-stroke.png"));
498 	strokeShadeLabel->setPixmap(iconManager.loadPixmap("shade.png"));
499 
500 	backIcon->setPixmap(iconManager.loadPixmap("16/color-fill.png"));
501 	backShadeLabel->setPixmap(iconManager.loadPixmap("shade.png"));
502 }
503 
languageChange()504 void PropertyWidget_TextColor::languageChange()
505 {
506 	retranslateUi(this);
507 	textEffects->languageChange();
508 }
509 
localeChange()510 void PropertyWidget_TextColor::localeChange()
511 {
512 	const QLocale& l(LocaleManager::instance().userPreferredLocale());
513 	textEffects->ShadowVal->Xoffset->setLocale(l);
514 	textEffects->ShadowVal->Yoffset->setLocale(l);
515 	textEffects->OutlineVal->LWidth->setLocale(l);
516 	textEffects->UnderlineVal->LPos->setLocale(l);
517 	textEffects->UnderlineVal->LWidth->setLocale(l);
518 	textEffects->StrikeVal->LPos->setLocale(l);
519 	textEffects->StrikeVal->LWidth->setLocale(l);
520 }
521