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/.
11 #include <widgetdraw/WidgetDefinitionReader.hxx>
13 #include <sal/config.h>
14 #include <osl/file.hxx>
15 #include <tools/stream.hxx>
16 #include <unordered_map>
22 bool lcl_fileExists(OUString
const& sFilename
)
24 osl::File
aFile(sFilename
);
25 osl::FileBase::RC eRC
= aFile
.open(osl_File_OpenFlag_Read
);
26 return osl::FileBase::E_None
== eRC
;
29 int lcl_gethex(sal_Char aChar
)
31 if (aChar
>= '0' && aChar
<= '9')
33 else if (aChar
>= 'a' && aChar
<= 'f')
34 return aChar
- 'a' + 10;
35 else if (aChar
>= 'A' && aChar
<= 'F')
36 return aChar
- 'A' + 10;
41 bool readColor(OString
const& rString
, Color
& rColor
)
43 if (rString
.getLength() != 7)
46 const sal_Char
aChar(rString
[0]);
51 rColor
.SetRed((lcl_gethex(rString
[1]) << 4) | lcl_gethex(rString
[2]));
52 rColor
.SetGreen((lcl_gethex(rString
[3]) << 4) | lcl_gethex(rString
[4]));
53 rColor
.SetBlue((lcl_gethex(rString
[5]) << 4) | lcl_gethex(rString
[6]));
58 OString
getValueOrAny(OString
const& rInputString
)
60 if (rInputString
.isEmpty())
65 ControlPart
xmlStringToControlPart(OString
const& sPart
)
67 if (sPart
.equalsIgnoreAsciiCase("NONE"))
68 return ControlPart::NONE
;
69 else if (sPart
.equalsIgnoreAsciiCase("Entire"))
70 return ControlPart::Entire
;
71 else if (sPart
.equalsIgnoreAsciiCase("ListboxWindow"))
72 return ControlPart::ListboxWindow
;
73 else if (sPart
.equalsIgnoreAsciiCase("Button"))
74 return ControlPart::Button
;
75 else if (sPart
.equalsIgnoreAsciiCase("ButtonUp"))
76 return ControlPart::ButtonUp
;
77 else if (sPart
.equalsIgnoreAsciiCase("ButtonDown"))
78 return ControlPart::ButtonDown
;
79 else if (sPart
.equalsIgnoreAsciiCase("ButtonLeft"))
80 return ControlPart::ButtonLeft
;
81 else if (sPart
.equalsIgnoreAsciiCase("ButtonRight"))
82 return ControlPart::ButtonRight
;
83 else if (sPart
.equalsIgnoreAsciiCase("AllButtons"))
84 return ControlPart::AllButtons
;
85 else if (sPart
.equalsIgnoreAsciiCase("SeparatorHorz"))
86 return ControlPart::SeparatorHorz
;
87 else if (sPart
.equalsIgnoreAsciiCase("SeparatorVert"))
88 return ControlPart::SeparatorVert
;
89 else if (sPart
.equalsIgnoreAsciiCase("TrackHorzLeft"))
90 return ControlPart::TrackHorzLeft
;
91 else if (sPart
.equalsIgnoreAsciiCase("TrackVertUpper"))
92 return ControlPart::TrackVertUpper
;
93 else if (sPart
.equalsIgnoreAsciiCase("TrackHorzRight"))
94 return ControlPart::TrackHorzRight
;
95 else if (sPart
.equalsIgnoreAsciiCase("TrackVertLower"))
96 return ControlPart::TrackVertLower
;
97 else if (sPart
.equalsIgnoreAsciiCase("TrackHorzArea"))
98 return ControlPart::TrackHorzArea
;
99 else if (sPart
.equalsIgnoreAsciiCase("TrackVertArea"))
100 return ControlPart::TrackVertArea
;
101 else if (sPart
.equalsIgnoreAsciiCase("Arrow"))
102 return ControlPart::Arrow
;
103 else if (sPart
.equalsIgnoreAsciiCase("ThumbHorz"))
104 return ControlPart::ThumbHorz
;
105 else if (sPart
.equalsIgnoreAsciiCase("ThumbVert"))
106 return ControlPart::ThumbVert
;
107 else if (sPart
.equalsIgnoreAsciiCase("MenuItem"))
108 return ControlPart::MenuItem
;
109 else if (sPart
.equalsIgnoreAsciiCase("MenuItemCheckMark"))
110 return ControlPart::MenuItemCheckMark
;
111 else if (sPart
.equalsIgnoreAsciiCase("MenuItemRadioMark"))
112 return ControlPart::MenuItemRadioMark
;
113 else if (sPart
.equalsIgnoreAsciiCase("Separator"))
114 return ControlPart::Separator
;
115 else if (sPart
.equalsIgnoreAsciiCase("SubmenuArrow"))
116 return ControlPart::SubmenuArrow
;
117 else if (sPart
.equalsIgnoreAsciiCase("SubEdit"))
118 return ControlPart::SubEdit
;
119 else if (sPart
.equalsIgnoreAsciiCase("DrawBackgroundHorz"))
120 return ControlPart::DrawBackgroundHorz
;
121 else if (sPart
.equalsIgnoreAsciiCase("DrawBackgroundVert"))
122 return ControlPart::DrawBackgroundVert
;
123 else if (sPart
.equalsIgnoreAsciiCase("TabsDrawRtl"))
124 return ControlPart::TabsDrawRtl
;
125 else if (sPart
.equalsIgnoreAsciiCase("HasBackgroundTexture"))
126 return ControlPart::HasBackgroundTexture
;
127 else if (sPart
.equalsIgnoreAsciiCase("HasThreeButtons"))
128 return ControlPart::HasThreeButtons
;
129 else if (sPart
.equalsIgnoreAsciiCase("BackgroundWindow"))
130 return ControlPart::BackgroundWindow
;
131 else if (sPart
.equalsIgnoreAsciiCase("BackgroundDialog"))
132 return ControlPart::BackgroundDialog
;
133 else if (sPart
.equalsIgnoreAsciiCase("Border"))
134 return ControlPart::Border
;
135 else if (sPart
.equalsIgnoreAsciiCase("Focus"))
136 return ControlPart::Focus
;
137 return ControlPart::NONE
;
140 bool getControlTypeForXmlString(OString
const& rString
, ControlType
& reType
)
142 static std::unordered_map
<OString
, ControlType
> aPartMap
= {
143 { "pushbutton", ControlType::Pushbutton
},
144 { "radiobutton", ControlType::Radiobutton
},
145 { "checkbox", ControlType::Checkbox
},
146 { "combobox", ControlType::Combobox
},
147 { "editbox", ControlType::Editbox
},
148 { "listbox", ControlType::Listbox
},
149 { "scrollbar", ControlType::Scrollbar
},
150 { "spinbox", ControlType::Spinbox
},
151 { "slider", ControlType::Slider
},
152 { "fixedline", ControlType::Fixedline
},
153 { "progress", ControlType::Progress
},
154 { "tabitem", ControlType::TabItem
},
155 { "tabheader", ControlType::TabHeader
},
156 { "tabpane", ControlType::TabPane
},
157 { "tabbody", ControlType::TabBody
},
158 { "frame", ControlType::Frame
},
159 { "windowbackground", ControlType::WindowBackground
},
160 { "toolbar", ControlType::Toolbar
},
161 { "listnode", ControlType::ListNode
},
162 { "listnet", ControlType::ListNet
},
163 { "listheader", ControlType::ListHeader
},
164 { "menubar", ControlType::Menubar
},
165 { "menupopup", ControlType::MenuPopup
},
166 { "tooltip", ControlType::Tooltip
},
169 auto const& rIterator
= aPartMap
.find(rString
);
170 if (rIterator
!= aPartMap
.end())
172 reType
= rIterator
->second
;
178 } // end anonymous namespace
180 WidgetDefinitionReader::WidgetDefinitionReader(OUString
const& rDefinitionFile
,
181 OUString
const& rResourcePath
)
182 : m_rDefinitionFile(rDefinitionFile
)
183 , m_rResourcePath(rResourcePath
)
187 void WidgetDefinitionReader::readDrawingDefinition(
188 tools::XmlWalker
& rWalker
, const std::shared_ptr
<WidgetDefinitionState
>& rpState
)
191 while (rWalker
.isValid())
193 if (rWalker
.name() == "rect")
196 readColor(rWalker
.attribute("stroke"), aStrokeColor
);
198 readColor(rWalker
.attribute("fill"), aFillColor
);
199 OString sStrokeWidth
= rWalker
.attribute("stroke-width");
200 sal_Int32 nStrokeWidth
= -1;
201 if (!sStrokeWidth
.isEmpty())
202 nStrokeWidth
= sStrokeWidth
.toInt32();
205 OString sRx
= rWalker
.attribute("rx");
210 OString sRy
= rWalker
.attribute("ry");
214 OString sX1
= rWalker
.attribute("x1");
215 float fX1
= sX1
.isEmpty() ? 0.0 : sX1
.toFloat();
217 OString sY1
= rWalker
.attribute("y1");
218 float fY1
= sY1
.isEmpty() ? 0.0 : sY1
.toFloat();
220 OString sX2
= rWalker
.attribute("x2");
221 float fX2
= sX2
.isEmpty() ? 1.0 : sX2
.toFloat();
223 OString sY2
= rWalker
.attribute("y2");
224 float fY2
= sY2
.isEmpty() ? 1.0 : sY2
.toFloat();
226 rpState
->addDrawRectangle(aStrokeColor
, nStrokeWidth
, aFillColor
, fX1
, fY1
, fX2
, fY2
,
229 else if (rWalker
.name() == "line")
232 readColor(rWalker
.attribute("stroke"), aStrokeColor
);
234 OString sStrokeWidth
= rWalker
.attribute("stroke-width");
235 sal_Int32 nStrokeWidth
= -1;
236 if (!sStrokeWidth
.isEmpty())
237 nStrokeWidth
= sStrokeWidth
.toInt32();
239 OString sX1
= rWalker
.attribute("x1");
240 float fX1
= sX1
.isEmpty() ? -1.0 : sX1
.toFloat();
242 OString sY1
= rWalker
.attribute("y1");
243 float fY1
= sY1
.isEmpty() ? -1.0 : sY1
.toFloat();
245 OString sX2
= rWalker
.attribute("x2");
246 float fX2
= sX2
.isEmpty() ? -1.0 : sX2
.toFloat();
248 OString sY2
= rWalker
.attribute("y2");
249 float fY2
= sY2
.isEmpty() ? -1.0 : sY2
.toFloat();
251 rpState
->addDrawLine(aStrokeColor
, nStrokeWidth
, fX1
, fY1
, fX2
, fY2
);
253 else if (rWalker
.name() == "image")
255 OString sSource
= rWalker
.attribute("source");
256 rpState
->addDrawImage(m_rResourcePath
257 + OStringToOUString(sSource
, RTL_TEXTENCODING_UTF8
));
259 else if (rWalker
.name() == "external")
261 OString sSource
= rWalker
.attribute("source");
262 rpState
->addDrawExternal(m_rResourcePath
263 + OStringToOUString(sSource
, RTL_TEXTENCODING_UTF8
));
270 void WidgetDefinitionReader::readDefinition(tools::XmlWalker
& rWalker
,
271 WidgetDefinition
& rWidgetDefinition
, ControlType eType
)
274 while (rWalker
.isValid())
276 if (rWalker
.name() == "part")
278 OString sPart
= rWalker
.attribute("value");
279 ControlPart ePart
= xmlStringToControlPart(sPart
);
281 std::shared_ptr
<WidgetDefinitionPart
> pPart
= std::make_shared
<WidgetDefinitionPart
>();
283 OString sWidth
= rWalker
.attribute("width");
284 if (!sWidth
.isEmpty())
286 sal_Int32 nWidth
= sWidth
.isEmpty() ? 0 : sWidth
.toInt32();
287 pPart
->mnWidth
= nWidth
;
290 OString sHeight
= rWalker
.attribute("height");
291 if (!sHeight
.isEmpty())
293 sal_Int32 nHeight
= sHeight
.isEmpty() ? 0 : sHeight
.toInt32();
294 pPart
->mnHeight
= nHeight
;
297 OString sMarginHeight
= rWalker
.attribute("margin-height");
298 if (!sMarginHeight
.isEmpty())
300 sal_Int32 nMarginHeight
= sMarginHeight
.isEmpty() ? 0 : sMarginHeight
.toInt32();
301 pPart
->mnMarginHeight
= nMarginHeight
;
304 OString sMarginWidth
= rWalker
.attribute("margin-width");
305 if (!sMarginWidth
.isEmpty())
307 sal_Int32 nMarginWidth
= sMarginWidth
.isEmpty() ? 0 : sMarginWidth
.toInt32();
308 pPart
->mnMarginWidth
= nMarginWidth
;
311 OString sOrientation
= rWalker
.attribute("orientation");
312 if (!sOrientation
.isEmpty())
314 pPart
->msOrientation
= sOrientation
;
317 rWidgetDefinition
.maDefinitions
.emplace(ControlTypeAndPart(eType
, ePart
), pPart
);
318 readPart(rWalker
, pPart
);
325 void WidgetDefinitionReader::readPart(tools::XmlWalker
& rWalker
,
326 std::shared_ptr
<WidgetDefinitionPart
> rpPart
)
329 while (rWalker
.isValid())
331 if (rWalker
.name() == "state")
333 OString sEnabled
= getValueOrAny(rWalker
.attribute("enabled"));
334 OString sFocused
= getValueOrAny(rWalker
.attribute("focused"));
335 OString sPressed
= getValueOrAny(rWalker
.attribute("pressed"));
336 OString sRollover
= getValueOrAny(rWalker
.attribute("rollover"));
337 OString sDefault
= getValueOrAny(rWalker
.attribute("default"));
338 OString sSelected
= getValueOrAny(rWalker
.attribute("selected"));
339 OString sButtonValue
= getValueOrAny(rWalker
.attribute("button-value"));
340 OString sExtra
= getValueOrAny(rWalker
.attribute("extra"));
342 std::shared_ptr
<WidgetDefinitionState
> pState
= std::make_shared
<WidgetDefinitionState
>(
343 sEnabled
, sFocused
, sPressed
, sRollover
, sDefault
, sSelected
, sButtonValue
, sExtra
);
345 rpPart
->maStates
.push_back(pState
);
346 readDrawingDefinition(rWalker
, pState
);
353 bool WidgetDefinitionReader::read(WidgetDefinition
& rWidgetDefinition
)
355 if (!lcl_fileExists(m_rDefinitionFile
))
358 auto pStyle
= std::make_shared
<WidgetDefinitionStyle
>();
360 std::unordered_map
<OString
, Color
*> aStyleColorMap
= {
361 { "faceColor", &pStyle
->maFaceColor
},
362 { "checkedColor", &pStyle
->maCheckedColor
},
363 { "lightColor", &pStyle
->maLightColor
},
364 { "lightBorderColor", &pStyle
->maLightBorderColor
},
365 { "shadowColor", &pStyle
->maShadowColor
},
366 { "darkShadowColor", &pStyle
->maDarkShadowColor
},
367 { "buttonTextColor", &pStyle
->maButtonTextColor
},
368 { "defaultActionButtonTextColor", &pStyle
->maDefaultActionButtonTextColor
},
369 { "actionButtonTextColor", &pStyle
->maActionButtonTextColor
},
370 { "actionButtonRolloverTextColor", &pStyle
->maActionButtonRolloverTextColor
},
371 { "buttonRolloverTextColor", &pStyle
->maButtonRolloverTextColor
},
372 { "radioCheckTextColor", &pStyle
->maRadioCheckTextColor
},
373 { "groupTextColor", &pStyle
->maGroupTextColor
},
374 { "labelTextColor", &pStyle
->maLabelTextColor
},
375 { "windowColor", &pStyle
->maWindowColor
},
376 { "windowTextColor", &pStyle
->maWindowTextColor
},
377 { "dialogColor", &pStyle
->maDialogColor
},
378 { "dialogTextColor", &pStyle
->maDialogTextColor
},
379 { "workspaceColor", &pStyle
->maWorkspaceColor
},
380 { "monoColor", &pStyle
->maMonoColor
},
381 { "fieldColor", &pStyle
->maFieldColor
},
382 { "fieldTextColor", &pStyle
->maFieldTextColor
},
383 { "fieldRolloverTextColor", &pStyle
->maFieldRolloverTextColor
},
384 { "activeColor", &pStyle
->maActiveColor
},
385 { "activeTextColor", &pStyle
->maActiveTextColor
},
386 { "activeBorderColor", &pStyle
->maActiveBorderColor
},
387 { "deactiveColor", &pStyle
->maDeactiveColor
},
388 { "deactiveTextColor", &pStyle
->maDeactiveTextColor
},
389 { "deactiveBorderColor", &pStyle
->maDeactiveBorderColor
},
390 { "menuColor", &pStyle
->maMenuColor
},
391 { "menuBarColor", &pStyle
->maMenuBarColor
},
392 { "menuBarRolloverColor", &pStyle
->maMenuBarRolloverColor
},
393 { "menuBorderColor", &pStyle
->maMenuBorderColor
},
394 { "menuTextColor", &pStyle
->maMenuTextColor
},
395 { "menuBarTextColor", &pStyle
->maMenuBarTextColor
},
396 { "menuBarRolloverTextColor", &pStyle
->maMenuBarRolloverTextColor
},
397 { "menuBarHighlightTextColor", &pStyle
->maMenuBarHighlightTextColor
},
398 { "menuHighlightColor", &pStyle
->maMenuHighlightColor
},
399 { "menuHighlightTextColor", &pStyle
->maMenuHighlightTextColor
},
400 { "highlightColor", &pStyle
->maHighlightColor
},
401 { "highlightTextColor", &pStyle
->maHighlightTextColor
},
402 { "activeTabColor", &pStyle
->maActiveTabColor
},
403 { "inactiveTabColor", &pStyle
->maInactiveTabColor
},
404 { "tabTextColor", &pStyle
->maTabTextColor
},
405 { "tabRolloverTextColor", &pStyle
->maTabRolloverTextColor
},
406 { "tabHighlightTextColor", &pStyle
->maTabHighlightTextColor
},
407 { "disableColor", &pStyle
->maDisableColor
},
408 { "helpColor", &pStyle
->maHelpColor
},
409 { "helpTextColor", &pStyle
->maHelpTextColor
},
410 { "linkColor", &pStyle
->maLinkColor
},
411 { "visitedLinkColor", &pStyle
->maVisitedLinkColor
},
412 { "toolTextColor", &pStyle
->maToolTextColor
},
413 { "fontColor", &pStyle
->maFontColor
},
415 rWidgetDefinition
.mpStyle
= pStyle
;
417 SvFileStream
aFileStream(m_rDefinitionFile
, StreamMode::READ
);
419 tools::XmlWalker aWalker
;
420 if (!aWalker
.open(&aFileStream
))
423 if (aWalker
.name() != "widgets")
427 while (aWalker
.isValid())
430 if (aWalker
.name() == "style")
433 while (aWalker
.isValid())
435 auto pair
= aStyleColorMap
.find(aWalker
.name());
436 if (pair
!= aStyleColorMap
.end())
438 readColor(aWalker
.attribute("value"), *pair
->second
);
444 else if (getControlTypeForXmlString(aWalker
.name(), eType
))
446 readDefinition(aWalker
, rWidgetDefinition
, eType
);
455 } // end vcl namespace
457 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */