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

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

Activate menu entry by clicking (instead of simple press)

This allows for visual feedback and also serves as the confirmation
of correctness/intent (same as with push button).

  • Property mode set to 100644
File size: 7.3 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>
47#include <ui/menu.h>
48#include <ui/menuentry.h>
49#include <ui/resource.h>
50#include "../private/menubar.h"
51#include "../private/menu.h"
52#include "../private/resource.h"
53
54enum {
55 menu_frame_w = 4,
56 menu_frame_h = 4,
57 menu_frame_w_text = 2,
58 menu_frame_h_text = 1
59};
60
61/** Create new menu.
62 *
63 * @param mbar Menu bar
64 * @param caption Caption
65 * @param rmenu Place to store pointer to new menu
66 * @return EOK on success, ENOMEM if out of memory
67 */
68errno_t ui_menu_create(ui_menu_bar_t *mbar, const char *caption,
69 ui_menu_t **rmenu)
70{
71 ui_menu_t *menu;
72
73 menu = calloc(1, sizeof(ui_menu_t));
74 if (menu == NULL)
75 return ENOMEM;
76
77 menu->caption = str_dup(caption);
78 if (menu->caption == NULL) {
79 free(menu);
80 return ENOMEM;
81 }
82
83 menu->mbar = mbar;
84 list_append(&menu->lmenus, &mbar->menus);
85 list_initialize(&menu->entries);
86
87 *rmenu = menu;
88 return EOK;
89}
90
91/** Destroy menu.
92 *
93 * @param menu Menu or @c NULL
94 */
95void ui_menu_destroy(ui_menu_t *menu)
96{
97 ui_menu_entry_t *mentry;
98
99 if (menu == NULL)
100 return;
101
102 /* Destroy entries */
103 mentry = ui_menu_entry_first(menu);
104 while (mentry != NULL) {
105 ui_menu_entry_destroy(mentry);
106 mentry = ui_menu_entry_first(menu);
107 }
108
109 list_remove(&menu->lmenus);
110 free(menu->caption);
111 free(menu);
112}
113
114/** Get first menu in menu bar.
115 *
116 * @param mbar Menu bar
117 * @return First menu or @c NULL if there is none
118 */
119ui_menu_t *ui_menu_first(ui_menu_bar_t *mbar)
120{
121 link_t *link;
122
123 link = list_first(&mbar->menus);
124 if (link == NULL)
125 return NULL;
126
127 return list_get_instance(link, ui_menu_t, lmenus);
128}
129
130/** Get next menu in menu bar.
131 *
132 * @param cur Current menu
133 * @return Next menu or @c NULL if @a cur is the last one
134 */
135ui_menu_t *ui_menu_next(ui_menu_t *cur)
136{
137 link_t *link;
138
139 link = list_next(&cur->lmenus, &cur->mbar->menus);
140 if (link == NULL)
141 return NULL;
142
143 return list_get_instance(link, ui_menu_t, lmenus);
144}
145
146/** Get menu caption.
147 *
148 * @param menu Menu
149 * @return Caption (owned by @a menu)
150 */
151const char *ui_menu_caption(ui_menu_t *menu)
152{
153 return menu->caption;
154}
155
156/** Get menu geometry.
157 *
158 * @param menu Menu
159 * @param spos Starting position
160 * @param geom Structure to fill in with computed geometry
161 */
162void ui_menu_get_geom(ui_menu_t *menu, gfx_coord2_t *spos,
163 ui_menu_geom_t *geom)
164{
165 ui_menu_entry_t *mentry;
166 gfx_coord2_t edim;
167 gfx_coord_t frame_w;
168 gfx_coord_t frame_h;
169 gfx_coord_t w;
170 gfx_coord_t h;
171
172 if (menu->mbar->res->textmode) {
173 frame_w = menu_frame_w_text;
174 frame_h = menu_frame_h_text;
175 } else {
176 frame_w = menu_frame_w;
177 frame_h = menu_frame_h;
178 }
179
180 edim.x = 0;
181 edim.y = 0;
182
183 mentry = ui_menu_entry_first(menu);
184 while (mentry != NULL) {
185 w = ui_menu_entry_width(mentry);
186 h = ui_menu_entry_height(mentry);
187
188 if (w > edim.x)
189 edim.x = w;
190 edim.y += h;
191
192 mentry = ui_menu_entry_next(mentry);
193 }
194
195 geom->outer_rect.p0 = *spos;
196 geom->outer_rect.p1.x = spos->x + edim.x + 2 * frame_w;
197 geom->outer_rect.p1.y = spos->y + edim.y + 2 * frame_h;
198
199 geom->entries_rect.p0.x = spos->x + frame_w;
200 geom->entries_rect.p0.y = spos->y + frame_h;
201 geom->entries_rect.p1.x = geom->entries_rect.p0.x + edim.x;
202 geom->entries_rect.p1.y = geom->entries_rect.p0.x + edim.y;
203}
204
205/** Get menu rectangle.
206 *
207 * @param menu Menu
208 * @param spos Starting position (top-left corner)
209 * @param rect Place to store menu rectangle
210 */
211void ui_menu_get_rect(ui_menu_t *menu, gfx_coord2_t *spos, gfx_rect_t *rect)
212{
213 ui_menu_geom_t geom;
214
215 ui_menu_get_geom(menu, spos, &geom);
216 *rect = geom.outer_rect;
217}
218
219/** Paint menu.
220 *
221 * @param menu Menu
222 * @param spos Starting position (top-left corner)
223 * @return EOK on success or an error code
224 */
225errno_t ui_menu_paint(ui_menu_t *menu, gfx_coord2_t *spos)
226{
227 ui_resource_t *res;
228 gfx_coord2_t pos;
229 ui_menu_entry_t *mentry;
230 ui_menu_geom_t geom;
231 gfx_rect_t bg_rect;
232 errno_t rc;
233
234 res = menu->mbar->res;
235 ui_menu_get_geom(menu, spos, &geom);
236
237 /* Paint menu frame */
238
239 rc = gfx_set_color(res->gc, res->wnd_face_color);
240 if (rc != EOK)
241 goto error;
242
243 rc = ui_paint_outset_frame(res, &geom.outer_rect, &bg_rect);
244 if (rc != EOK)
245 goto error;
246
247 /* Paint menu background */
248
249 rc = gfx_set_color(res->gc, res->wnd_face_color);
250 if (rc != EOK)
251 goto error;
252
253 rc = gfx_fill_rect(res->gc, &bg_rect);
254 if (rc != EOK)
255 goto error;
256
257 /* Paint entries */
258 pos = geom.entries_rect.p0;
259
260 mentry = ui_menu_entry_first(menu);
261 while (mentry != NULL) {
262 rc = ui_menu_entry_paint(mentry, &pos);
263 if (rc != EOK)
264 goto error;
265
266 pos.y += ui_menu_entry_height(mentry);
267 mentry = ui_menu_entry_next(mentry);
268 }
269
270 rc = gfx_update(res->gc);
271 if (rc != EOK)
272 goto error;
273
274 return EOK;
275error:
276 return rc;
277}
278
279/** Unpaint menu.
280 *
281 * @param menu Menu
282 * @return EOK on success or an error code
283 */
284errno_t ui_menu_unpaint(ui_menu_t *menu)
285{
286 ui_resource_expose(menu->mbar->res);
287 return EOK;
288}
289
290/** Handle button press in menu.
291 *
292 * @param menu Menu
293 * @param spos Starting position (top-left corner)
[0262f16c]294 * @param event Position event
295 * @return ui_claimed iff the event was claimed
[214aefb]296 */
[0262f16c]297ui_evclaim_t ui_menu_pos_event(ui_menu_t *menu, gfx_coord2_t *spos,
298 pos_event_t *event)
[214aefb]299{
300 ui_menu_geom_t geom;
301 ui_menu_entry_t *mentry;
302 gfx_coord2_t pos;
[0262f16c]303 gfx_coord2_t epos;
304 ui_evclaim_t claimed;
[214aefb]305
306 ui_menu_get_geom(menu, spos, &geom);
[0262f16c]307 epos.x = event->hpos;
308 epos.y = event->vpos;
[214aefb]309
310 pos = geom.entries_rect.p0;
311
312 mentry = ui_menu_entry_first(menu);
313 while (mentry != NULL) {
[0262f16c]314 claimed = ui_menu_entry_pos_event(mentry, &pos, event);
315 if (claimed == ui_claimed)
316 return ui_claimed;
[214aefb]317
318 pos.y += ui_menu_entry_height(mentry);
319 mentry = ui_menu_entry_next(mentry);
320 }
[0262f16c]321
322 if (gfx_pix_inside_rect(&epos, &geom.outer_rect))
323 return ui_claimed;
324
325 return ui_unclaimed;
[214aefb]326}
327
328/** @}
329 */
Note: See TracBrowser for help on using the repository browser.