1/*
2 * Copyright (C) 2017 Igalia S.L.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "WebKitOptionMenu.h"
22
23#include "WebKitOptionMenuItemPrivate.h"
24#include "WebKitOptionMenuPrivate.h"
25#include <wtf/glib/WTFGType.h>
26
27using namespace WebKit;
28
29/**
30 * SECTION: WebKitOptionMenu
31 * @Short_description:
32 * @Title: WebKitOptionMenu
33 *
34 * WebKitOptionMenu represents the dropdown menu of a select element in a #WebKitWebView.
35 *
36 * When a select element in a #WebKitWebView needs to display a dropdown menu, the signal
37 * #WebKitWebView::show-option-menu is emitted, providing a WebKitOptionMenu with the
38 * #WebKitOptionMenuItem<!-- -->s that should be displayed.
39 *
40 * Since: 2.18
41 */
42
43struct _WebKitOptionMenuPrivate {
44 Vector<WebKitOptionMenuItem> items;
45 RefPtr<WebKitPopupMenu> popupMenu;
46};
47
48enum {
49 CLOSE,
50
51 LAST_SIGNAL
52};
53
54static guint signals[LAST_SIGNAL] = { 0, };
55
56WEBKIT_DEFINE_TYPE(WebKitOptionMenu, webkit_option_menu, G_TYPE_OBJECT)
57
58static void webkit_option_menu_class_init(WebKitOptionMenuClass* optionMenuClass)
59{
60 /**
61 * WebKitOptionMenu::close:
62 * @menu: the #WebKitOptionMenu on which the signal is emitted
63 *
64 * Emitted when closing a #WebKitOptionMenu is requested. This can happen
65 * when the user explicitly calls webkit_option_menu_close() or when the
66 * element is detached from the current page.
67 *
68 * Since: 2.18
69 */
70 signals[CLOSE] =
71 g_signal_new("close",
72 G_TYPE_FROM_CLASS(optionMenuClass),
73 G_SIGNAL_RUN_LAST,
74 0, nullptr, nullptr,
75 g_cclosure_marshal_VOID__VOID,
76 G_TYPE_NONE, 0);
77}
78
79WebKitOptionMenu* webkitOptionMenuCreate(WebKitPopupMenu& popupMenu, const Vector<WebPopupItem>& items, int32_t selectedIndex)
80{
81 auto* menu = WEBKIT_OPTION_MENU(g_object_new(WEBKIT_TYPE_OPTION_MENU, nullptr));
82 menu->priv->popupMenu = &popupMenu;
83 menu->priv->items.reserveInitialCapacity(items.size());
84 for (const auto& item : items)
85 menu->priv->items.uncheckedAppend(WebKitOptionMenuItem(item));
86 if (selectedIndex >= 0) {
87 ASSERT(static_cast<unsigned>(selectedIndex) < menu->priv->items.size());
88 menu->priv->items[selectedIndex].isSelected = true;
89 }
90 return menu;
91}
92
93/**
94 * webkit_option_menu_get_n_items:
95 * @menu: a #WebKitOptionMenu
96 *
97 * Gets the length of the @menu.
98 *
99 * Returns: the number of #WebKitOptionMenuItem<!-- -->s in @menu
100 *
101 * Since: 2.18
102 */
103guint webkit_option_menu_get_n_items(WebKitOptionMenu* menu)
104{
105 g_return_val_if_fail(WEBKIT_IS_OPTION_MENU(menu), 0);
106
107 return menu->priv->items.size();
108}
109
110/**
111 * webkit_option_menu_get_item:
112 * @menu: a #WebKitOptionMenu
113 * @index: the index of the item
114 *
115 * Returns the #WebKitOptionMenuItem at @index in @menu.
116 *
117 * Returns: (transfer none): a #WebKitOptionMenuItem of @menu.
118 *
119 * Since: 2.18
120 */
121WebKitOptionMenuItem* webkit_option_menu_get_item(WebKitOptionMenu* menu, guint index)
122{
123 g_return_val_if_fail(WEBKIT_IS_OPTION_MENU(menu), nullptr);
124 g_return_val_if_fail(index < menu->priv->items.size(), nullptr);
125
126 return &menu->priv->items[index];
127}
128
129/**
130 * webkit_option_menu_select_item:
131 * @menu: a #WebKitOptionMenu
132 * @index: the index of the item
133 *
134 * Selects the #WebKitOptionMenuItem at @index in @menu. Selecting an item changes the
135 * text shown by the combo button, but it doesn't change the value of the element. You need to
136 * explicitly activate the item with webkit_option_menu_select_item() or close the menu with
137 * webkit_option_menu_close() in which case the currently selected item will be activated.
138 *
139 * Since: 2.18
140 */
141void webkit_option_menu_select_item(WebKitOptionMenu* menu, guint index)
142{
143 g_return_if_fail(WEBKIT_IS_OPTION_MENU(menu));
144 g_return_if_fail(index < menu->priv->items.size());
145
146 menu->priv->popupMenu->selectItem(index);
147}
148
149/**
150 * webkit_option_menu_activate_item:
151 * @menu: a #WebKitOptionMenu
152 * @index: the index of the item
153 *
154 * Activates the #WebKitOptionMenuItem at @index in @menu. Activating an item changes the value
155 * of the element making the item the active one. You are expected to close the menu with
156 * webkit_option_menu_close() after activating an item, calling this function again will have no
157 * effect.
158 *
159 * Since: 2.18
160 */
161void webkit_option_menu_activate_item(WebKitOptionMenu* menu, guint index)
162{
163 g_return_if_fail(WEBKIT_IS_OPTION_MENU(menu));
164 g_return_if_fail(index < menu->priv->items.size());
165
166 menu->priv->popupMenu->activateItem(index);
167}
168
169/**
170 * webkit_option_menu_close:
171 * @menu: a #WebKitOptionMenu
172 *
173 * Request to close a #WebKitOptionMenu. This emits WebKitOptionMenu::close signal.
174 * This function should always be called to notify WebKit that the associated
175 * menu has been closed. If the menu is closed and neither webkit_option_menu_select_item()
176 * nor webkit_option_menu_activate_item() have been called, the element value remains
177 * unchanged.
178 *
179 * Since: 2.18
180 */
181void webkit_option_menu_close(WebKitOptionMenu* menu)
182{
183 g_return_if_fail(WEBKIT_IS_OPTION_MENU(menu));
184
185 g_signal_emit(menu, signals[CLOSE], 0, nullptr);
186}
187