summaryrefslogtreecommitdiffstats
path: root/vcl/source/gdi/WidgetDefinitionReader.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/gdi/WidgetDefinitionReader.cxx')
-rw-r--r--vcl/source/gdi/WidgetDefinitionReader.cxx495
1 files changed, 495 insertions, 0 deletions
diff --git a/vcl/source/gdi/WidgetDefinitionReader.cxx b/vcl/source/gdi/WidgetDefinitionReader.cxx
new file mode 100644
index 000000000..4f68c35e4
--- /dev/null
+++ b/vcl/source/gdi/WidgetDefinitionReader.cxx
@@ -0,0 +1,495 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <widgetdraw/WidgetDefinitionReader.hxx>
+
+#include <sal/config.h>
+#include <osl/file.hxx>
+#include <tools/stream.hxx>
+#include <o3tl/string_view.hxx>
+#include <unordered_map>
+
+namespace vcl
+{
+namespace
+{
+bool lcl_fileExists(OUString const& sFilename)
+{
+ osl::File aFile(sFilename);
+ osl::FileBase::RC eRC = aFile.open(osl_File_OpenFlag_Read);
+ return osl::FileBase::E_None == eRC;
+}
+
+int lcl_gethex(char aChar)
+{
+ if (aChar >= '0' && aChar <= '9')
+ return aChar - '0';
+ else if (aChar >= 'a' && aChar <= 'f')
+ return aChar - 'a' + 10;
+ else if (aChar >= 'A' && aChar <= 'F')
+ return aChar - 'A' + 10;
+ else
+ return 0;
+}
+
+bool readColor(OString const& rString, Color& rColor)
+{
+ if (rString.getLength() != 7)
+ return false;
+
+ const char aChar(rString[0]);
+
+ if (aChar != '#')
+ return false;
+
+ rColor.SetRed((lcl_gethex(rString[1]) << 4) | lcl_gethex(rString[2]));
+ rColor.SetGreen((lcl_gethex(rString[3]) << 4) | lcl_gethex(rString[4]));
+ rColor.SetBlue((lcl_gethex(rString[5]) << 4) | lcl_gethex(rString[6]));
+
+ return true;
+}
+
+bool readSetting(OString const& rInputString, OString& rOutputString)
+{
+ if (!rInputString.isEmpty())
+ rOutputString = rInputString;
+ return true;
+}
+
+OString getValueOrAny(OString const& rInputString)
+{
+ if (rInputString.isEmpty())
+ return "any";
+ return rInputString;
+}
+
+ControlPart xmlStringToControlPart(std::string_view sPart)
+{
+ if (o3tl::equalsIgnoreAsciiCase(sPart, "NONE"))
+ return ControlPart::NONE;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "Entire"))
+ return ControlPart::Entire;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "ListboxWindow"))
+ return ControlPart::ListboxWindow;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "Button"))
+ return ControlPart::Button;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "ButtonUp"))
+ return ControlPart::ButtonUp;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "ButtonDown"))
+ return ControlPart::ButtonDown;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "ButtonLeft"))
+ return ControlPart::ButtonLeft;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "ButtonRight"))
+ return ControlPart::ButtonRight;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "AllButtons"))
+ return ControlPart::AllButtons;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "SeparatorHorz"))
+ return ControlPart::SeparatorHorz;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "SeparatorVert"))
+ return ControlPart::SeparatorVert;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackHorzLeft"))
+ return ControlPart::TrackHorzLeft;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackVertUpper"))
+ return ControlPart::TrackVertUpper;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackHorzRight"))
+ return ControlPart::TrackHorzRight;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackVertLower"))
+ return ControlPart::TrackVertLower;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackHorzArea"))
+ return ControlPart::TrackHorzArea;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackVertArea"))
+ return ControlPart::TrackVertArea;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "Arrow"))
+ return ControlPart::Arrow;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "ThumbHorz"))
+ return ControlPart::ThumbHorz;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "ThumbVert"))
+ return ControlPart::ThumbVert;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "MenuItem"))
+ return ControlPart::MenuItem;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "MenuItemCheckMark"))
+ return ControlPart::MenuItemCheckMark;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "MenuItemRadioMark"))
+ return ControlPart::MenuItemRadioMark;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "Separator"))
+ return ControlPart::Separator;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "SubmenuArrow"))
+ return ControlPart::SubmenuArrow;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "SubEdit"))
+ return ControlPart::SubEdit;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "DrawBackgroundHorz"))
+ return ControlPart::DrawBackgroundHorz;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "DrawBackgroundVert"))
+ return ControlPart::DrawBackgroundVert;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "TabsDrawRtl"))
+ return ControlPart::TabsDrawRtl;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "HasBackgroundTexture"))
+ return ControlPart::HasBackgroundTexture;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "HasThreeButtons"))
+ return ControlPart::HasThreeButtons;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "BackgroundWindow"))
+ return ControlPart::BackgroundWindow;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "BackgroundDialog"))
+ return ControlPart::BackgroundDialog;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "Border"))
+ return ControlPart::Border;
+ else if (o3tl::equalsIgnoreAsciiCase(sPart, "Focus"))
+ return ControlPart::Focus;
+ return ControlPart::NONE;
+}
+
+bool getControlTypeForXmlString(OString const& rString, ControlType& reType)
+{
+ static std::unordered_map<OString, ControlType> aPartMap = {
+ { "pushbutton", ControlType::Pushbutton },
+ { "radiobutton", ControlType::Radiobutton },
+ { "checkbox", ControlType::Checkbox },
+ { "combobox", ControlType::Combobox },
+ { "editbox", ControlType::Editbox },
+ { "listbox", ControlType::Listbox },
+ { "scrollbar", ControlType::Scrollbar },
+ { "spinbox", ControlType::Spinbox },
+ { "slider", ControlType::Slider },
+ { "fixedline", ControlType::Fixedline },
+ { "progress", ControlType::Progress },
+ { "tabitem", ControlType::TabItem },
+ { "tabheader", ControlType::TabHeader },
+ { "tabpane", ControlType::TabPane },
+ { "tabbody", ControlType::TabBody },
+ { "frame", ControlType::Frame },
+ { "windowbackground", ControlType::WindowBackground },
+ { "toolbar", ControlType::Toolbar },
+ { "listnode", ControlType::ListNode },
+ { "listnet", ControlType::ListNet },
+ { "listheader", ControlType::ListHeader },
+ { "menubar", ControlType::Menubar },
+ { "menupopup", ControlType::MenuPopup },
+ { "tooltip", ControlType::Tooltip },
+ };
+
+ auto const& rIterator = aPartMap.find(rString);
+ if (rIterator != aPartMap.end())
+ {
+ reType = rIterator->second;
+ return true;
+ }
+ return false;
+}
+
+} // end anonymous namespace
+
+WidgetDefinitionReader::WidgetDefinitionReader(OUString const& rDefinitionFile,
+ OUString const& rResourcePath)
+ : m_rDefinitionFile(rDefinitionFile)
+ , m_rResourcePath(rResourcePath)
+{
+}
+
+void WidgetDefinitionReader::readDrawingDefinition(
+ tools::XmlWalker& rWalker, const std::shared_ptr<WidgetDefinitionState>& rpState)
+{
+ rWalker.children();
+ while (rWalker.isValid())
+ {
+ if (rWalker.name() == "rect")
+ {
+ Color aStrokeColor;
+ readColor(rWalker.attribute("stroke"), aStrokeColor);
+ Color aFillColor;
+ readColor(rWalker.attribute("fill"), aFillColor);
+ OString sStrokeWidth = rWalker.attribute("stroke-width");
+ sal_Int32 nStrokeWidth = -1;
+ if (!sStrokeWidth.isEmpty())
+ nStrokeWidth = sStrokeWidth.toInt32();
+
+ sal_Int32 nRx = -1;
+ OString sRx = rWalker.attribute("rx");
+ if (!sRx.isEmpty())
+ nRx = sRx.toInt32();
+
+ sal_Int32 nRy = -1;
+ OString sRy = rWalker.attribute("ry");
+ if (!sRy.isEmpty())
+ nRy = sRy.toInt32();
+
+ OString sX1 = rWalker.attribute("x1");
+ float fX1 = sX1.isEmpty() ? 0.0 : sX1.toFloat();
+
+ OString sY1 = rWalker.attribute("y1");
+ float fY1 = sY1.isEmpty() ? 0.0 : sY1.toFloat();
+
+ OString sX2 = rWalker.attribute("x2");
+ float fX2 = sX2.isEmpty() ? 1.0 : sX2.toFloat();
+
+ OString sY2 = rWalker.attribute("y2");
+ float fY2 = sY2.isEmpty() ? 1.0 : sY2.toFloat();
+
+ rpState->addDrawRectangle(aStrokeColor, nStrokeWidth, aFillColor, fX1, fY1, fX2, fY2,
+ nRx, nRy);
+ }
+ else if (rWalker.name() == "line")
+ {
+ Color aStrokeColor;
+ readColor(rWalker.attribute("stroke"), aStrokeColor);
+
+ OString sStrokeWidth = rWalker.attribute("stroke-width");
+ sal_Int32 nStrokeWidth = -1;
+ if (!sStrokeWidth.isEmpty())
+ nStrokeWidth = sStrokeWidth.toInt32();
+
+ OString sX1 = rWalker.attribute("x1");
+ float fX1 = sX1.isEmpty() ? -1.0 : sX1.toFloat();
+
+ OString sY1 = rWalker.attribute("y1");
+ float fY1 = sY1.isEmpty() ? -1.0 : sY1.toFloat();
+
+ OString sX2 = rWalker.attribute("x2");
+ float fX2 = sX2.isEmpty() ? -1.0 : sX2.toFloat();
+
+ OString sY2 = rWalker.attribute("y2");
+ float fY2 = sY2.isEmpty() ? -1.0 : sY2.toFloat();
+
+ rpState->addDrawLine(aStrokeColor, nStrokeWidth, fX1, fY1, fX2, fY2);
+ }
+ else if (rWalker.name() == "image")
+ {
+ OString sSource = rWalker.attribute("source");
+ rpState->addDrawImage(m_rResourcePath
+ + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8));
+ }
+ else if (rWalker.name() == "external")
+ {
+ OString sSource = rWalker.attribute("source");
+ rpState->addDrawExternal(m_rResourcePath
+ + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8));
+ }
+ rWalker.next();
+ }
+ rWalker.parent();
+}
+
+void WidgetDefinitionReader::readDefinition(tools::XmlWalker& rWalker,
+ WidgetDefinition& rWidgetDefinition, ControlType eType)
+{
+ rWalker.children();
+ while (rWalker.isValid())
+ {
+ if (rWalker.name() == "part")
+ {
+ OString sPart = rWalker.attribute("value");
+ ControlPart ePart = xmlStringToControlPart(sPart);
+
+ std::shared_ptr<WidgetDefinitionPart> pPart = std::make_shared<WidgetDefinitionPart>();
+
+ OString sWidth = rWalker.attribute("width");
+ if (!sWidth.isEmpty())
+ {
+ sal_Int32 nWidth = sWidth.isEmpty() ? 0 : sWidth.toInt32();
+ pPart->mnWidth = nWidth;
+ }
+
+ OString sHeight = rWalker.attribute("height");
+ if (!sHeight.isEmpty())
+ {
+ sal_Int32 nHeight = sHeight.isEmpty() ? 0 : sHeight.toInt32();
+ pPart->mnHeight = nHeight;
+ }
+
+ OString sMarginHeight = rWalker.attribute("margin-height");
+ if (!sMarginHeight.isEmpty())
+ {
+ sal_Int32 nMarginHeight = sMarginHeight.isEmpty() ? 0 : sMarginHeight.toInt32();
+ pPart->mnMarginHeight = nMarginHeight;
+ }
+
+ OString sMarginWidth = rWalker.attribute("margin-width");
+ if (!sMarginWidth.isEmpty())
+ {
+ sal_Int32 nMarginWidth = sMarginWidth.isEmpty() ? 0 : sMarginWidth.toInt32();
+ pPart->mnMarginWidth = nMarginWidth;
+ }
+
+ OString sOrientation = rWalker.attribute("orientation");
+ if (!sOrientation.isEmpty())
+ {
+ pPart->msOrientation = sOrientation;
+ }
+
+ rWidgetDefinition.maDefinitions.emplace(ControlTypeAndPart(eType, ePart), pPart);
+ readPart(rWalker, pPart);
+ }
+ rWalker.next();
+ }
+ rWalker.parent();
+}
+
+void WidgetDefinitionReader::readPart(tools::XmlWalker& rWalker,
+ std::shared_ptr<WidgetDefinitionPart> rpPart)
+{
+ rWalker.children();
+ while (rWalker.isValid())
+ {
+ if (rWalker.name() == "state")
+ {
+ OString sEnabled = getValueOrAny(rWalker.attribute("enabled"));
+ OString sFocused = getValueOrAny(rWalker.attribute("focused"));
+ OString sPressed = getValueOrAny(rWalker.attribute("pressed"));
+ OString sRollover = getValueOrAny(rWalker.attribute("rollover"));
+ OString sDefault = getValueOrAny(rWalker.attribute("default"));
+ OString sSelected = getValueOrAny(rWalker.attribute("selected"));
+ OString sButtonValue = getValueOrAny(rWalker.attribute("button-value"));
+ OString sExtra = getValueOrAny(rWalker.attribute("extra"));
+
+ std::shared_ptr<WidgetDefinitionState> pState = std::make_shared<WidgetDefinitionState>(
+ sEnabled, sFocused, sPressed, sRollover, sDefault, sSelected, sButtonValue, sExtra);
+
+ rpPart->maStates.push_back(pState);
+ readDrawingDefinition(rWalker, pState);
+ }
+ rWalker.next();
+ }
+ rWalker.parent();
+}
+
+bool WidgetDefinitionReader::read(WidgetDefinition& rWidgetDefinition)
+{
+ if (!lcl_fileExists(m_rDefinitionFile))
+ return false;
+
+ auto pStyle = std::make_shared<WidgetDefinitionStyle>();
+
+ std::unordered_map<OString, Color*> aStyleColorMap = {
+ { "faceColor", &pStyle->maFaceColor },
+ { "checkedColor", &pStyle->maCheckedColor },
+ { "lightColor", &pStyle->maLightColor },
+ { "lightBorderColor", &pStyle->maLightBorderColor },
+ { "shadowColor", &pStyle->maShadowColor },
+ { "darkShadowColor", &pStyle->maDarkShadowColor },
+ { "buttonTextColor", &pStyle->maButtonTextColor },
+ { "defaultActionButtonTextColor", &pStyle->maDefaultActionButtonTextColor },
+ { "actionButtonTextColor", &pStyle->maActionButtonTextColor },
+ { "actionButtonRolloverTextColor", &pStyle->maActionButtonRolloverTextColor },
+ { "buttonRolloverTextColor", &pStyle->maButtonRolloverTextColor },
+ { "radioCheckTextColor", &pStyle->maRadioCheckTextColor },
+ { "groupTextColor", &pStyle->maGroupTextColor },
+ { "labelTextColor", &pStyle->maLabelTextColor },
+ { "windowColor", &pStyle->maWindowColor },
+ { "windowTextColor", &pStyle->maWindowTextColor },
+ { "dialogColor", &pStyle->maDialogColor },
+ { "dialogTextColor", &pStyle->maDialogTextColor },
+ { "workspaceColor", &pStyle->maWorkspaceColor },
+ { "monoColor", &pStyle->maMonoColor },
+ { "fieldColor", &pStyle->maFieldColor },
+ { "fieldTextColor", &pStyle->maFieldTextColor },
+ { "fieldRolloverTextColor", &pStyle->maFieldRolloverTextColor },
+ { "activeColor", &pStyle->maActiveColor },
+ { "activeTextColor", &pStyle->maActiveTextColor },
+ { "activeBorderColor", &pStyle->maActiveBorderColor },
+ { "deactiveColor", &pStyle->maDeactiveColor },
+ { "deactiveTextColor", &pStyle->maDeactiveTextColor },
+ { "deactiveBorderColor", &pStyle->maDeactiveBorderColor },
+ { "menuColor", &pStyle->maMenuColor },
+ { "menuBarColor", &pStyle->maMenuBarColor },
+ { "menuBarRolloverColor", &pStyle->maMenuBarRolloverColor },
+ { "menuBorderColor", &pStyle->maMenuBorderColor },
+ { "menuTextColor", &pStyle->maMenuTextColor },
+ { "menuBarTextColor", &pStyle->maMenuBarTextColor },
+ { "menuBarRolloverTextColor", &pStyle->maMenuBarRolloverTextColor },
+ { "menuBarHighlightTextColor", &pStyle->maMenuBarHighlightTextColor },
+ { "menuHighlightColor", &pStyle->maMenuHighlightColor },
+ { "menuHighlightTextColor", &pStyle->maMenuHighlightTextColor },
+ { "highlightColor", &pStyle->maHighlightColor },
+ { "highlightTextColor", &pStyle->maHighlightTextColor },
+ { "activeTabColor", &pStyle->maActiveTabColor },
+ { "inactiveTabColor", &pStyle->maInactiveTabColor },
+ { "tabTextColor", &pStyle->maTabTextColor },
+ { "tabRolloverTextColor", &pStyle->maTabRolloverTextColor },
+ { "tabHighlightTextColor", &pStyle->maTabHighlightTextColor },
+ { "disableColor", &pStyle->maDisableColor },
+ { "helpColor", &pStyle->maHelpColor },
+ { "helpTextColor", &pStyle->maHelpTextColor },
+ { "linkColor", &pStyle->maLinkColor },
+ { "visitedLinkColor", &pStyle->maVisitedLinkColor },
+ { "toolTextColor", &pStyle->maToolTextColor },
+ { "fontColor", &pStyle->maFontColor },
+ };
+
+ rWidgetDefinition.mpStyle = pStyle;
+
+ auto pSettings = std::make_shared<WidgetDefinitionSettings>();
+
+ std::unordered_map<OString, OString*> aSettingMap = {
+ { "noActiveTabTextRaise", &pSettings->msNoActiveTabTextRaise },
+ { "centeredTabs", &pSettings->msCenteredTabs },
+ { "listBoxEntryMargin", &pSettings->msListBoxEntryMargin },
+ { "defaultFontSize", &pSettings->msDefaultFontSize },
+ { "titleHeight", &pSettings->msTitleHeight },
+ { "floatTitleHeight", &pSettings->msFloatTitleHeight },
+ { "listBoxPreviewDefaultLogicWidth", &pSettings->msListBoxPreviewDefaultLogicWidth },
+ { "listBoxPreviewDefaultLogicHeight", &pSettings->msListBoxPreviewDefaultLogicHeight },
+ };
+
+ rWidgetDefinition.mpSettings = pSettings;
+
+ SvFileStream aFileStream(m_rDefinitionFile, StreamMode::READ);
+
+ tools::XmlWalker aWalker;
+ if (!aWalker.open(&aFileStream))
+ return false;
+
+ if (aWalker.name() != "widgets")
+ return false;
+
+ aWalker.children();
+ while (aWalker.isValid())
+ {
+ ControlType eType;
+ if (aWalker.name() == "style")
+ {
+ aWalker.children();
+ while (aWalker.isValid())
+ {
+ auto pair = aStyleColorMap.find(aWalker.name());
+ if (pair != aStyleColorMap.end())
+ {
+ readColor(aWalker.attribute("value"), *pair->second);
+ }
+ aWalker.next();
+ }
+ aWalker.parent();
+ }
+ if (aWalker.name() == "settings")
+ {
+ aWalker.children();
+ while (aWalker.isValid())
+ {
+ auto pair = aSettingMap.find(aWalker.name());
+ if (pair != aSettingMap.end())
+ {
+ readSetting(aWalker.attribute("value"), *pair->second);
+ }
+ aWalker.next();
+ }
+ aWalker.parent();
+ }
+ else if (getControlTypeForXmlString(aWalker.name(), eType))
+ {
+ readDefinition(aWalker, rWidgetDefinition, eType);
+ }
+ aWalker.next();
+ }
+ aWalker.parent();
+
+ return true;
+}
+
+} // end vcl namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */