1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
12 #include <widgetdraw/WidgetDefinitionReader.hxx>
14 #include <sal/config.h>
15 #include <osl/file.hxx>
16 #include <tools/stream.hxx>
17 #include <o3tl/string_view.hxx>
18 #include <unordered_map>
24 bool lcl_fileExists(OUString
const& sFilename
)
26 osl::File
aFile(sFilename
);
27 osl::FileBase::RC eRC
= aFile
.open(osl_File_OpenFlag_Read
);
28 return osl::FileBase::E_None
== eRC
;
31 int lcl_gethex(char aChar
)
33 if (aChar
>= '0' && aChar
<= '9')
35 else if (aChar
>= 'a' && aChar
<= 'f')
36 return aChar
- 'a' + 10;
37 else if (aChar
>= 'A' && aChar
<= 'F')
38 return aChar
- 'A' + 10;
43 bool readColor(OString
const& rString
, Color
& rColor
)
45 if (rString
.getLength() != 7)
48 const char aChar(rString
[0]);
53 rColor
.SetRed((lcl_gethex(rString
[1]) << 4) | lcl_gethex(rString
[2]));
54 rColor
.SetGreen((lcl_gethex(rString
[3]) << 4) | lcl_gethex(rString
[4]));
55 rColor
.SetBlue((lcl_gethex(rString
[5]) << 4) | lcl_gethex(rString
[6]));
60 bool readSetting(OString
const& rInputString
, OString
& rOutputString
)
62 if (!rInputString
.isEmpty())
63 rOutputString
= rInputString
;
67 OString
getValueOrAny(OString
const& rInputString
)
69 if (rInputString
.isEmpty())
74 ControlPart
xmlStringToControlPart(std::string_view sPart
)
76 if (o3tl::equalsIgnoreAsciiCase(sPart
, "NONE"))
77 return ControlPart::NONE
;
78 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "Entire"))
79 return ControlPart::Entire
;
80 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "ListboxWindow"))
81 return ControlPart::ListboxWindow
;
82 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "Button"))
83 return ControlPart::Button
;
84 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "ButtonUp"))
85 return ControlPart::ButtonUp
;
86 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "ButtonDown"))
87 return ControlPart::ButtonDown
;
88 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "ButtonLeft"))
89 return ControlPart::ButtonLeft
;
90 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "ButtonRight"))
91 return ControlPart::ButtonRight
;
92 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "AllButtons"))
93 return ControlPart::AllButtons
;
94 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "SeparatorHorz"))
95 return ControlPart::SeparatorHorz
;
96 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "SeparatorVert"))
97 return ControlPart::SeparatorVert
;
98 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "TrackHorzLeft"))
99 return ControlPart::TrackHorzLeft
;
100 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "TrackVertUpper"))
101 return ControlPart::TrackVertUpper
;
102 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "TrackHorzRight"))
103 return ControlPart::TrackHorzRight
;
104 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "TrackVertLower"))
105 return ControlPart::TrackVertLower
;
106 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "TrackHorzArea"))
107 return ControlPart::TrackHorzArea
;
108 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "TrackVertArea"))
109 return ControlPart::TrackVertArea
;
110 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "Arrow"))
111 return ControlPart::Arrow
;
112 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "ThumbHorz"))
113 return ControlPart::ThumbHorz
;
114 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "ThumbVert"))
115 return ControlPart::ThumbVert
;
116 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "MenuItem"))
117 return ControlPart::MenuItem
;
118 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "MenuItemCheckMark"))
119 return ControlPart::MenuItemCheckMark
;
120 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "MenuItemRadioMark"))
121 return ControlPart::MenuItemRadioMark
;
122 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "Separator"))
123 return ControlPart::Separator
;
124 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "SubmenuArrow"))
125 return ControlPart::SubmenuArrow
;
126 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "SubEdit"))
127 return ControlPart::SubEdit
;
128 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "DrawBackgroundHorz"))
129 return ControlPart::DrawBackgroundHorz
;
130 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "DrawBackgroundVert"))
131 return ControlPart::DrawBackgroundVert
;
132 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "TabsDrawRtl"))
133 return ControlPart::TabsDrawRtl
;
134 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "HasBackgroundTexture"))
135 return ControlPart::HasBackgroundTexture
;
136 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "HasThreeButtons"))
137 return ControlPart::HasThreeButtons
;
138 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "BackgroundWindow"))
139 return ControlPart::BackgroundWindow
;
140 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "BackgroundDialog"))
141 return ControlPart::BackgroundDialog
;
142 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "Border"))
143 return ControlPart::Border
;
144 else if (o3tl::equalsIgnoreAsciiCase(sPart
, "Focus"))
145 return ControlPart::Focus
;
146 return ControlPart::NONE
;
149 bool getControlTypeForXmlString(OString
const& rString
, ControlType
& reType
)
151 static std::unordered_map
<OString
, ControlType
> aPartMap
= {
152 { "pushbutton", ControlType::Pushbutton
},
153 { "radiobutton", ControlType::Radiobutton
},
154 { "checkbox", ControlType::Checkbox
},
155 { "combobox", ControlType::Combobox
},
156 { "editbox", ControlType::Editbox
},
157 { "listbox", ControlType::Listbox
},
158 { "scrollbar", ControlType::Scrollbar
},
159 { "spinbox", ControlType::Spinbox
},
160 { "slider", ControlType::Slider
},
161 { "fixedline", ControlType::Fixedline
},
162 { "progress", ControlType::Progress
},
163 { "tabitem", ControlType::TabItem
},
164 { "tabheader", ControlType::TabHeader
},
165 { "tabpane", ControlType::TabPane
},
166 { "tabbody", ControlType::TabBody
},
167 { "frame", ControlType::Frame
},
168 { "windowbackground", ControlType::WindowBackground
},
169 { "toolbar", ControlType::Toolbar
},
170 { "listnode", ControlType::ListNode
},
171 { "listnet", ControlType::ListNet
},
172 { "listheader", ControlType::ListHeader
},
173 { "menubar", ControlType::Menubar
},
174 { "menupopup", ControlType::MenuPopup
},
175 { "tooltip", ControlType::Tooltip
},
178 auto const& rIterator
= aPartMap
.find(rString
);
179 if (rIterator
!= aPartMap
.end())
181 reType
= rIterator
->second
;
187 } // end anonymous namespace
189 WidgetDefinitionReader::WidgetDefinitionReader(OUString aDefinitionFile
, OUString aResourcePath
)
190 : m_rDefinitionFile(std::move(aDefinitionFile
))
191 , m_rResourcePath(std::move(aResourcePath
))
195 void WidgetDefinitionReader::readDrawingDefinition(
196 tools::XmlWalker
& rWalker
, const std::shared_ptr
<WidgetDefinitionState
>& rpState
)
199 while (rWalker
.isValid())
201 if (rWalker
.name() == "rect")
204 readColor(rWalker
.attribute("stroke"), aStrokeColor
);
206 readColor(rWalker
.attribute("fill"), aFillColor
);
207 OString sStrokeWidth
= rWalker
.attribute("stroke-width");
208 sal_Int32 nStrokeWidth
= -1;
209 if (!sStrokeWidth
.isEmpty())
210 nStrokeWidth
= sStrokeWidth
.toInt32();
213 OString sRx
= rWalker
.attribute("rx");
218 OString sRy
= rWalker
.attribute("ry");
222 OString sX1
= rWalker
.attribute("x1");
223 float fX1
= sX1
.isEmpty() ? 0.0 : sX1
.toFloat();
225 OString sY1
= rWalker
.attribute("y1");
226 float fY1
= sY1
.isEmpty() ? 0.0 : sY1
.toFloat();
228 OString sX2
= rWalker
.attribute("x2");
229 float fX2
= sX2
.isEmpty() ? 1.0 : sX2
.toFloat();
231 OString sY2
= rWalker
.attribute("y2");
232 float fY2
= sY2
.isEmpty() ? 1.0 : sY2
.toFloat();
234 rpState
->addDrawRectangle(aStrokeColor
, nStrokeWidth
, aFillColor
, fX1
, fY1
, fX2
, fY2
,
237 else if (rWalker
.name() == "line")
240 readColor(rWalker
.attribute("stroke"), aStrokeColor
);
242 OString sStrokeWidth
= rWalker
.attribute("stroke-width");
243 sal_Int32 nStrokeWidth
= -1;
244 if (!sStrokeWidth
.isEmpty())
245 nStrokeWidth
= sStrokeWidth
.toInt32();
247 OString sX1
= rWalker
.attribute("x1");
248 float fX1
= sX1
.isEmpty() ? -1.0 : sX1
.toFloat();
250 OString sY1
= rWalker
.attribute("y1");
251 float fY1
= sY1
.isEmpty() ? -1.0 : sY1
.toFloat();
253 OString sX2
= rWalker
.attribute("x2");
254 float fX2
= sX2
.isEmpty() ? -1.0 : sX2
.toFloat();
256 OString sY2
= rWalker
.attribute("y2");
257 float fY2
= sY2
.isEmpty() ? -1.0 : sY2
.toFloat();
259 rpState
->addDrawLine(aStrokeColor
, nStrokeWidth
, fX1
, fY1
, fX2
, fY2
);
261 else if (rWalker
.name() == "image")
263 OString sSource
= rWalker
.attribute("source");
264 rpState
->addDrawImage(m_rResourcePath
265 + OStringToOUString(sSource
, RTL_TEXTENCODING_UTF8
));
267 else if (rWalker
.name() == "external")
269 OString sSource
= rWalker
.attribute("source");
270 rpState
->addDrawExternal(m_rResourcePath
271 + OStringToOUString(sSource
, RTL_TEXTENCODING_UTF8
));
278 void WidgetDefinitionReader::readDefinition(tools::XmlWalker
& rWalker
,
279 WidgetDefinition
& rWidgetDefinition
, ControlType eType
)
282 while (rWalker
.isValid())
284 if (rWalker
.name() == "part")
286 OString sPart
= rWalker
.attribute("value");
287 ControlPart ePart
= xmlStringToControlPart(sPart
);
289 std::shared_ptr
<WidgetDefinitionPart
> pPart
= std::make_shared
<WidgetDefinitionPart
>();
291 OString sWidth
= rWalker
.attribute("width");
292 if (!sWidth
.isEmpty())
294 sal_Int32 nWidth
= sWidth
.isEmpty() ? 0 : sWidth
.toInt32();
295 pPart
->mnWidth
= nWidth
;
298 OString sHeight
= rWalker
.attribute("height");
299 if (!sHeight
.isEmpty())
301 sal_Int32 nHeight
= sHeight
.isEmpty() ? 0 : sHeight
.toInt32();
302 pPart
->mnHeight
= nHeight
;
305 OString sMarginHeight
= rWalker
.attribute("margin-height");
306 if (!sMarginHeight
.isEmpty())
308 sal_Int32 nMarginHeight
= sMarginHeight
.isEmpty() ? 0 : sMarginHeight
.toInt32();
309 pPart
->mnMarginHeight
= nMarginHeight
;
312 OString sMarginWidth
= rWalker
.attribute("margin-width");
313 if (!sMarginWidth
.isEmpty())
315 sal_Int32 nMarginWidth
= sMarginWidth
.isEmpty() ? 0 : sMarginWidth
.toInt32();
316 pPart
->mnMarginWidth
= nMarginWidth
;
319 OString sOrientation
= rWalker
.attribute("orientation");
320 if (!sOrientation
.isEmpty())
322 pPart
->msOrientation
= sOrientation
;
325 rWidgetDefinition
.maDefinitions
.emplace(ControlTypeAndPart(eType
, ePart
), pPart
);
326 readPart(rWalker
, pPart
);
333 void WidgetDefinitionReader::readPart(tools::XmlWalker
& rWalker
,
334 std::shared_ptr
<WidgetDefinitionPart
> rpPart
)
337 while (rWalker
.isValid())
339 if (rWalker
.name() == "state")
341 OString sEnabled
= getValueOrAny(rWalker
.attribute("enabled"));
342 OString sFocused
= getValueOrAny(rWalker
.attribute("focused"));
343 OString sPressed
= getValueOrAny(rWalker
.attribute("pressed"));
344 OString sRollover
= getValueOrAny(rWalker
.attribute("rollover"));
345 OString sDefault
= getValueOrAny(rWalker
.attribute("default"));
346 OString sSelected
= getValueOrAny(rWalker
.attribute("selected"));
347 OString sButtonValue
= getValueOrAny(rWalker
.attribute("button-value"));
348 OString sExtra
= getValueOrAny(rWalker
.attribute("extra"));
350 std::shared_ptr
<WidgetDefinitionState
> pState
= std::make_shared
<WidgetDefinitionState
>(
351 sEnabled
, sFocused
, sPressed
, sRollover
, sDefault
, sSelected
, sButtonValue
, sExtra
);
353 rpPart
->maStates
.push_back(pState
);
354 readDrawingDefinition(rWalker
, pState
);
361 bool WidgetDefinitionReader::read(WidgetDefinition
& rWidgetDefinition
)
363 if (!lcl_fileExists(m_rDefinitionFile
))
366 auto pStyle
= std::make_shared
<WidgetDefinitionStyle
>();
368 std::unordered_map
<OString
, Color
*> aStyleColorMap
= {
369 { "faceColor", &pStyle
->maFaceColor
},
370 { "checkedColor", &pStyle
->maCheckedColor
},
371 { "lightColor", &pStyle
->maLightColor
},
372 { "lightBorderColor", &pStyle
->maLightBorderColor
},
373 { "shadowColor", &pStyle
->maShadowColor
},
374 { "darkShadowColor", &pStyle
->maDarkShadowColor
},
375 { "buttonTextColor", &pStyle
->maButtonTextColor
},
376 { "defaultActionButtonTextColor", &pStyle
->maDefaultActionButtonTextColor
},
377 { "actionButtonTextColor", &pStyle
->maActionButtonTextColor
},
378 { "actionButtonRolloverTextColor", &pStyle
->maActionButtonRolloverTextColor
},
379 { "buttonRolloverTextColor", &pStyle
->maButtonRolloverTextColor
},
380 { "radioCheckTextColor", &pStyle
->maRadioCheckTextColor
},
381 { "groupTextColor", &pStyle
->maGroupTextColor
},
382 { "labelTextColor", &pStyle
->maLabelTextColor
},
383 { "windowColor", &pStyle
->maWindowColor
},
384 { "windowTextColor", &pStyle
->maWindowTextColor
},
385 { "dialogColor", &pStyle
->maDialogColor
},
386 { "dialogTextColor", &pStyle
->maDialogTextColor
},
387 { "workspaceColor", &pStyle
->maWorkspaceColor
},
388 { "monoColor", &pStyle
->maMonoColor
},
389 { "fieldColor", &pStyle
->maFieldColor
},
390 { "fieldTextColor", &pStyle
->maFieldTextColor
},
391 { "fieldRolloverTextColor", &pStyle
->maFieldRolloverTextColor
},
392 { "activeColor", &pStyle
->maActiveColor
},
393 { "activeTextColor", &pStyle
->maActiveTextColor
},
394 { "activeBorderColor", &pStyle
->maActiveBorderColor
},
395 { "deactiveColor", &pStyle
->maDeactiveColor
},
396 { "deactiveTextColor", &pStyle
->maDeactiveTextColor
},
397 { "deactiveBorderColor", &pStyle
->maDeactiveBorderColor
},
398 { "menuColor", &pStyle
->maMenuColor
},
399 { "menuBarColor", &pStyle
->maMenuBarColor
},
400 { "menuBarRolloverColor", &pStyle
->maMenuBarRolloverColor
},
401 { "menuBorderColor", &pStyle
->maMenuBorderColor
},
402 { "menuTextColor", &pStyle
->maMenuTextColor
},
403 { "menuBarTextColor", &pStyle
->maMenuBarTextColor
},
404 { "menuBarRolloverTextColor", &pStyle
->maMenuBarRolloverTextColor
},
405 { "menuBarHighlightTextColor", &pStyle
->maMenuBarHighlightTextColor
},
406 { "menuHighlightColor", &pStyle
->maMenuHighlightColor
},
407 { "menuHighlightTextColor", &pStyle
->maMenuHighlightTextColor
},
408 { "highlightColor", &pStyle
->maHighlightColor
},
409 { "highlightTextColor", &pStyle
->maHighlightTextColor
},
410 { "activeTabColor", &pStyle
->maActiveTabColor
},
411 { "inactiveTabColor", &pStyle
->maInactiveTabColor
},
412 { "tabTextColor", &pStyle
->maTabTextColor
},
413 { "tabRolloverTextColor", &pStyle
->maTabRolloverTextColor
},
414 { "tabHighlightTextColor", &pStyle
->maTabHighlightTextColor
},
415 { "disableColor", &pStyle
->maDisableColor
},
416 { "helpColor", &pStyle
->maHelpColor
},
417 { "helpTextColor", &pStyle
->maHelpTextColor
},
418 { "linkColor", &pStyle
->maLinkColor
},
419 { "visitedLinkColor", &pStyle
->maVisitedLinkColor
},
420 { "toolTextColor", &pStyle
->maToolTextColor
},
423 rWidgetDefinition
.mpStyle
= pStyle
;
425 auto pSettings
= std::make_shared
<WidgetDefinitionSettings
>();
427 std::unordered_map
<OString
, OString
*> aSettingMap
= {
428 { "noActiveTabTextRaise", &pSettings
->msNoActiveTabTextRaise
},
429 { "centeredTabs", &pSettings
->msCenteredTabs
},
430 { "listBoxEntryMargin", &pSettings
->msListBoxEntryMargin
},
431 { "defaultFontSize", &pSettings
->msDefaultFontSize
},
432 { "titleHeight", &pSettings
->msTitleHeight
},
433 { "floatTitleHeight", &pSettings
->msFloatTitleHeight
},
434 { "listBoxPreviewDefaultLogicWidth", &pSettings
->msListBoxPreviewDefaultLogicWidth
},
435 { "listBoxPreviewDefaultLogicHeight", &pSettings
->msListBoxPreviewDefaultLogicHeight
},
438 rWidgetDefinition
.mpSettings
= pSettings
;
440 SvFileStream
aFileStream(m_rDefinitionFile
, StreamMode::READ
);
442 tools::XmlWalker aWalker
;
443 if (!aWalker
.open(&aFileStream
))
446 if (aWalker
.name() != "widgets")
450 while (aWalker
.isValid())
453 if (aWalker
.name() == "style")
456 while (aWalker
.isValid())
458 auto pair
= aStyleColorMap
.find(aWalker
.name());
459 if (pair
!= aStyleColorMap
.end())
461 readColor(aWalker
.attribute("value"), *pair
->second
);
467 if (aWalker
.name() == "settings")
470 while (aWalker
.isValid())
472 auto pair
= aSettingMap
.find(aWalker
.name());
473 if (pair
!= aSettingMap
.end())
475 readSetting(aWalker
.attribute("value"), *pair
->second
);
481 else if (getControlTypeForXmlString(aWalker
.name(), eType
))
483 readDefinition(aWalker
, rWidgetDefinition
, eType
);
492 } // end vcl namespace
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */