2 * Copyright (C) 2017 Igalia S.L.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "RenderThemeWidget.h"
29 #if GTK_CHECK_VERSION(3, 20, 0)
31 #include <wtf/HashMap.h>
32 #include <wtf/NeverDestroyed.h>
36 static HashMap<unsigned, std::unique_ptr<RenderThemeWidget>>& widgetMap()
38 static NeverDestroyed<HashMap<unsigned, std::unique_ptr<RenderThemeWidget>>> map;
42 RenderThemeWidget& RenderThemeWidget::getOrCreate(Type widgetType)
44 auto addResult = widgetMap().ensure(static_cast<unsigned>(widgetType), [widgetType]() -> std::unique_ptr<RenderThemeWidget> {
46 case RenderThemeWidget::Type::VerticalScrollbarRight:
47 return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_VERTICAL, RenderThemeScrollbar::Mode::Full);
48 case RenderThemeWidget::Type::VerticalScrollbarLeft:
49 return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_VERTICAL, RenderThemeScrollbar::Mode::Full, RenderThemeScrollbar::VerticalPosition::Left);
50 case RenderThemeWidget::Type::HorizontalScrollbar:
51 return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_HORIZONTAL, RenderThemeScrollbar::Mode::Full);
52 case RenderThemeWidget::Type::VerticalScrollIndicatorRight:
53 return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_VERTICAL, RenderThemeScrollbar::Mode::Indicator);
54 case RenderThemeWidget::Type::VerticalScrollIndicatorLeft:
55 return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_VERTICAL, RenderThemeScrollbar::Mode::Indicator, RenderThemeScrollbar::VerticalPosition::Left);
56 case RenderThemeWidget::Type::HorizontalScrollIndicator:
57 return std::make_unique<RenderThemeScrollbar>(GTK_ORIENTATION_HORIZONTAL, RenderThemeScrollbar::Mode::Indicator);
58 case RenderThemeWidget::Type::CheckButton:
59 return std::make_unique<RenderThemeToggleButton>(RenderThemeToggleButton::Type::Check);
60 case RenderThemeWidget::Type::RadioButton:
61 return std::make_unique<RenderThemeToggleButton>(RenderThemeToggleButton::Type::Radio);
62 case RenderThemeWidget::Type::Button:
63 return std::make_unique<RenderThemeButton>(RenderThemeButton::Default::No);
64 case RenderThemeWidget::Type::ButtonDefault:
65 return std::make_unique<RenderThemeButton>(RenderThemeButton::Default::Yes);
66 case RenderThemeWidget::Type::ComboBox:
67 return std::make_unique<RenderThemeComboBox>();
68 case RenderThemeWidget::Type::Entry:
69 return std::make_unique<RenderThemeEntry>();
70 case RenderThemeWidget::Type::SelectedEntry:
71 return std::make_unique<RenderThemeEntry>(RenderThemeEntry::Selected::Yes);
72 case RenderThemeWidget::Type::SearchEntry:
73 return std::make_unique<RenderThemeSearchEntry>();
74 case RenderThemeWidget::Type::SpinButton:
75 return std::make_unique<RenderThemeSpinButton>();
76 case RenderThemeWidget::Type::VerticalSlider:
77 return std::make_unique<RenderThemeSlider>(GTK_ORIENTATION_VERTICAL);
78 case RenderThemeWidget::Type::HorizontalSlider:
79 return std::make_unique<RenderThemeSlider>(GTK_ORIENTATION_HORIZONTAL);
80 case RenderThemeWidget::Type::ProgressBar:
81 return std::make_unique<RenderThemeProgressBar>(RenderThemeProgressBar::Mode::Determinate);
82 case RenderThemeWidget::Type::IndeterminateProgressBar:
83 return std::make_unique<RenderThemeProgressBar>(RenderThemeProgressBar::Mode::Indeterminate);
84 case RenderThemeWidget::Type::ListView:
85 return std::make_unique<RenderThemeListView>();
86 case RenderThemeWidget::Type::Icon:
87 return std::make_unique<RenderThemeIcon>();
92 return *addResult.iterator->value;
95 void RenderThemeWidget::clearCache()
100 RenderThemeWidget::~RenderThemeWidget() = default;
102 RenderThemeScrollbar::RenderThemeScrollbar(GtkOrientation orientation, Mode mode, VerticalPosition verticalPosition)
104 RenderThemeGadget::Info info = { RenderThemeGadget::Type::Scrollbar, "scrollbar", { } };
105 if (orientation == GTK_ORIENTATION_VERTICAL) {
106 info.classList.append("vertical");
107 info.classList.append(verticalPosition == VerticalPosition::Right ? "right" : "left");
109 info.classList.append("horizontal");
110 info.classList.append("bottom");
112 static bool usesOverlayScrollbars = g_strcmp0(g_getenv("GTK_OVERLAY_SCROLLING"), "0");
113 if (usesOverlayScrollbars)
114 info.classList.append("overlay-indicator");
115 if (mode == Mode::Full)
116 info.classList.append("hovering");
117 m_scrollbar = RenderThemeGadget::create(info);
119 Vector<RenderThemeGadget::Info> children;
120 auto steppers = static_cast<RenderThemeScrollbarGadget*>(m_scrollbar.get())->steppers();
121 if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Backward)) {
122 m_steppersPosition[0] = children.size();
123 children.append({ RenderThemeGadget::Type::Generic, "button", { "up" } });
125 if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryForward)) {
126 m_steppersPosition[1] = children.size();
127 children.append({ RenderThemeGadget::Type::Generic, "button", { "down" } });
129 m_troughPosition = children.size();
130 children.append({ RenderThemeGadget::Type::Generic, "trough", { } });
131 if (steppers.contains(RenderThemeScrollbarGadget::Steppers::SecondaryBackward)) {
132 m_steppersPosition[2] = children.size();
133 children.append({ RenderThemeGadget::Type::Generic, "button", { "up" } });
135 if (steppers.contains(RenderThemeScrollbarGadget::Steppers::Forward)) {
136 m_steppersPosition[3] = children.size();
137 children.append({ RenderThemeGadget::Type::Generic, "button", { "down" } });
139 info.type = RenderThemeGadget::Type::Generic;
140 info.name = "contents";
141 info.classList.clear();
142 m_contents = std::make_unique<RenderThemeBoxGadget>(info, GTK_ORIENTATION_VERTICAL, children, m_scrollbar.get());
143 info.name = "slider";
144 m_slider = RenderThemeGadget::create(info, m_contents->child(m_troughPosition));
147 RenderThemeGadget* RenderThemeScrollbar::stepper(RenderThemeScrollbarGadget::Steppers scrollbarStepper)
149 if (!static_cast<RenderThemeScrollbarGadget*>(m_scrollbar.get())->steppers().contains(scrollbarStepper))
152 switch (scrollbarStepper) {
153 case RenderThemeScrollbarGadget::Steppers::Backward:
154 return m_contents->child(m_steppersPosition[0]);
155 case RenderThemeScrollbarGadget::Steppers::SecondaryForward:
156 return m_contents->child(m_steppersPosition[1]);
157 case RenderThemeScrollbarGadget::Steppers::SecondaryBackward:
158 return m_contents->child(m_steppersPosition[2]);
159 case RenderThemeScrollbarGadget::Steppers::Forward:
160 return m_contents->child(m_steppersPosition[3]);
168 RenderThemeToggleButton::RenderThemeToggleButton(Type toggleType)
170 RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, toggleType == Type::Check ? "checkbutton" : "radiobutton", { "text-button" } };
171 m_button = RenderThemeGadget::create(info);
172 if (toggleType == Type::Check) {
173 info.type = RenderThemeGadget::Type::Check;
176 info.type = RenderThemeGadget::Type::Radio;
179 info.classList.clear();
180 m_toggle = RenderThemeGadget::create(info, m_button.get());
183 RenderThemeButton::RenderThemeButton(Default isDefault)
185 RenderThemeGadget::Info info = { RenderThemeGadget::Type::Button, "button", { "text-button" } };
186 if (isDefault == Default::Yes)
187 info.classList.append("default");
188 m_button = RenderThemeGadget::create(info);
191 RenderThemeComboBox::RenderThemeComboBox()
193 RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "combobox", { } };
194 m_comboBox = RenderThemeGadget::create(info);
195 Vector<RenderThemeGadget::Info> children = {
196 { RenderThemeGadget::Type::Generic, "button", { "combo" } }
199 info.classList = { "horizontal", "linked" };
200 m_box = std::make_unique<RenderThemeBoxGadget>(info, GTK_ORIENTATION_HORIZONTAL, children, m_comboBox.get());
201 RenderThemeGadget* button = m_box->child(0);
202 info.classList.removeLast();
203 m_buttonBox = RenderThemeGadget::create(info, button);
204 info.type = RenderThemeGadget::Type::Arrow;
206 info.classList = { };
207 m_arrow = RenderThemeGadget::create(info, m_buttonBox.get());
210 RenderThemeEntry::RenderThemeEntry(Selected isSelected)
212 RenderThemeGadget::Info info = { RenderThemeGadget::Type::TextField, "entry", { } };
213 m_entry = RenderThemeGadget::create(info);
214 if (isSelected == Selected::Yes) {
215 info.type = RenderThemeGadget::Type::Generic;
216 info.name = "selection";
217 m_selection = RenderThemeGadget::create(info, m_entry.get());
221 RenderThemeSearchEntry::RenderThemeSearchEntry()
223 RenderThemeGadget::Info info = { RenderThemeGadget::Type::Icon, "image", { "left" } };
224 m_leftIcon = RenderThemeGadget::create(info, m_entry.get());
225 static_cast<RenderThemeIconGadget*>(m_leftIcon.get())->setIconName("edit-find-symbolic");
226 info.classList.clear();
227 info.classList.append("right");
228 m_rightIcon = RenderThemeGadget::create(info, m_entry.get());
229 static_cast<RenderThemeIconGadget*>(m_rightIcon.get())->setIconName("edit-clear-symbolic");
232 RenderThemeSpinButton::RenderThemeSpinButton()
234 RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "spinbutton", { "horizontal" } };
235 m_spinButton = RenderThemeGadget::create(info);
236 info.type = RenderThemeGadget::Type::TextField;
238 info.classList.clear();
239 m_entry = RenderThemeGadget::create(info, m_spinButton.get());
240 info.type = RenderThemeGadget::Type::Icon;
241 info.name = "button";
242 info.classList.append("up");
243 m_up = RenderThemeGadget::create(info, m_spinButton.get());
244 auto* upIcon = static_cast<RenderThemeIconGadget*>(m_up.get());
245 upIcon->setIconSize(RenderThemeIconGadget::IconSizeGtk::Menu);
246 upIcon->setIconName("list-add-symbolic");
247 info.classList[0] = "down";
248 m_down = RenderThemeGadget::create(info, m_spinButton.get());
249 auto* downIcon = static_cast<RenderThemeIconGadget*>(m_down.get());
250 downIcon->setIconSize(RenderThemeIconGadget::IconSizeGtk::Menu);
251 downIcon->setIconName("list-remove-symbolic");
254 RenderThemeSlider::RenderThemeSlider(GtkOrientation orientation)
256 RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "scale", { } };
257 if (orientation == GTK_ORIENTATION_VERTICAL)
258 info.classList.append("vertical");
260 info.classList.append("horizontal");
261 m_scale = RenderThemeGadget::create(info);
262 info.name = "contents";
263 info.classList.clear();
264 m_contents = RenderThemeGadget::create(info, m_scale.get());
265 info.name = "trough";
266 m_trough = RenderThemeGadget::create(info, m_contents.get());
267 info.name = "slider";
268 m_slider = RenderThemeGadget::create(info, m_trough.get());
269 info.name = "highlight";
270 m_highlight = RenderThemeGadget::create(info, m_trough.get());
273 RenderThemeProgressBar::RenderThemeProgressBar(Mode mode)
275 RenderThemeGadget::Info info = { RenderThemeGadget::Type::Generic, "progressbar", { "horizontal" } };
276 m_progressBar = RenderThemeGadget::create(info);
277 info.name = "trough";
278 info.classList.clear();
279 m_trough = RenderThemeGadget::create(info, m_progressBar.get());
280 info.name = "progress";
281 if (mode == Mode::Determinate)
282 info.classList.append("pulse");
283 m_progress = RenderThemeGadget::create(info, m_trough.get());
286 RenderThemeListView::RenderThemeListView()
287 : m_treeview(RenderThemeGadget::create({ RenderThemeGadget::Type::Generic, "treeview", { "view" } }))
291 RenderThemeIcon::RenderThemeIcon()
292 : m_icon(RenderThemeGadget::create({ RenderThemeGadget::Type::Icon, "image", { } }))
296 } // namepsace WebCore
298 #endif // GTK_CHECK_VERSION(3, 20, 0)