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

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

Open menu in separate popup window (WIP)

  • Property mode set to 100644
File size: 8.5 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>
51#include "../private/menubar.h"
52#include "../private/menu.h"
53#include "../private/resource.h"
54
55enum {
56 menu_frame_w = 4,
57 menu_frame_h = 4,
58 menu_frame_w_text = 2,
59 menu_frame_h_text = 1
60};
61
[3c8c580]62static void ui_menu_popup_pos(ui_popup_t *, void *, pos_event_t *);
63
64static ui_popup_cb_t ui_menu_popup_cb = {
65 .pos = ui_menu_popup_pos
66};
67
[214aefb]68/** Create new menu.
69 *
70 * @param mbar Menu bar
71 * @param caption Caption
72 * @param rmenu Place to store pointer to new menu
73 * @return EOK on success, ENOMEM if out of memory
74 */
75errno_t ui_menu_create(ui_menu_bar_t *mbar, const char *caption,
76 ui_menu_t **rmenu)
77{
78 ui_menu_t *menu;
79
80 menu = calloc(1, sizeof(ui_menu_t));
81 if (menu == NULL)
82 return ENOMEM;
83
84 menu->caption = str_dup(caption);
85 if (menu->caption == NULL) {
86 free(menu);
87 return ENOMEM;
88 }
89
90 menu->mbar = mbar;
91 list_append(&menu->lmenus, &mbar->menus);
92 list_initialize(&menu->entries);
93
94 *rmenu = menu;
95 return EOK;
96}
97
98/** Destroy menu.
99 *
100 * @param menu Menu or @c NULL
101 */
102void ui_menu_destroy(ui_menu_t *menu)
103{
104 ui_menu_entry_t *mentry;
105
106 if (menu == NULL)
107 return;
108
109 /* Destroy entries */
110 mentry = ui_menu_entry_first(menu);
111 while (mentry != NULL) {
112 ui_menu_entry_destroy(mentry);
113 mentry = ui_menu_entry_first(menu);
114 }
115
116 list_remove(&menu->lmenus);
117 free(menu->caption);
118 free(menu);
119}
120
121/** Get first menu in menu bar.
122 *
123 * @param mbar Menu bar
124 * @return First menu or @c NULL if there is none
125 */
126ui_menu_t *ui_menu_first(ui_menu_bar_t *mbar)
127{
128 link_t *link;
129
130 link = list_first(&mbar->menus);
131 if (link == NULL)
132 return NULL;
133
134 return list_get_instance(link, ui_menu_t, lmenus);
135}
136
137/** Get next menu in menu bar.
138 *
139 * @param cur Current menu
140 * @return Next menu or @c NULL if @a cur is the last one
141 */
142ui_menu_t *ui_menu_next(ui_menu_t *cur)
143{
144 link_t *link;
145
146 link = list_next(&cur->lmenus, &cur->mbar->menus);
147 if (link == NULL)
148 return NULL;
149
150 return list_get_instance(link, ui_menu_t, lmenus);
151}
152
153/** Get menu caption.
154 *
155 * @param menu Menu
156 * @return Caption (owned by @a menu)
157 */
158const char *ui_menu_caption(ui_menu_t *menu)
159{
160 return menu->caption;
161}
162
163/** Get menu geometry.
164 *
165 * @param menu Menu
166 * @param spos Starting position
167 * @param geom Structure to fill in with computed geometry
168 */
169void ui_menu_get_geom(ui_menu_t *menu, gfx_coord2_t *spos,
170 ui_menu_geom_t *geom)
171{
172 gfx_coord2_t edim;
173 gfx_coord_t frame_w;
174 gfx_coord_t frame_h;
175
176 if (menu->mbar->res->textmode) {
177 frame_w = menu_frame_w_text;
178 frame_h = menu_frame_h_text;
179 } else {
180 frame_w = menu_frame_w;
181 frame_h = menu_frame_h;
182 }
183
[b8b64a8]184 edim.x = ui_menu_entry_calc_width(menu, menu->max_caption_w,
185 menu->max_shortcut_w);
[f251883]186 edim.y = menu->total_h;
[214aefb]187
188 geom->outer_rect.p0 = *spos;
189 geom->outer_rect.p1.x = spos->x + edim.x + 2 * frame_w;
190 geom->outer_rect.p1.y = spos->y + edim.y + 2 * frame_h;
191
192 geom->entries_rect.p0.x = spos->x + frame_w;
193 geom->entries_rect.p0.y = spos->y + frame_h;
194 geom->entries_rect.p1.x = geom->entries_rect.p0.x + edim.x;
195 geom->entries_rect.p1.y = geom->entries_rect.p0.x + edim.y;
196}
197
198/** Get menu rectangle.
199 *
200 * @param menu Menu
201 * @param spos Starting position (top-left corner)
202 * @param rect Place to store menu rectangle
203 */
204void ui_menu_get_rect(ui_menu_t *menu, gfx_coord2_t *spos, gfx_rect_t *rect)
205{
206 ui_menu_geom_t geom;
207
208 ui_menu_get_geom(menu, spos, &geom);
209 *rect = geom.outer_rect;
210}
211
[3c8c580]212/** Get UI resource from menu.
213 *
214 * @param menu Menu
215 * @return UI resource
216 */
217ui_resource_t *ui_menu_get_res(ui_menu_t *menu)
218{
219 return ui_popup_get_res(menu->popup);
220}
221
222/** Open menu.
223 *
224 * @param menu Menu
225 * @param prect Parent rectangle around which the menu should be placed
226 */
227errno_t ui_menu_open(ui_menu_t *menu, gfx_rect_t *prect)
228{
229 ui_popup_t *popup = NULL;
230 ui_popup_params_t params;
231 ui_menu_geom_t geom;
232 gfx_coord2_t mpos;
233 errno_t rc;
234
235 /* Determine menu dimensions */
236
237 mpos.x = 0;
238 mpos.y = 0;
239 ui_menu_get_geom(menu, &mpos, &geom);
240
241 ui_popup_params_init(&params);
242 params.rect = geom.outer_rect;
243
244 rc = ui_popup_create(menu->mbar->ui, &params, &popup);
245 if (rc != EOK)
246 return rc;
247
248 menu->popup = popup;
249 ui_popup_set_cb(popup, &ui_menu_popup_cb, menu);
250
251 return ui_menu_paint(menu, &mpos);
252}
253
254/** Close menu.
255 *
256 * @param menu Menu
257 */
258void ui_menu_close(ui_menu_t *menu)
259{
260 ui_popup_destroy(menu->popup);
261 menu->popup = NULL;
262}
263
[214aefb]264/** Paint menu.
265 *
266 * @param menu Menu
267 * @param spos Starting position (top-left corner)
268 * @return EOK on success or an error code
269 */
270errno_t ui_menu_paint(ui_menu_t *menu, gfx_coord2_t *spos)
271{
272 ui_resource_t *res;
273 gfx_coord2_t pos;
274 ui_menu_entry_t *mentry;
275 ui_menu_geom_t geom;
276 gfx_rect_t bg_rect;
277 errno_t rc;
278
[3c8c580]279 res = ui_menu_get_res(menu);
[214aefb]280 ui_menu_get_geom(menu, spos, &geom);
281
282 /* Paint menu frame */
283
284 rc = gfx_set_color(res->gc, res->wnd_face_color);
285 if (rc != EOK)
286 goto error;
287
288 rc = ui_paint_outset_frame(res, &geom.outer_rect, &bg_rect);
289 if (rc != EOK)
290 goto error;
291
292 /* Paint menu background */
293
294 rc = gfx_set_color(res->gc, res->wnd_face_color);
295 if (rc != EOK)
296 goto error;
297
298 rc = gfx_fill_rect(res->gc, &bg_rect);
299 if (rc != EOK)
300 goto error;
301
302 /* Paint entries */
303 pos = geom.entries_rect.p0;
304
305 mentry = ui_menu_entry_first(menu);
306 while (mentry != NULL) {
307 rc = ui_menu_entry_paint(mentry, &pos);
308 if (rc != EOK)
309 goto error;
310
311 pos.y += ui_menu_entry_height(mentry);
312 mentry = ui_menu_entry_next(mentry);
313 }
314
315 rc = gfx_update(res->gc);
316 if (rc != EOK)
317 goto error;
318
319 return EOK;
320error:
321 return rc;
322}
323
[f536a16]324/** Handle position event in menu.
[214aefb]325 *
326 * @param menu Menu
327 * @param spos Starting position (top-left corner)
[0262f16c]328 * @param event Position event
329 * @return ui_claimed iff the event was claimed
[214aefb]330 */
[0262f16c]331ui_evclaim_t ui_menu_pos_event(ui_menu_t *menu, gfx_coord2_t *spos,
332 pos_event_t *event)
[214aefb]333{
334 ui_menu_geom_t geom;
335 ui_menu_entry_t *mentry;
336 gfx_coord2_t pos;
[0262f16c]337 gfx_coord2_t epos;
338 ui_evclaim_t claimed;
[214aefb]339
340 ui_menu_get_geom(menu, spos, &geom);
[0262f16c]341 epos.x = event->hpos;
342 epos.y = event->vpos;
[214aefb]343
344 pos = geom.entries_rect.p0;
345
346 mentry = ui_menu_entry_first(menu);
347 while (mentry != NULL) {
[0262f16c]348 claimed = ui_menu_entry_pos_event(mentry, &pos, event);
349 if (claimed == ui_claimed)
350 return ui_claimed;
[214aefb]351
352 pos.y += ui_menu_entry_height(mentry);
353 mentry = ui_menu_entry_next(mentry);
354 }
[0262f16c]355
[f536a16]356 /* Event inside menu? */
357 if (gfx_pix_inside_rect(&epos, &geom.outer_rect)) {
358 /* Claim event */
[0262f16c]359 return ui_claimed;
[f536a16]360 } else {
361 /* Press outside menu - close it */
[3c8c580]362// if (event->type == POS_PRESS)
363// ui_menu_bar_select(menu->mbar, NULL, NULL);
[f536a16]364 }
[0262f16c]365
366 return ui_unclaimed;
[214aefb]367}
368
[3c8c580]369/** Handle position event in menu popup window.
370 *
371 * @param popup Menu popup window
372 * @param arg Argument (ui_menu_t *)
373 * @param event Position event
374 */
375static void ui_menu_popup_pos(ui_popup_t *popup, void *arg, pos_event_t *event)
376{
377 ui_menu_t *menu = (ui_menu_t *)arg;
378 gfx_coord2_t spos;
379
380 spos.x = 0;
381 spos.y = 0;
382 ui_menu_pos_event(menu, &spos, event);
383}
384
[214aefb]385/** @}
386 */
Note: See TracBrowser for help on using the repository browser.