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

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

Puttext needs to know the color of the text being printed

So far we were using the GC's current drawing color. But unless there
was a way to read it, we could not render text-mode text in the correct
color.

  • Property mode set to 100644
File size: 10.2 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 ui_rbutton_t *old_selected;
319
320 if (!rbutton->held)
321 return;
322
323 rbutton->held = false;
324
325 if (rbutton->inside) {
326 /* Activate radio button */
327 old_selected = rbutton->group->selected;
328
329 if (old_selected != rbutton) {
330 rbutton->group->selected = rbutton;
331 ui_rbutton_paint(old_selected);
332 }
333
334 /* Repaint and notify */
335 (void) ui_rbutton_paint(rbutton);
336
337 if (old_selected != rbutton)
338 ui_rbutton_selected(rbutton);
339 }
340}
341
342/** Pointer entered button.
343 *
344 * @param rbutton Radio button
345 */
346void ui_rbutton_enter(ui_rbutton_t *rbutton)
347{
348 if (rbutton->inside)
349 return;
350
351 rbutton->inside = true;
352 if (rbutton->held)
353 (void) ui_rbutton_paint(rbutton);
354}
355
356/** Pointer left button.
357 *
358 * @param rbutton Radio button
359 */
360void ui_rbutton_leave(ui_rbutton_t *rbutton)
361{
362 if (!rbutton->inside)
363 return;
364
365 rbutton->inside = false;
366 if (rbutton->held)
367 (void) ui_rbutton_paint(rbutton);
368}
369
370/** Button was selected.
371 *
372 * @param rbutton Radio button
373 */
374void ui_rbutton_selected(ui_rbutton_t *rbutton)
375{
376 ui_rbutton_group_t *group = rbutton->group;
377
378 if (group->cb != NULL && group->cb->selected != NULL) {
379 group->cb->selected(group, group->arg, rbutton->arg);
380 }
381}
382
383/** Handle radio button position event.
384 *
385 * @param rbutton Radio button
386 * @param pos_event Position event
387 * @return @c ui_claimed iff the event is claimed
388 */
389ui_evclaim_t ui_rbutton_pos_event(ui_rbutton_t *rbutton, pos_event_t *event)
390{
391 gfx_coord2_t pos;
392 bool inside;
393
394 pos.x = event->hpos;
395 pos.y = event->vpos;
396
397 inside = gfx_pix_inside_rect(&pos, &rbutton->rect);
398
399 switch (event->type) {
400 case POS_PRESS:
401 if (inside) {
402 ui_rbutton_press(rbutton);
403 return ui_claimed;
404 }
405 break;
406 case POS_RELEASE:
407 if (rbutton->held) {
408 ui_rbutton_release(rbutton);
409 return ui_claimed;
410 }
411 break;
412 case POS_UPDATE:
413 if (inside && !rbutton->inside) {
414 ui_rbutton_enter(rbutton);
415 return ui_claimed;
416 } else if (!inside && rbutton->inside) {
417 ui_rbutton_leave(rbutton);
418 }
419 break;
420 }
421
422 return ui_unclaimed;
423}
424
425/** Destroy radio button control.
426 *
427 * @param arg Argument (ui_rbutton_t *)
428 */
429void ui_rbutton_ctl_destroy(void *arg)
430{
431 ui_rbutton_t *rbutton = (ui_rbutton_t *) arg;
432
433 ui_rbutton_destroy(rbutton);
434}
435
436/** Paint radio button control.
437 *
438 * @param arg Argument (ui_rbutton_t *)
439 * @return EOK on success or an error code
440 */
441errno_t ui_rbutton_ctl_paint(void *arg)
442{
443 ui_rbutton_t *rbutton = (ui_rbutton_t *) arg;
444
445 return ui_rbutton_paint(rbutton);
446}
447
448/** Handle radio button control position event.
449 *
450 * @param arg Argument (ui_rbutton_t *)
451 * @param pos_event Position event
452 * @return @c ui_claimed iff the event is claimed
453 */
454ui_evclaim_t ui_rbutton_ctl_pos_event(void *arg, pos_event_t *event)
455{
456 ui_rbutton_t *rbutton = (ui_rbutton_t *) arg;
457
458 return ui_rbutton_pos_event(rbutton, event);
459}
460
461/** @}
462 */
Note: See TracBrowser for help on using the repository browser.