source: mainline/uspace/lib/ui/src/rbutton.c@ 5de71df

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5de71df was 5de71df, checked in by Jiri Svoboda <jiri@…>, 4 years ago

Demonstrate entry alignment and read-only flag

We already have radio buttons and a check box that don't really
do anything useful so we might just use them.

  • Property mode set to 100644
File size: 10.4 KB
Line 
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 Radio button
34 */
35
36#include <errno.h>
37#include <gfx/color.h>
38#include <gfx/context.h>
39#include <gfx/render.h>
40#include <gfx/text.h>
41#include <io/pos_event.h>
42#include <stdlib.h>
43#include <str.h>
44#include <ui/control.h>
45#include <ui/paint.h>
46#include <ui/rbutton.h>
47#include "../private/rbutton.h"
48#include "../private/resource.h"
49
50enum {
51 rbutton_oframe_r = 7,
52 rbutton_iframe_r = 6,
53 rbutton_interior_r = 5,
54 rbutton_indicator_r = 3,
55 rbutton_label_margin = 8
56};
57
58static void ui_rbutton_ctl_destroy(void *);
59static errno_t ui_rbutton_ctl_paint(void *);
60static ui_evclaim_t ui_rbutton_ctl_pos_event(void *, pos_event_t *);
61
62/** Radio button control ops */
63ui_control_ops_t ui_rbutton_ops = {
64 .destroy = ui_rbutton_ctl_destroy,
65 .paint = ui_rbutton_ctl_paint,
66 .pos_event = ui_rbutton_ctl_pos_event
67};
68
69/** Create new radio button group.
70 *
71 * @param res UI resource
72 * @param rgroup Place to store pointer to new radio button group
73 * @return EOK on success, ENOMEM if out of memory
74 */
75errno_t ui_rbutton_group_create(ui_resource_t *res, ui_rbutton_group_t **rgroup)
76{
77 ui_rbutton_group_t *group;
78
79 group = calloc(1, sizeof(ui_rbutton_group_t));
80 if (group == NULL)
81 return ENOMEM;
82
83 group->res = res;
84 *rgroup = group;
85 return EOK;
86}
87
88/** Destroy radio button group.
89 *
90 * @param group Radio button group or @c NULL
91 */
92void ui_rbutton_group_destroy(ui_rbutton_group_t *group)
93{
94 if (group == NULL)
95 return;
96
97 free(group);
98}
99
100/** Create new radio button.
101 *
102 * @param group Radio button group
103 * @param caption Caption
104 * @param arg Callback argument
105 * @param rrbutton Place to store pointer to new radio button
106 * @return EOK on success, ENOMEM if out of memory
107 */
108errno_t ui_rbutton_create(ui_rbutton_group_t *group, const char *caption,
109 void *arg, ui_rbutton_t **rrbutton)
110{
111 ui_rbutton_t *rbutton;
112 errno_t rc;
113
114 rbutton = calloc(1, sizeof(ui_rbutton_t));
115 if (rbutton == NULL)
116 return ENOMEM;
117
118 rc = ui_control_new(&ui_rbutton_ops, (void *) rbutton,
119 &rbutton->control);
120 if (rc != EOK) {
121 free(rbutton);
122 return rc;
123 }
124
125 rbutton->caption = str_dup(caption);
126 if (rbutton->caption == NULL) {
127 ui_control_delete(rbutton->control);
128 free(rbutton);
129 return ENOMEM;
130 }
131
132 rbutton->group = group;
133 rbutton->arg = arg;
134
135 if (group->selected == NULL)
136 group->selected = rbutton;
137
138 *rrbutton = rbutton;
139 return EOK;
140}
141
142/** Destroy radio button.
143 *
144 * @param rbutton Radio button or @c NULL
145 */
146void ui_rbutton_destroy(ui_rbutton_t *rbutton)
147{
148 if (rbutton == NULL)
149 return;
150
151 ui_control_delete(rbutton->control);
152 free(rbutton);
153}
154
155/** Get base control from radio button.
156 *
157 * @param rbutton Radio button
158 * @return Control
159 */
160ui_control_t *ui_rbutton_ctl(ui_rbutton_t *rbutton)
161{
162 return rbutton->control;
163}
164
165/** Set radio button group callbacks.
166 *
167 * @param group Radio button group
168 * @param cb Radio button group callbacks
169 * @param arg Callback argument
170 */
171void ui_rbutton_group_set_cb(ui_rbutton_group_t *group,
172 ui_rbutton_group_cb_t *cb, void *arg)
173{
174 group->cb = cb;
175 group->arg = arg;
176}
177
178/** Set button rectangle.
179 *
180 * @param rbutton Button
181 * @param rect New button rectangle
182 */
183void ui_rbutton_set_rect(ui_rbutton_t *rbutton, gfx_rect_t *rect)
184{
185 rbutton->rect = *rect;
186}
187
188/** Paint radio button.
189 *
190 * @param rbutton Radio button
191 * @return EOK on success or an error code
192 */
193errno_t ui_rbutton_paint(ui_rbutton_t *rbutton)
194{
195 gfx_coord2_t pos;
196 gfx_coord2_t center;
197 gfx_text_fmt_t fmt;
198 bool depressed;
199 errno_t rc;
200
201 center.x = rbutton->rect.p0.x + rbutton_oframe_r;
202 center.y = rbutton->rect.p0.y + rbutton_oframe_r;
203
204 /* Paint rbutton frame */
205
206 rc = gfx_set_color(rbutton->group->res->gc,
207 rbutton->group->res->wnd_shadow_color);
208 if (rc != EOK)
209 goto error;
210
211 rc = ui_paint_filled_circle(rbutton->group->res->gc,
212 &center, rbutton_oframe_r, ui_fcircle_upleft);
213 if (rc != EOK)
214 goto error;
215
216 rc = gfx_set_color(rbutton->group->res->gc,
217 rbutton->group->res->wnd_highlight_color);
218 if (rc != EOK)
219 goto error;
220
221 rc = ui_paint_filled_circle(rbutton->group->res->gc,
222 &center, rbutton_oframe_r, ui_fcircle_lowright);
223 if (rc != EOK)
224 goto error;
225
226 rc = gfx_set_color(rbutton->group->res->gc,
227 rbutton->group->res->wnd_frame_sh_color);
228 if (rc != EOK)
229 goto error;
230
231 rc = ui_paint_filled_circle(rbutton->group->res->gc,
232 &center, rbutton_iframe_r, ui_fcircle_upleft);
233 if (rc != EOK)
234 goto error;
235
236 rc = gfx_set_color(rbutton->group->res->gc,
237 rbutton->group->res->wnd_face_color);
238 if (rc != EOK)
239 goto error;
240
241 rc = ui_paint_filled_circle(rbutton->group->res->gc,
242 &center, rbutton_iframe_r, ui_fcircle_lowright);
243 if (rc != EOK)
244 goto error;
245
246 /* Paint rbutton interior */
247 depressed = rbutton->held && rbutton->inside;
248
249 rc = gfx_set_color(rbutton->group->res->gc, depressed ?
250 rbutton->group->res->entry_act_bg_color :
251 rbutton->group->res->entry_bg_color);
252 if (rc != EOK)
253 goto error;
254
255 rc = ui_paint_filled_circle(rbutton->group->res->gc,
256 &center, rbutton_interior_r, ui_fcircle_entire);
257 if (rc != EOK)
258 goto error;
259
260 /* Paint active mark */
261
262 if (rbutton->group->selected == rbutton) {
263 rc = gfx_set_color(rbutton->group->res->gc,
264 rbutton->group->res->entry_fg_color);
265 if (rc != EOK)
266 goto error;
267
268 rc = ui_paint_filled_circle(rbutton->group->res->gc,
269 &center, rbutton_indicator_r, ui_fcircle_entire);
270 if (rc != EOK)
271 goto error;
272 }
273
274 /* Paint rbutton label */
275
276 pos.x = center.x + rbutton_oframe_r + rbutton_label_margin;
277 pos.y = center.y;
278
279 gfx_text_fmt_init(&fmt);
280 fmt.color = rbutton->group->res->wnd_text_color;
281 fmt.halign = gfx_halign_left;
282 fmt.valign = gfx_valign_center;
283
284 rc = gfx_puttext(rbutton->group->res->font, &pos, &fmt,
285 rbutton->caption);
286 if (rc != EOK)
287 goto error;
288
289 rc = gfx_update(rbutton->group->res->gc);
290 if (rc != EOK)
291 goto error;
292
293 return EOK;
294error:
295 return rc;
296}
297
298/** Press down button.
299 *
300 * @param rbutton Radio button
301 */
302void ui_rbutton_press(ui_rbutton_t *rbutton)
303{
304 if (rbutton->held)
305 return;
306
307 rbutton->inside = true;
308 rbutton->held = true;
309 (void) ui_rbutton_paint(rbutton);
310}
311
312/** Release button.
313 *
314 * @param rbutton Radio button
315 */
316void ui_rbutton_release(ui_rbutton_t *rbutton)
317{
318 if (!rbutton->held)
319 return;
320
321 rbutton->held = false;
322
323 if (rbutton->inside) {
324 /* Activate radio button */
325 ui_rbutton_select(rbutton);
326 }
327}
328
329/** Pointer entered button.
330 *
331 * @param rbutton Radio button
332 */
333void ui_rbutton_enter(ui_rbutton_t *rbutton)
334{
335 if (rbutton->inside)
336 return;
337
338 rbutton->inside = true;
339 if (rbutton->held)
340 (void) ui_rbutton_paint(rbutton);
341}
342
343/** Pointer left button.
344 *
345 * @param rbutton Radio button
346 */
347void ui_rbutton_leave(ui_rbutton_t *rbutton)
348{
349 if (!rbutton->inside)
350 return;
351
352 rbutton->inside = false;
353 if (rbutton->held)
354 (void) ui_rbutton_paint(rbutton);
355}
356
357/** Select radio button.
358 *
359 * @param rbutton Radio button
360 */
361void ui_rbutton_select(ui_rbutton_t *rbutton)
362{
363 ui_rbutton_t *old_selected;
364
365 old_selected = rbutton->group->selected;
366
367 if (old_selected != rbutton) {
368 rbutton->group->selected = rbutton;
369 ui_rbutton_paint(old_selected);
370 }
371
372 /* Repaint and notify */
373 (void) ui_rbutton_paint(rbutton);
374
375 if (old_selected != rbutton)
376 ui_rbutton_selected(rbutton);
377}
378
379/** Notify that button was selected.
380 *
381 * @param rbutton Radio button
382 */
383void ui_rbutton_selected(ui_rbutton_t *rbutton)
384{
385 ui_rbutton_group_t *group = rbutton->group;
386
387 if (group->cb != NULL && group->cb->selected != NULL) {
388 group->cb->selected(group, group->arg, rbutton->arg);
389 }
390}
391
392/** Handle radio button position event.
393 *
394 * @param rbutton Radio button
395 * @param pos_event Position event
396 * @return @c ui_claimed iff the event is claimed
397 */
398ui_evclaim_t ui_rbutton_pos_event(ui_rbutton_t *rbutton, pos_event_t *event)
399{
400 gfx_coord2_t pos;
401 bool inside;
402
403 pos.x = event->hpos;
404 pos.y = event->vpos;
405
406 inside = gfx_pix_inside_rect(&pos, &rbutton->rect);
407
408 switch (event->type) {
409 case POS_PRESS:
410 if (inside) {
411 ui_rbutton_press(rbutton);
412 return ui_claimed;
413 }
414 break;
415 case POS_RELEASE:
416 if (rbutton->held) {
417 ui_rbutton_release(rbutton);
418 return ui_claimed;
419 }
420 break;
421 case POS_UPDATE:
422 if (inside && !rbutton->inside) {
423 ui_rbutton_enter(rbutton);
424 return ui_claimed;
425 } else if (!inside && rbutton->inside) {
426 ui_rbutton_leave(rbutton);
427 }
428 break;
429 }
430
431 return ui_unclaimed;
432}
433
434/** Destroy radio button control.
435 *
436 * @param arg Argument (ui_rbutton_t *)
437 */
438void ui_rbutton_ctl_destroy(void *arg)
439{
440 ui_rbutton_t *rbutton = (ui_rbutton_t *) arg;
441
442 ui_rbutton_destroy(rbutton);
443}
444
445/** Paint radio button control.
446 *
447 * @param arg Argument (ui_rbutton_t *)
448 * @return EOK on success or an error code
449 */
450errno_t ui_rbutton_ctl_paint(void *arg)
451{
452 ui_rbutton_t *rbutton = (ui_rbutton_t *) arg;
453
454 return ui_rbutton_paint(rbutton);
455}
456
457/** Handle radio button control position event.
458 *
459 * @param arg Argument (ui_rbutton_t *)
460 * @param pos_event Position event
461 * @return @c ui_claimed iff the event is claimed
462 */
463ui_evclaim_t ui_rbutton_ctl_pos_event(void *arg, pos_event_t *event)
464{
465 ui_rbutton_t *rbutton = (ui_rbutton_t *) arg;
466
467 return ui_rbutton_pos_event(rbutton, event);
468}
469
470/** @}
471 */
Note: See TracBrowser for help on using the repository browser.