LibreOffice Module sw (master) 1
ThemePanel.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 */
10
11#include <sal/config.h>
12
13#include "ThemePanel.hxx"
14
15#include <sfx2/objsh.hxx>
16
17#include <com/sun/star/lang/IllegalArgumentException.hpp>
18
19#include <editeng/fontitem.hxx>
20#include <utility>
21#include <vcl/bitmapex.hxx>
22#include <vcl/image.hxx>
23#include <vcl/settings.hxx>
24#include <vcl/svapp.hxx>
25#include <vcl/virdev.hxx>
26#include <charatr.hxx>
27#include <charfmt.hxx>
28#include <docsh.hxx>
29#include <docstyle.hxx>
30#include <fmtcol.hxx>
31#include <format.hxx>
32
33namespace
34{
35
36class FontSet
37{
38public:
39 OUString maName;
40 OUString msMonoFont;
41 OUString msHeadingFont;
42 OUString msBaseFont;
43};
44
45class ColorVariable
46{
47public:
49 sal_Int16 mnTintShade;
50
51 ColorVariable()
52 : mnIndex(-1)
53 , mnTintShade()
54 {}
55
56 ColorVariable(tools::Long nIndex, sal_Int16 nTintShade)
58 , mnTintShade(nTintShade)
59 {}
60};
61
62class StyleRedefinition
63{
64 ColorVariable maVariable;
65
66public:
67 OUString maElementName;
68
69public:
70 explicit StyleRedefinition(OUString aElementName)
71 : maElementName(std::move(aElementName))
72 {}
73
74 void setColorVariable(ColorVariable aVariable)
75 {
76 maVariable = aVariable;
77 }
78
79 Color getColor(svx::ColorSet const & rColorSet)
80 {
81 Color aColor;
82 if (maVariable.mnIndex > -1)
83 {
84 aColor = rColorSet.getColor(maVariable.mnIndex);
85 aColor.ApplyTintOrShade(maVariable.mnTintShade);
86 }
87 else
88 {
89 aColor = COL_BLACK;
90 }
91 return aColor;
92 }
93};
94
95class StyleSet
96{
97 std::vector<StyleRedefinition> maStyles;
98
99public:
100 explicit StyleSet()
101 {}
102
103 void add(StyleRedefinition const & aRedefinition)
104 {
105 maStyles.push_back(aRedefinition);
106 }
107
108 StyleRedefinition* get(std::u16string_view aString)
109 {
110 for (StyleRedefinition & rStyle : maStyles)
111 {
112 if (rStyle.maElementName == aString)
113 {
114 return &rStyle;
115 }
116 }
117 return nullptr;
118 }
119};
120
121StyleSet setupThemes()
122{
123 StyleSet aSet;
124
125 {
126 StyleRedefinition aRedefinition("Heading 1");
127 aRedefinition.setColorVariable(ColorVariable(10, -1000));
128 aSet.add(aRedefinition);
129 }
130
131 {
132 StyleRedefinition aRedefinition("Heading 2");
133 aRedefinition.setColorVariable(ColorVariable(7, -500));
134 aSet.add(aRedefinition);
135 }
136
137 {
138 StyleRedefinition aRedefinition("Heading 3");
139 aRedefinition.setColorVariable(ColorVariable(5, 0));
140 aSet.add(aRedefinition);
141 }
142
143 {
144 StyleRedefinition aRedefinition("Heading 4");
145 aRedefinition.setColorVariable(ColorVariable(6, -1000));
146 aSet.add(aRedefinition);
147 }
148
149 {
150 StyleRedefinition aRedefinition("Heading 5");
151 aRedefinition.setColorVariable(ColorVariable(4, -1500));
152 aSet.add(aRedefinition);
153 }
154
155 {
156 StyleRedefinition aRedefinition("Heading 6");
157 aRedefinition.setColorVariable(ColorVariable(3, -2500));
158 aSet.add(aRedefinition);
159 }
160
161 {
162 StyleRedefinition aRedefinition("Heading 7");
163 aRedefinition.setColorVariable(ColorVariable(3, -2500));
164 aSet.add(aRedefinition);
165 }
166
167 {
168 StyleRedefinition aRedefinition("Heading 8");
169 aRedefinition.setColorVariable(ColorVariable(2, 0));
170 aSet.add(aRedefinition);
171 }
172
173 {
174 StyleRedefinition aRedefinition("Heading 9");
175 aRedefinition.setColorVariable(ColorVariable(2, 0));
176 aSet.add(aRedefinition);
177 }
178
179 {
180 StyleRedefinition aRedefinition("Heading 10");
181 aRedefinition.setColorVariable(ColorVariable(0, 0));
182 aSet.add(aRedefinition);
183 }
184
185 return aSet;
186}
187
188void changeFont(SwFormat* pFormat, SwDocStyleSheet const * pStyle, FontSet const & rFontSet)
189{
190 if (pStyle->GetName() != "Default Style" && pFormat->GetAttrSet().GetItem(RES_CHRATR_FONT, false) == nullptr)
191 {
192 return;
193 }
194
195 SvxFontItem aFontItem(pFormat->GetFont(false));
196
197 FontPitch ePitch = aFontItem.GetPitch();
198
199 if (ePitch == PITCH_FIXED)
200 {
201 aFontItem.SetFamilyName(rFontSet.msMonoFont);
202 }
203 else
204 {
205 if (pStyle->GetName() == "Heading")
206 {
207 aFontItem.SetFamilyName(rFontSet.msHeadingFont);
208 }
209 else
210 {
211 aFontItem.SetFamilyName(rFontSet.msBaseFont);
212 }
213 }
214
215 pFormat->SetFormatAttr(aFontItem);
216}
217
218/*void changeBorder(SwTextFormatColl* pCollection, SwDocStyleSheet* pStyle, StyleSet& rStyleSet)
219{
220 if (pStyle->GetName() == "Heading")
221 {
222 SvxBoxItem aBoxItem(pCollection->GetBox());
223 editeng::SvxBorderLine aBorderLine;
224 aBorderLine.SetWidth(40); //20 = 1pt
225 aBorderLine.SetColor(rColorSet.mBaseColors[0]);
226 aBoxItem.SetLine(&aBorderLine, SvxBoxItemLine::BOTTOM);
227
228 pCollection->SetFormatAttr(aBoxItem);
229 }
230}*/
231
232void changeColor(SwTextFormatColl* pCollection, svx::ColorSet const & rColorSet, StyleRedefinition* pRedefinition)
233{
234 Color aColor = pRedefinition->getColor(rColorSet);
235
236 SvxColorItem aColorItem(pCollection->GetColor());
237 aColorItem.SetValue(aColor);
238 pCollection->SetFormatAttr(aColorItem);
239}
240
241std::vector<FontSet> initFontSets()
242{
243 std::vector<FontSet> aFontSets;
244 {
245 FontSet aFontSet;
246 aFontSet.maName = "Liberation Family";
247 aFontSet.msHeadingFont = "Liberation Sans";
248 aFontSet.msBaseFont = "Liberation Serif";
249 aFontSet.msMonoFont = "Liberation Mono";
250 aFontSets.push_back(aFontSet);
251 }
252 {
253 FontSet aFontSet;
254 aFontSet.maName = "DejaVu Family";
255 aFontSet.msHeadingFont = "DejaVu Sans";
256 aFontSet.msBaseFont = "DejaVu Serif";
257 aFontSet.msMonoFont = "DejaVu Sans Mono";
258 aFontSets.push_back(aFontSet);
259 }
260 {
261 FontSet aFontSet;
262 aFontSet.maName = "Croscore Modern";
263 aFontSet.msHeadingFont = "Caladea";
264 aFontSet.msBaseFont = "Carlito";
265 aFontSet.msMonoFont = "Liberation Mono";
266 aFontSets.push_back(aFontSet);
267 }
268 {
269 FontSet aFontSet;
270 aFontSet.maName = "Carlito";
271 aFontSet.msHeadingFont = "Carlito";
272 aFontSet.msBaseFont = "Carlito";
273 aFontSet.msMonoFont = "Liberation Mono";
274 aFontSets.push_back(aFontSet);
275 }
276 {
277 FontSet aFontSet;
278 aFontSet.maName = "Source Sans Family";
279 aFontSet.msHeadingFont = "Source Sans Pro";
280 aFontSet.msBaseFont = "Source Sans Pro";
281 aFontSet.msMonoFont = "Source Code Pro";
282 aFontSets.push_back(aFontSet);
283 }
284 {
285 FontSet aFontSet;
286 aFontSet.maName = "Source Sans Family 2";
287 aFontSet.msHeadingFont = "Source Sans Pro";
288 aFontSet.msBaseFont = "Source Sans Pro Light";
289 aFontSet.msMonoFont = "Source Code Pro";
290 aFontSets.push_back(aFontSet);
291 }
292 {
293 FontSet aFontSet;
294 aFontSet.maName = "Libertine Family";
295 aFontSet.msHeadingFont = "Linux Biolinum G";
296 aFontSet.msBaseFont = "Linux Libertine G";
297 aFontSet.msMonoFont = "Liberation Mono";
298 aFontSets.push_back(aFontSet);
299 }
300 {
301 FontSet aFontSet;
302 aFontSet.maName = "Noto Sans";
303 aFontSet.msHeadingFont = "Noto Sans";
304 aFontSet.msBaseFont = "Noto Sans";
305 aFontSet.msMonoFont = "Noto Mono";
306 aFontSets.push_back(aFontSet);
307 }
308 {
309 FontSet aFontSet;
310 aFontSet.maName = "Droid Sans";
311 aFontSet.msHeadingFont = "Droid Sans";
312 aFontSet.msBaseFont = "Droid Sans";
313 aFontSet.msMonoFont = "Droid Sans Mono";
314 aFontSets.push_back(aFontSet);
315 }
316 return aFontSets;
317}
318
319FontSet getFontSet(std::u16string_view rFontVariant, std::vector<FontSet>& aFontSets)
320{
321 for (const FontSet & rFontSet : aFontSets)
322 {
323 if (rFontSet.maName == rFontVariant)
324 return rFontSet;
325 }
326 return aFontSets[0];
327}
328
329void applyTheme(SfxStyleSheetBasePool* pPool, std::u16string_view sFontSetName, std::u16string_view sColorSetName,
330 StyleSet& rStyleSet, svx::ColorSets& rColorSets)
331{
332 SwDocStyleSheet* pStyle;
333
334 std::vector<FontSet> aFontSets = initFontSets();
335 FontSet aFontSet = getFontSet(sFontSetName, aFontSets);
336
337 svx::ColorSet aColorSet = rColorSets.getColorSet(sColorSetName);
338
339 pStyle = static_cast<SwDocStyleSheet*>(pPool->First(SfxStyleFamily::Para));
340 while (pStyle)
341 {
342 SwTextFormatColl* pCollection = pStyle->GetCollection();
343
344 changeFont(pCollection, pStyle, aFontSet);
345
346 StyleRedefinition* pRedefinition = rStyleSet.get(pStyle->GetName());
347
348 if (pRedefinition)
349 {
350 changeColor(pCollection, aColorSet, pRedefinition);
351 }
352
353 pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
354 }
355
356 pStyle = static_cast<SwDocStyleSheet*>(pPool->First(SfxStyleFamily::Char));
357 while (pStyle)
358 {
359 SwCharFormat* pCharFormat = pStyle->GetCharFormat();
360
361 changeFont(static_cast<SwFormat*>(pCharFormat), pStyle, aFontSet);
362
363 pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
364 }
365}
366
367BitmapEx GenerateColorPreview(const svx::ColorSet& rColorSet)
368{
370 float fScaleFactor = pVirtualDev->GetDPIScaleFactor();
371 tools::Long BORDER = 3 * fScaleFactor;
372 tools::Long SIZE = 14 * fScaleFactor;
373 tools::Long LABEL_HEIGHT = 16 * fScaleFactor;
374 tools::Long LABEL_TEXT_HEIGHT = 14 * fScaleFactor;
375
376 Size aSize(BORDER * 7 + SIZE * 6 + BORDER * 2, BORDER * 3 + SIZE * 2 + LABEL_HEIGHT);
377 pVirtualDev->SetOutputSizePixel(aSize);
378 pVirtualDev->SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetFaceColor()));
379 pVirtualDev->Erase();
380
383 tools::Long y2 = y1 + SIZE + BORDER;
384
385 pVirtualDev->SetLineColor(COL_LIGHTGRAY);
386 pVirtualDev->SetFillColor(COL_LIGHTGRAY);
387 tools::Rectangle aNameRect(Point(0, 0), Size(aSize.Width(), LABEL_HEIGHT));
388 pVirtualDev->DrawRect(aNameRect);
389
390 vcl::Font aFont;
391 OUString aName = rColorSet.getName();
392 aFont.SetFontHeight(LABEL_TEXT_HEIGHT);
393 pVirtualDev->SetFont(aFont);
394
395 Size aTextSize(pVirtualDev->GetTextWidth(aName), pVirtualDev->GetTextHeight());
396
397 Point aPoint((aNameRect.GetWidth() / 2.0) - (aTextSize.Width() / 2.0),
398 (aNameRect.GetHeight() / 2.0) - (aTextSize.Height() / 2.0));
399
400 pVirtualDev->DrawText(aPoint, aName);
401
402 pVirtualDev->SetLineColor(COL_LIGHTGRAY);
403 pVirtualDev->SetFillColor();
404
405 for (sal_uInt32 i = 0; i < 12; i += 2)
406 {
407 pVirtualDev->SetFillColor(rColorSet.getColor(i));
408 pVirtualDev->DrawRect(tools::Rectangle(x, y1, x + SIZE, y1 + SIZE));
409
410 pVirtualDev->SetFillColor(rColorSet.getColor(i + 1));
411 pVirtualDev->DrawRect(tools::Rectangle(x, y2, x + SIZE, y2 + SIZE));
412
413 x += SIZE + BORDER;
414 if (i == 2 || i == 8)
415 x += BORDER;
416 }
417
418 return pVirtualDev->GetBitmapEx(Point(), aSize);
419}
420
421} // end anonymous namespace
422
423namespace sw::sidebar {
424
425std::unique_ptr<PanelLayout> ThemePanel::Create(weld::Widget* pParent)
426{
427 if (pParent == nullptr)
428 throw css::lang::IllegalArgumentException("no parent Window given to PagePropertyPanel::Create", nullptr, 0);
429
430 return std::make_unique<ThemePanel>(pParent);
431}
432
434 : PanelLayout(pParent, "ThemePanel", "modules/swriter/ui/sidebartheme.ui")
435 , mxListBoxFonts(m_xBuilder->weld_tree_view("listbox_fonts"))
436 , mxValueSetColors(new ValueSet(nullptr))
437 , mxValueSetColorsWin(new weld::CustomWeld(*m_xBuilder, "valueset_colors", *mxValueSetColors))
438 , mxApplyButton(m_xBuilder->weld_button("apply"))
439{
440 mxValueSetColors->SetColCount(2);
441 mxValueSetColors->SetLineCount(3);
442 mxValueSetColors->SetColor(Application::GetSettings().GetStyleSettings().GetFaceColor());
443
444 mxApplyButton->connect_clicked(LINK(this, ThemePanel, ClickHdl));
445 mxListBoxFonts->connect_row_activated(LINK(this, ThemePanel, DoubleClickHdl));
446 mxValueSetColors->SetDoubleClickHdl(LINK(this, ThemePanel, DoubleClickValueSetHdl));
447
448 std::vector<FontSet> aFontSets = initFontSets();
449 for (const FontSet & rFontSet : aFontSets)
450 mxListBoxFonts->append_text(rFontSet.maName);
451 mxListBoxFonts->set_size_request(-1, mxListBoxFonts->get_height_rows(aFontSets.size()));
452
454
455 const std::vector<svx::ColorSet>& aColorSets = maColorSets.getColorSets();
456 for (size_t i = 0; i < aColorSets.size(); ++i)
457 {
458 const svx::ColorSet& rColorSet = aColorSets[i];
459
460 const OUString& aName = rColorSet.getName();
461 BitmapEx aPreview = GenerateColorPreview(rColorSet);
462
463 sal_uInt16 nId = i + 1;
464 mxValueSetColors->InsertItem(nId, Image(aPreview), aName);
465 }
466
467 mxValueSetColors->SetOptimalSize();
468
469 if (!aColorSets.empty())
470 mxValueSetColors->SelectItem(1); // ItemId 1, position 0
471}
472
474{
475 mxListBoxFonts.reset();
476 mxValueSetColorsWin.reset();
477 mxValueSetColors.reset();
478 mxApplyButton.reset();
479}
480
482{
483 DoubleClickHdl();
484}
485
486IMPL_LINK_NOARG(ThemePanel, DoubleClickValueSetHdl, ValueSet*, void)
487{
488 DoubleClickHdl();
489}
490
492{
493 DoubleClickHdl();
494 return true;
495}
496
498{
499 SwDocShell* pDocSh = static_cast<SwDocShell*>(SfxObjectShell::Current());
500 if (!pDocSh)
501 return;
502
503 sal_uInt32 nItemId = mxValueSetColors->GetSelectedItemId();
504 if (!nItemId)
505 return;
506 OUString sEntryFonts = mxListBoxFonts->get_selected_text();
507 sal_uInt32 nIndex = nItemId - 1;
508 OUString sEntryColors = maColorSets.getColorSet(nIndex).getName();
509
510 StyleSet aStyleSet = setupThemes();
511
512 applyTheme(pDocSh->GetStyleSheetPool(), sEntryFonts, sEntryColors, aStyleSet, maColorSets);
513}
514
515void ThemePanel::NotifyItemUpdate(const sal_uInt16 /*nSId*/,
516 const SfxItemState /*eState*/,
517 const SfxPoolItem* /*pState*/)
518{
519}
520
521} // end of namespace ::sw::sidebar
522
523/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
int mnIndex
OUString maName
static OutputDevice * GetDefaultDevice()
static const AllSettings & GetSettings()
void ApplyTintOrShade(sal_Int16 n100thPercent)
const SfxPoolItem * GetItem(sal_uInt16 nWhich, bool bSearchInParent=true) const
static SfxObjectShell * Current()
SfxStyleSheetBase * First(SfxStyleFamily eFamily, SfxStyleSearchBits eMask=SfxStyleSearchBits::All)
SfxStyleSheetBase * Next()
const OUString & GetName() const
Represents the style of a text portion.
Definition: charfmt.hxx:27
virtual SfxStyleSheetBasePool * GetStyleSheetPool() override
For Style PI.
Definition: docsh.cxx:1154
SwCharFormat * GetCharFormat()
Definition: docstyle.cxx:2179
SwTextFormatColl * GetCollection()
Definition: docstyle.cxx:2186
Base class for various Writer styles.
Definition: format.hxx:47
const SvxFontItem & GetFont(bool=true) const
Definition: charatr.hxx:122
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:136
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:449
const SvxColorItem & GetColor(bool=true) const
Definition: charatr.hxx:128
Represents the style of a paragraph.
Definition: fmtcol.hxx:59
virtual bool SetFormatAttr(const SfxPoolItem &rAttr) override
Override to recognize changes on the <SwNumRuleItem> and register/unregister the paragragh style at t...
Definition: fmtcol.cxx:334
const OUString & getName() const
const Color & getColor(sal_uInt32 nIndex) const
const std::vector< ColorSet > & getColorSets() const
const ColorSet & getColorSet(sal_uInt32 nIndex)
std::unique_ptr< weld::TreeView > mxListBoxFonts
Definition: ThemePanel.hxx:35
virtual void NotifyItemUpdate(const sal_uInt16 nSId, const SfxItemState eState, const SfxPoolItem *pState) override
Definition: ThemePanel.cxx:515
virtual ~ThemePanel() override
Definition: ThemePanel.cxx:473
svx::ColorSets maColorSets
Definition: ThemePanel.hxx:43
std::unique_ptr< weld::CustomWeld > mxValueSetColorsWin
Definition: ThemePanel.hxx:40
std::unique_ptr< ValueSet > mxValueSetColors
Definition: ThemePanel.hxx:39
std::unique_ptr< weld::Button > mxApplyButton
Definition: ThemePanel.hxx:41
static std::unique_ptr< PanelLayout > Create(weld::Widget *pParent)
Definition: ThemePanel.cxx:425
ThemePanel(weld::Widget *pParent)
Definition: ThemePanel.cxx:433
void SetFontHeight(tools::Long nHeight)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
#define BORDER
Definition: drpcps.cxx:170
float x
FontPitch
constexpr TypedWhichId< SvxFontItem > RES_CHRATR_FONT(7)
sal_Int32 nIndex
OUString aName
int i
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
IMPL_LINK_NOARG(PageColumnControl, MoreButtonClickHdl_Impl, weld::Button &, void)
long Long
sal_Int16 nId
OUString maElementName
SfxItemState
#define LABEL_HEIGHT