source: mainline/uspace/lib/ui/src/checkbox.c@ 11662bd

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 11662bd was 86fff971, checked in by Jiri Svoboda <jiri@…>, 3 years ago

'X' does not mark the spot

Stop misusing 'X' character as a cross mark, create a routine for
drawing a cross and use it as a custom decoration for the close button.
Also use it for checkbox cross.

  • Property mode set to 100644
File size: 9.8 KB
Line 
1/*
2 * Copyright (c) 2022 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 Check box
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/checkbox.h>
47#include "../private/checkbox.h"
48#include "../private/resource.h"
49
50enum {
51 checkbox_box_w = 16,
52 checkbox_box_h = 16,
53 checkbox_label_margin = 8,
54 checkbox_cross_n = 5,
55 checkbox_cross_w = 2,
56 checkbox_cross_h = 2
57};
58
59static void ui_checkbox_ctl_destroy(void *);
60static errno_t ui_checkbox_ctl_paint(void *);
61static ui_evclaim_t ui_checkbox_ctl_pos_event(void *, pos_event_t *);
62
63/** Check box control ops */
64ui_control_ops_t ui_checkbox_ops = {
65 .destroy = ui_checkbox_ctl_destroy,
66 .paint = ui_checkbox_ctl_paint,
67 .pos_event = ui_checkbox_ctl_pos_event
68};
69
70/** Create new check box.
71 *
72 * @param resource UI resource
73 * @param caption Caption
74 * @param rcheckbox Place to store pointer to new check box
75 * @return EOK on success, ENOMEM if out of memory
76 */
77errno_t ui_checkbox_create(ui_resource_t *resource, const char *caption,
78 ui_checkbox_t **rcheckbox)
79{
80 ui_checkbox_t *checkbox;
81 errno_t rc;
82
83 checkbox = calloc(1, sizeof(ui_checkbox_t));
84 if (checkbox == NULL)
85 return ENOMEM;
86
87 rc = ui_control_new(&ui_checkbox_ops, (void *) checkbox,
88 &checkbox->control);
89 if (rc != EOK) {
90 free(checkbox);
91 return rc;
92 }
93
94 checkbox->caption = str_dup(caption);
95 if (checkbox->caption == NULL) {
96 ui_control_delete(checkbox->control);
97 free(checkbox);
98 return ENOMEM;
99 }
100
101 checkbox->res = resource;
102 *rcheckbox = checkbox;
103 return EOK;
104}
105
106/** Destroy check box.
107 *
108 * @param checkbox Check box or @c NULL
109 */
110void ui_checkbox_destroy(ui_checkbox_t *checkbox)
111{
112 if (checkbox == NULL)
113 return;
114
115 ui_control_delete(checkbox->control);
116 free(checkbox);
117}
118
119/** Get base control from check box.
120 *
121 * @param checkbox Check box
122 * @return Control
123 */
124ui_control_t *ui_checkbox_ctl(ui_checkbox_t *checkbox)
125{
126 return checkbox->control;
127}
128
129/** Set check box callbacks.
130 *
131 * @param checkbox Check box
132 * @param cb Check box callbacks
133 * @param arg Callback argument
134 */
135void ui_checkbox_set_cb(ui_checkbox_t *checkbox, ui_checkbox_cb_t *cb, void *arg)
136{
137 checkbox->cb = cb;
138 checkbox->arg = arg;
139}
140
141/** Set button rectangle.
142 *
143 * @param checkbox Button
144 * @param rect New button rectangle
145 */
146void ui_checkbox_set_rect(ui_checkbox_t *checkbox, gfx_rect_t *rect)
147{
148 checkbox->rect = *rect;
149}
150
151/** Paint check box in graphics mode.
152 *
153 * @param checkbox Check box
154 * @return EOK on success or an error code
155 */
156errno_t ui_checkbox_paint_gfx(ui_checkbox_t *checkbox)
157{
158 gfx_coord2_t pos;
159 gfx_text_fmt_t fmt;
160 gfx_rect_t box_rect;
161 gfx_rect_t box_inside;
162 gfx_coord2_t box_center;
163 bool depressed;
164 errno_t rc;
165
166 box_rect.p0 = checkbox->rect.p0;
167 box_rect.p1.x = box_rect.p0.x + checkbox_box_w;
168 box_rect.p1.y = box_rect.p0.y + checkbox_box_h;
169
170 /* Paint checkbox frame */
171
172 rc = ui_paint_inset_frame(checkbox->res, &box_rect, &box_inside);
173 if (rc != EOK)
174 goto error;
175
176 /* Paint checkbox interior */
177
178 depressed = checkbox->held && checkbox->inside;
179
180 rc = gfx_set_color(checkbox->res->gc, depressed ?
181 checkbox->res->entry_act_bg_color :
182 checkbox->res->entry_bg_color);
183 if (rc != EOK)
184 goto error;
185
186 rc = gfx_fill_rect(checkbox->res->gc, &box_inside);
187 if (rc != EOK)
188 goto error;
189
190 /* Paint cross mark */
191
192 if (checkbox->checked) {
193 rc = gfx_set_color(checkbox->res->gc,
194 checkbox->res->entry_fg_color);
195 if (rc != EOK)
196 goto error;
197
198 box_center.x = (box_inside.p0.x + box_inside.p1.x) / 2 - 1;
199 box_center.y = (box_inside.p0.y + box_inside.p1.y) / 2 - 1;
200
201 rc = ui_paint_cross(checkbox->res->gc, &box_center,
202 checkbox_cross_n, checkbox_cross_w, checkbox_cross_h);
203 if (rc != EOK)
204 goto error;
205 }
206
207 /* Paint checkbox label */
208
209 pos.x = box_rect.p1.x + checkbox_label_margin;
210 pos.y = (box_rect.p0.y + box_rect.p1.y) / 2;
211
212 gfx_text_fmt_init(&fmt);
213 fmt.font = checkbox->res->font;
214 fmt.color = checkbox->res->wnd_text_color;
215 fmt.halign = gfx_halign_left;
216 fmt.valign = gfx_valign_center;
217
218 rc = gfx_puttext(&pos, &fmt, checkbox->caption);
219 if (rc != EOK)
220 goto error;
221
222 rc = gfx_update(checkbox->res->gc);
223 if (rc != EOK)
224 goto error;
225
226 return EOK;
227error:
228 return rc;
229}
230
231/** Paint check box in text mode.
232 *
233 * @param checkbox Check box
234 * @return EOK on success or an error code
235 */
236errno_t ui_checkbox_paint_text(ui_checkbox_t *checkbox)
237{
238 gfx_coord2_t pos;
239 gfx_text_fmt_t fmt;
240 bool depressed;
241 errno_t rc;
242
243 /* Paint checkbox */
244
245 depressed = checkbox->held && checkbox->inside;
246
247 pos.x = checkbox->rect.p0.x;
248 pos.y = checkbox->rect.p0.y;
249
250 gfx_text_fmt_init(&fmt);
251 fmt.font = checkbox->res->font;
252 fmt.color = depressed ? checkbox->res->entry_act_bg_color :
253 checkbox->res->wnd_text_color;
254 fmt.halign = gfx_halign_left;
255 fmt.valign = gfx_valign_top;
256
257 rc = gfx_puttext(&pos, &fmt, checkbox->checked ? "[X]" : "[ ]");
258 if (rc != EOK)
259 goto error;
260
261 /* Paint checkbox label */
262
263 pos.x += 4;
264 fmt.color = checkbox->res->wnd_text_color;
265
266 rc = gfx_puttext(&pos, &fmt, checkbox->caption);
267 if (rc != EOK)
268 goto error;
269
270 rc = gfx_update(checkbox->res->gc);
271 if (rc != EOK)
272 goto error;
273
274 return EOK;
275error:
276 return rc;
277}
278
279/** Paint check box.
280 *
281 * @param checkbox Check box
282 * @return EOK on success or an error code
283 */
284errno_t ui_checkbox_paint(ui_checkbox_t *checkbox)
285{
286 if (checkbox->res->textmode)
287 return ui_checkbox_paint_text(checkbox);
288 else
289 return ui_checkbox_paint_gfx(checkbox);
290}
291
292/** Press down button.
293 *
294 * @param checkbox Check box
295 */
296void ui_checkbox_press(ui_checkbox_t *checkbox)
297{
298 if (checkbox->held)
299 return;
300
301 checkbox->inside = true;
302 checkbox->held = true;
303 (void) ui_checkbox_paint(checkbox);
304}
305
306/** Release button.
307 *
308 * @param checkbox Check box
309 */
310void ui_checkbox_release(ui_checkbox_t *checkbox)
311{
312 if (!checkbox->held)
313 return;
314
315 checkbox->held = false;
316
317 if (checkbox->inside) {
318 /* Toggle check box state */
319 checkbox->checked = !checkbox->checked;
320
321 /* Repaint and notify */
322 (void) ui_checkbox_paint(checkbox);
323 ui_checkbox_switched(checkbox);
324 }
325}
326
327/** Pointer entered button.
328 *
329 * @param checkbox Check box
330 */
331void ui_checkbox_enter(ui_checkbox_t *checkbox)
332{
333 if (checkbox->inside)
334 return;
335
336 checkbox->inside = true;
337 if (checkbox->held)
338 (void) ui_checkbox_paint(checkbox);
339}
340
341/** Pointer left button.
342 *
343 * @param checkbox Check box
344 */
345void ui_checkbox_leave(ui_checkbox_t *checkbox)
346{
347 if (!checkbox->inside)
348 return;
349
350 checkbox->inside = false;
351 if (checkbox->held)
352 (void) ui_checkbox_paint(checkbox);
353}
354
355/** Button was switched.
356 *
357 * @param checkbox Check box
358 */
359void ui_checkbox_switched(ui_checkbox_t *checkbox)
360{
361 if (checkbox->cb != NULL && checkbox->cb->switched != NULL) {
362 checkbox->cb->switched(checkbox, checkbox->arg,
363 checkbox->checked);
364 }
365}
366
367/** Handle check box position event.
368 *
369 * @param checkbox Check box
370 * @param pos_event Position event
371 * @return @c ui_claimed iff the event is claimed
372 */
373ui_evclaim_t ui_checkbox_pos_event(ui_checkbox_t *checkbox, pos_event_t *event)
374{
375 gfx_coord2_t pos;
376 bool inside;
377
378 pos.x = event->hpos;
379 pos.y = event->vpos;
380
381 inside = gfx_pix_inside_rect(&pos, &checkbox->rect);
382
383 switch (event->type) {
384 case POS_PRESS:
385 if (inside) {
386 ui_checkbox_press(checkbox);
387 return ui_claimed;
388 }
389 break;
390 case POS_RELEASE:
391 if (checkbox->held) {
392 ui_checkbox_release(checkbox);
393 return ui_claimed;
394 }
395 break;
396 case POS_UPDATE:
397 if (inside && !checkbox->inside) {
398 ui_checkbox_enter(checkbox);
399 return ui_claimed;
400 } else if (!inside && checkbox->inside) {
401 ui_checkbox_leave(checkbox);
402 }
403 break;
404 case POS_DCLICK:
405 break;
406 }
407
408 return ui_unclaimed;
409}
410
411/** Destroy check box control.
412 *
413 * @param arg Argument (ui_checkbox_t *)
414 */
415void ui_checkbox_ctl_destroy(void *arg)
416{
417 ui_checkbox_t *checkbox = (ui_checkbox_t *) arg;
418
419 ui_checkbox_destroy(checkbox);
420}
421
422/** Paint check box control.
423 *
424 * @param arg Argument (ui_checkbox_t *)
425 * @return EOK on success or an error code
426 */
427errno_t ui_checkbox_ctl_paint(void *arg)
428{
429 ui_checkbox_t *checkbox = (ui_checkbox_t *) arg;
430
431 return ui_checkbox_paint(checkbox);
432}
433
434/** Handle check box control position event.
435 *
436 * @param arg Argument (ui_checkbox_t *)
437 * @param pos_event Position event
438 * @return @c ui_claimed iff the event is claimed
439 */
440ui_evclaim_t ui_checkbox_ctl_pos_event(void *arg, pos_event_t *event)
441{
442 ui_checkbox_t *checkbox = (ui_checkbox_t *) arg;
443
444 return ui_checkbox_pos_event(checkbox, event);
445}
446
447/** @}
448 */
Note: See TracBrowser for help on using the repository browser.