source: mainline/uspace/lib/ui/src/menu.c@ c68c18b9

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c68c18b9 was c68c18b9, checked in by jxsvoboda <5887334+jxsvoboda@…>, 4 years ago

Specify parent window when creating popup

This will be used in conjunction with ui_wnd_popup_params_t.place
(a rectangle relative to the parent window) to determine where on
the screen the popup window should appear.

  • Property mode set to 100644
File size: 8.6 KB
RevLine 
[214aefb]1/*
2 * Copyright (c) 2021 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libui
30 * @{
31 */
32/**
33 * @file Menu
34 */
35
36#include <adt/list.h>
37#include <errno.h>
38#include <gfx/color.h>
39#include <gfx/context.h>
40#include <gfx/render.h>
41#include <gfx/text.h>
42#include <io/pos_event.h>
43#include <stdlib.h>
44#include <str.h>
45#include <ui/control.h>
46#include <ui/paint.h>
[3c8c580]47#include <ui/popup.h>
[214aefb]48#include <ui/menu.h>
49#include <ui/menuentry.h>
50#include <ui/resource.h>
[c68c18b9]51#include <ui/window.h>
[214aefb]52#include "../private/menubar.h"
53#include "../private/menu.h"
54#include "../private/resource.h"
55
56enum {
57 menu_frame_w = 4,
58 menu_frame_h = 4,
59 menu_frame_w_text = 2,
60 menu_frame_h_text = 1
61};
62
[3c8c580]63static void ui_menu_popup_pos(ui_popup_t *, void *, pos_event_t *);
64
65static ui_popup_cb_t ui_menu_popup_cb = {
66 .pos = ui_menu_popup_pos
67};
68
[214aefb]69/** Create new menu.
70 *
71 * @param mbar Menu bar
72 * @param caption Caption
73 * @param rmenu Place to store pointer to new menu
74 * @return EOK on success, ENOMEM if out of memory
75 */
76errno_t ui_menu_create(ui_menu_bar_t *mbar, const char *caption,
77 ui_menu_t **rmenu)
78{
79 ui_menu_t *menu;
80
81 menu = calloc(1, sizeof(ui_menu_t));
82 if (menu == NULL)
83 return ENOMEM;
84
85 menu->caption = str_dup(caption);
86 if (menu->caption == NULL) {
87 free(menu);
88 return ENOMEM;
89 }
90
91 menu->mbar = mbar;
92 list_append(&menu->lmenus, &mbar->menus);
93 list_initialize(&menu->entries);
94
95 *rmenu = menu;
96 return EOK;
97}
98
99/** Destroy menu.
100 *
101 * @param menu Menu or @c NULL
102 */
103void ui_menu_destroy(ui_menu_t *menu)
104{
105 ui_menu_entry_t *mentry;
106
107 if (menu == NULL)
108 return;
109
110 /* Destroy entries */
111 mentry = ui_menu_entry_first(menu);
112 while (mentry != NULL) {
113 ui_menu_entry_destroy(mentry);
114 mentry = ui_menu_entry_first(menu);
115 }
116
117 list_remove(&menu->lmenus);
118 free(menu->caption);
119 free(menu);
120}
121
122/** Get first menu in menu bar.
123 *
124 * @param mbar Menu bar
125 * @return First menu or @c NULL if there is none
126 */
127ui_menu_t *ui_menu_first(ui_menu_bar_t *mbar)
128{
129 link_t *link;
130
131 link = list_first(&mbar->menus);
132 if (link == NULL)
133 return NULL;
134
135 return list_get_instance(link, ui_menu_t, lmenus);
136}
137
138/** Get next menu in menu bar.
139 *
140 * @param cur Current menu
141 * @return Next menu or @c NULL if @a cur is the last one
142 */
143ui_menu_t *ui_menu_next(ui_menu_t *cur)
144{
145 link_t *link;
146
147 link = list_next(&cur->lmenus, &cur->mbar->menus);
148 if (link == NULL)
149 return NULL;
150
151 return list_get_instance(link, ui_menu_t, lmenus);
152}
153
154/** Get menu caption.
155 *
156 * @param menu Menu
157 * @return Caption (owned by @a menu)
158 */
159const char *ui_menu_caption(ui_menu_t *menu)
160{
161 return menu->caption;
162}
163
164/** Get menu geometry.
165 *
166 * @param menu Menu
167 * @param spos Starting position
168 * @param geom Structure to fill in with computed geometry
169 */
170void ui_menu_get_geom(ui_menu_t *menu, gfx_coord2_t *spos,
171 ui_menu_geom_t *geom)
172{
[c68c18b9]173 ui_resource_t *res;
[214aefb]174 gfx_coord2_t edim;
175 gfx_coord_t frame_w;
176 gfx_coord_t frame_h;
177
[c68c18b9]178 res = ui_window_get_res(menu->mbar->window);
179
180 if (res->textmode) {
[214aefb]181 frame_w = menu_frame_w_text;
182 frame_h = menu_frame_h_text;
183 } else {
184 frame_w = menu_frame_w;
185 frame_h = menu_frame_h;
186 }
187
[b8b64a8]188 edim.x = ui_menu_entry_calc_width(menu, menu->max_caption_w,
189 menu->max_shortcut_w);
[f251883]190 edim.y = menu->total_h;
[214aefb]191
192 geom->outer_rect.p0 = *spos;
193 geom->outer_rect.p1.x = spos->x + edim.x + 2 * frame_w;
194 geom->outer_rect.p1.y = spos->y + edim.y + 2 * frame_h;
195
196 geom->entries_rect.p0.x = spos->x + frame_w;
197 geom->entries_rect.p0.y = spos->y + frame_h;
198 geom->entries_rect.p1.x = geom->entries_rect.p0.x + edim.x;
199 geom->entries_rect.p1.y = geom->entries_rect.p0.x + edim.y;
200}
201
202/** Get menu rectangle.
203 *
204 * @param menu Menu
205 * @param spos Starting position (top-left corner)
206 * @param rect Place to store menu rectangle
207 */
208void ui_menu_get_rect(ui_menu_t *menu, gfx_coord2_t *spos, gfx_rect_t *rect)
209{
210 ui_menu_geom_t geom;
211
212 ui_menu_get_geom(menu, spos, &geom);
213 *rect = geom.outer_rect;
214}
215
[3c8c580]216/** Get UI resource from menu.
217 *
218 * @param menu Menu
219 * @return UI resource
220 */
221ui_resource_t *ui_menu_get_res(ui_menu_t *menu)
222{
223 return ui_popup_get_res(menu->popup);
224}
225
226/** Open menu.
227 *
228 * @param menu Menu
229 * @param prect Parent rectangle around which the menu should be placed
230 */
231errno_t ui_menu_open(ui_menu_t *menu, gfx_rect_t *prect)
232{
233 ui_popup_t *popup = NULL;
234 ui_popup_params_t params;
235 ui_menu_geom_t geom;
236 gfx_coord2_t mpos;
237 errno_t rc;
238
239 /* Determine menu dimensions */
240
241 mpos.x = 0;
242 mpos.y = 0;
243 ui_menu_get_geom(menu, &mpos, &geom);
244
245 ui_popup_params_init(&params);
246 params.rect = geom.outer_rect;
247
[c68c18b9]248 rc = ui_popup_create(menu->mbar->ui, menu->mbar->window, &params,
249 &popup);
[3c8c580]250 if (rc != EOK)
251 return rc;
252
253 menu->popup = popup;
254 ui_popup_set_cb(popup, &ui_menu_popup_cb, menu);
255
256 return ui_menu_paint(menu, &mpos);
257}
258
259/** Close menu.
260 *
261 * @param menu Menu
262 */
263void ui_menu_close(ui_menu_t *menu)
264{
265 ui_popup_destroy(menu->popup);
266 menu->popup = NULL;
267}
268
[214aefb]269/** Paint menu.
270 *
271 * @param menu Menu
272 * @param spos Starting position (top-left corner)
273 * @return EOK on success or an error code
274 */
275errno_t ui_menu_paint(ui_menu_t *menu, gfx_coord2_t *spos)
276{
277 ui_resource_t *res;
278 gfx_coord2_t pos;
279 ui_menu_entry_t *mentry;
280 ui_menu_geom_t geom;
281 gfx_rect_t bg_rect;
282 errno_t rc;
283
[3c8c580]284 res = ui_menu_get_res(menu);
[214aefb]285 ui_menu_get_geom(menu, spos, &geom);
286
287 /* Paint menu frame */
288
289 rc = gfx_set_color(res->gc, res->wnd_face_color);
290 if (rc != EOK)
291 goto error;
292
293 rc = ui_paint_outset_frame(res, &geom.outer_rect, &bg_rect);
294 if (rc != EOK)
295 goto error;
296
297 /* Paint menu background */
298
299 rc = gfx_set_color(res->gc, res->wnd_face_color);
300 if (rc != EOK)
301 goto error;
302
303 rc = gfx_fill_rect(res->gc, &bg_rect);
304 if (rc != EOK)
305 goto error;
306
307 /* Paint entries */
308 pos = geom.entries_rect.p0;
309
310 mentry = ui_menu_entry_first(menu);
311 while (mentry != NULL) {
312 rc = ui_menu_entry_paint(mentry, &pos);
313 if (rc != EOK)
314 goto error;
315
316 pos.y += ui_menu_entry_height(mentry);
317 mentry = ui_menu_entry_next(mentry);
318 }
319
320 rc = gfx_update(res->gc);
321 if (rc != EOK)
322 goto error;
323
324 return EOK;
325error:
326 return rc;
327}
328
[f536a16]329/** Handle position event in menu.
[214aefb]330 *
331 * @param menu Menu
332 * @param spos Starting position (top-left corner)
[0262f16c]333 * @param event Position event
334 * @return ui_claimed iff the event was claimed
[214aefb]335 */
[0262f16c]336ui_evclaim_t ui_menu_pos_event(ui_menu_t *menu, gfx_coord2_t *spos,
337 pos_event_t *event)
[214aefb]338{
339 ui_menu_geom_t geom;
340 ui_menu_entry_t *mentry;
341 gfx_coord2_t pos;
[0262f16c]342 gfx_coord2_t epos;
343 ui_evclaim_t claimed;
[214aefb]344
345 ui_menu_get_geom(menu, spos, &geom);
[0262f16c]346 epos.x = event->hpos;
347 epos.y = event->vpos;
[214aefb]348
349 pos = geom.entries_rect.p0;
350
351 mentry = ui_menu_entry_first(menu);
352 while (mentry != NULL) {
[0262f16c]353 claimed = ui_menu_entry_pos_event(mentry, &pos, event);
354 if (claimed == ui_claimed)
355 return ui_claimed;
[214aefb]356
357 pos.y += ui_menu_entry_height(mentry);
358 mentry = ui_menu_entry_next(mentry);
359 }
[0262f16c]360
[f536a16]361 /* Event inside menu? */
362 if (gfx_pix_inside_rect(&epos, &geom.outer_rect)) {
363 /* Claim event */
[0262f16c]364 return ui_claimed;
[f536a16]365 } else {
366 /* Press outside menu - close it */
[3c8c580]367// if (event->type == POS_PRESS)
368// ui_menu_bar_select(menu->mbar, NULL, NULL);
[f536a16]369 }
[0262f16c]370
371 return ui_unclaimed;
[214aefb]372}
373
[3c8c580]374/** Handle position event in menu popup window.
375 *
376 * @param popup Menu popup window
377 * @param arg Argument (ui_menu_t *)
378 * @param event Position event
379 */
380static void ui_menu_popup_pos(ui_popup_t *popup, void *arg, pos_event_t *event)
381{
382 ui_menu_t *menu = (ui_menu_t *)arg;
383 gfx_coord2_t spos;
384
385 spos.x = 0;
386 spos.y = 0;
387 ui_menu_pos_event(menu, &spos, event);
388}
389
[214aefb]390/** @}
391 */
Note: See TracBrowser for help on using the repository browser.