source: mainline/uspace/lib/ui/src/pbutton.c@ 4df6607

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

Paint controls via layout

  • Property mode set to 100644
File size: 9.9 KB
RevLine 
[f80690a]1/*
2 * Copyright (c) 2020 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 Push button
34 */
35
36#include <errno.h>
[47728678]37#include <gfx/color.h>
38#include <gfx/context.h>
39#include <gfx/render.h>
40#include <gfx/text.h>
[faca61b8]41#include <io/pos_event.h>
[f80690a]42#include <stdlib.h>
[47728678]43#include <str.h>
[8009dc27]44#include <ui/control.h>
[de9992c]45#include <ui/paint.h>
[f80690a]46#include <ui/pbutton.h>
47#include "../private/pbutton.h"
[47728678]48#include "../private/resource.h"
[f80690a]49
[f6df5a3]50/** Caption movement when button is pressed down */
51enum {
[c9a7adc]52 ui_pb_press_dx = 1,
53 ui_pb_press_dy = 1
[f6df5a3]54};
55
[4df6607]56static errno_t ui_pbutton_ctl_paint(void *);
[8009dc27]57static ui_evclaim_t ui_pbutton_ctl_pos_event(void *, pos_event_t *);
58
59/** Push button control ops */
60ui_control_ops_t ui_pbutton_ops = {
[4df6607]61 .paint = ui_pbutton_ctl_paint,
[8009dc27]62 .pos_event = ui_pbutton_ctl_pos_event
63};
64
[f80690a]65/** Create new push button.
66 *
[47728678]67 * @param resource UI resource
[f80690a]68 * @param caption Caption
69 * @param rpbutton Place to store pointer to new push button
70 * @return EOK on success, ENOMEM if out of memory
71 */
[47728678]72errno_t ui_pbutton_create(ui_resource_t *resource, const char *caption,
73 ui_pbutton_t **rpbutton)
[f80690a]74{
75 ui_pbutton_t *pbutton;
[8009dc27]76 errno_t rc;
[f80690a]77
78 pbutton = calloc(1, sizeof(ui_pbutton_t));
79 if (pbutton == NULL)
80 return ENOMEM;
81
[8009dc27]82 rc = ui_control_new(&ui_pbutton_ops, (void *) pbutton,
83 &pbutton->control);
84 if (rc != EOK) {
85 free(pbutton);
86 return rc;
87 }
88
[47728678]89 pbutton->caption = str_dup(caption);
90 if (pbutton->caption == NULL) {
[8009dc27]91 ui_control_delete(pbutton->control);
[47728678]92 free(pbutton);
93 return ENOMEM;
94 }
95
96 pbutton->res = resource;
[f80690a]97 *rpbutton = pbutton;
98 return EOK;
99}
100
101/** Destroy push button.
102 *
103 * @param pbutton Push button or @c NULL
104 */
105void ui_pbutton_destroy(ui_pbutton_t *pbutton)
106{
107 if (pbutton == NULL)
108 return;
109
[8009dc27]110 ui_control_delete(pbutton->control);
[f80690a]111 free(pbutton);
112}
113
[8009dc27]114/** Get base control from push button.
115 *
116 * @param pbutton Push button
117 * @return Control
118 */
119ui_control_t *ui_pbutton_ctl(ui_pbutton_t *pbutton)
120{
121 return pbutton->control;
122}
123
[8ef48ece]124/** Set push button callbacks.
125 *
126 * @param pbutton Push button
127 * @param cb Push button callbacks
128 * @param arg Callback argument
129 */
130void ui_pbutton_set_cb(ui_pbutton_t *pbutton, ui_pbutton_cb_t *cb, void *arg)
131{
132 pbutton->cb = cb;
133 pbutton->arg = arg;
134}
135
[47728678]136/** Set button rectangle.
137 *
138 * @param pbutton Button
[ba09d06]139 * @param rect New button rectangle
[47728678]140 */
141void ui_pbutton_set_rect(ui_pbutton_t *pbutton, gfx_rect_t *rect)
142{
143 pbutton->rect = *rect;
144}
145
[c9a7adc]146/** Set default flag.
147 *
148 * Default button is the one activated by Enter key, it is marked
149 * by thicker frame.
150 *
151 * @param pbutton Button
152 * @param isdefault @c true iff button is default
153 */
154void ui_pbutton_set_default(ui_pbutton_t *pbutton, bool isdefault)
155{
156 pbutton->isdefault = isdefault;
157}
158
159/** Paint outer button frame.
[47728678]160 *
161 * @param pbutton Push button
162 * @return EOK on success or an error code
163 */
[c9a7adc]164static errno_t ui_pbutton_paint_frame(ui_pbutton_t *pbutton)
[47728678]165{
[c9a7adc]166 gfx_rect_t rect;
167 gfx_coord_t thickness;
[47728678]168 errno_t rc;
169
[c9a7adc]170 thickness = pbutton->isdefault ? 2 : 1;
171
[de9992c]172 rc = gfx_set_color(pbutton->res->gc, pbutton->res->btn_frame_color);
[c9a7adc]173 if (rc != EOK)
174 goto error;
175
176 rect.p0.x = pbutton->rect.p0.x + 1;
177 rect.p0.y = pbutton->rect.p0.y;
178 rect.p1.x = pbutton->rect.p1.x - 1;
179 rect.p1.y = pbutton->rect.p0.y + thickness;
180 rc = gfx_fill_rect(pbutton->res->gc, &rect);
181 if (rc != EOK)
182 goto error;
183
184 rect.p0.x = pbutton->rect.p0.x + 1;
185 rect.p0.y = pbutton->rect.p1.y - thickness;
186 rect.p1.x = pbutton->rect.p1.x - 1;
187 rect.p1.y = pbutton->rect.p1.y;
188 rc = gfx_fill_rect(pbutton->res->gc, &rect);
189 if (rc != EOK)
190 goto error;
191
192 rect.p0.x = pbutton->rect.p0.x;
193 rect.p0.y = pbutton->rect.p0.y + 1;
194 rect.p1.x = pbutton->rect.p0.x + thickness;
195 rect.p1.y = pbutton->rect.p1.y - 1;
196 rc = gfx_fill_rect(pbutton->res->gc, &rect);
197 if (rc != EOK)
198 goto error;
199
200 rect.p0.x = pbutton->rect.p1.x - thickness;
201 rect.p0.y = pbutton->rect.p0.y + 1;
202 rect.p1.x = pbutton->rect.p1.x;
203 rect.p1.y = pbutton->rect.p1.y - 1;
204 rc = gfx_fill_rect(pbutton->res->gc, &rect);
205 if (rc != EOK)
206 goto error;
207
208 return EOK;
209error:
210 return rc;
211}
212
213/** Paint outset button bevel.
214 *
215 * @param pbutton Push button
216 * @return EOK on success or an error code
217 */
218static errno_t ui_pbutton_paint_outset(ui_pbutton_t *pbutton,
219 gfx_rect_t *rect)
220{
[de9992c]221 return ui_paint_bevel(pbutton->res->gc, rect,
222 pbutton->res->btn_highlight_color,
223 pbutton->res->btn_shadow_color, 2, NULL);
[c9a7adc]224}
225
226/** Paint inset button bevel.
227 *
228 * @param pbutton Push button
229 * @return EOK on success or an error code
230 */
231static errno_t ui_pbutton_paint_inset(ui_pbutton_t *pbutton,
232 gfx_rect_t *rect)
233{
[de9992c]234 return ui_paint_bevel(pbutton->res->gc, rect,
235 pbutton->res->btn_shadow_color,
236 pbutton->res->btn_face_color, 2, NULL);
[c9a7adc]237}
238
239/** Paint push button.
240 *
241 * @param pbutton Push button
242 * @return EOK on success or an error code
243 */
244errno_t ui_pbutton_paint(ui_pbutton_t *pbutton)
245{
246 gfx_coord2_t pos;
247 gfx_text_fmt_t fmt;
248 gfx_rect_t rect;
249 gfx_coord_t thickness;
[8ef48ece]250 bool depressed;
[c9a7adc]251 errno_t rc;
252
253 thickness = pbutton->isdefault ? 2 : 1;
[8ef48ece]254 depressed = pbutton->held && pbutton->inside;
[c9a7adc]255
256 rect.p0.x = pbutton->rect.p0.x + thickness;
257 rect.p0.y = pbutton->rect.p0.y + thickness;
258 rect.p1.x = pbutton->rect.p1.x - thickness;
259 rect.p1.y = pbutton->rect.p1.y - thickness;
260
[de9992c]261 rc = gfx_set_color(pbutton->res->gc, pbutton->res->btn_face_color);
[c9a7adc]262 if (rc != EOK)
263 goto error;
264
265 rc = gfx_fill_rect(pbutton->res->gc, &rect);
266 if (rc != EOK)
267 goto error;
268
[de9992c]269 rc = gfx_set_color(pbutton->res->gc, pbutton->res->btn_text_color);
[47728678]270 if (rc != EOK)
271 goto error;
272
273 /* Center of button rectangle */
[c9a7adc]274 pos.x = (rect.p0.x + rect.p1.x) / 2;
275 pos.y = (rect.p0.y + rect.p1.y) / 2;
[47728678]276
[8ef48ece]277 if (depressed) {
[f6df5a3]278 pos.x += ui_pb_press_dx;
279 pos.y += ui_pb_press_dy;
280 }
281
[47728678]282 gfx_text_fmt_init(&fmt);
283 fmt.halign = gfx_halign_center;
284 fmt.valign = gfx_valign_center;
285
286 rc = gfx_puttext(pbutton->res->font, &pos, &fmt, pbutton->caption);
287 if (rc != EOK)
288 goto error;
289
[c9a7adc]290 rc = ui_pbutton_paint_frame(pbutton);
291 if (rc != EOK)
292 goto error;
293
[8ef48ece]294 if (depressed) {
[c9a7adc]295 rc = ui_pbutton_paint_inset(pbutton, &rect);
296 if (rc != EOK)
297 goto error;
298 } else {
299 rc = ui_pbutton_paint_outset(pbutton, &rect);
300 if (rc != EOK)
301 goto error;
302 }
[47728678]303
304 return EOK;
305error:
306 return rc;
307}
308
[f6df5a3]309/** Press down button.
310 *
311 * @param pbutton Push button
312 */
313void ui_pbutton_press(ui_pbutton_t *pbutton)
314{
[8ef48ece]315 if (pbutton->held)
316 return;
317
318 pbutton->inside = true;
[f6df5a3]319 pbutton->held = true;
[8ef48ece]320 (void) ui_pbutton_paint(pbutton);
[f6df5a3]321}
322
323/** Release button.
324 *
325 * @param pbutton Push button
326 */
327void ui_pbutton_release(ui_pbutton_t *pbutton)
328{
[8ef48ece]329 if (!pbutton->held)
330 return;
331
[f6df5a3]332 pbutton->held = false;
[8ef48ece]333
334 if (pbutton->inside) {
335 (void) ui_pbutton_paint(pbutton);
336 ui_pbutton_clicked(pbutton);
337 }
338}
339
340/** Pointer entered button.
341 *
342 * @param pbutton Push button
343 */
344void ui_pbutton_enter(ui_pbutton_t *pbutton)
345{
346 if (pbutton->inside)
347 return;
348
349 pbutton->inside = true;
350 if (pbutton->held)
351 (void) ui_pbutton_paint(pbutton);
352}
353
354/** Pointer left button.
355 *
356 * @param pbutton Push button
357 */
358void ui_pbutton_leave(ui_pbutton_t *pbutton)
359{
360 if (!pbutton->inside)
361 return;
362
363 pbutton->inside = false;
364 if (pbutton->held)
365 (void) ui_pbutton_paint(pbutton);
366}
367
368/** Button was clicked.
369 *
370 * @param pbutton Push button
371 */
372void ui_pbutton_clicked(ui_pbutton_t *pbutton)
373{
374 if (pbutton->cb != NULL && pbutton->cb->clicked != NULL)
375 pbutton->cb->clicked(pbutton, pbutton->arg);
[f6df5a3]376}
377
[faca61b8]378/** Handle push button position event.
379 *
380 * @param pbutton Push button
381 * @param pos_event Position event
[a2f173b]382 * @return @c ui_claimed iff the event is claimed
[faca61b8]383 */
[a2f173b]384ui_evclaim_t ui_pbutton_pos_event(ui_pbutton_t *pbutton, pos_event_t *event)
[faca61b8]385{
386 gfx_coord2_t pos;
[8ef48ece]387 bool inside;
[faca61b8]388
389 pos.x = event->hpos;
390 pos.y = event->vpos;
391
[8ef48ece]392 inside = gfx_pix_inside_rect(&pos, &pbutton->rect);
[faca61b8]393
[8ef48ece]394 switch (event->type) {
395 case POS_PRESS:
[a2f173b]396 if (inside) {
[8ef48ece]397 ui_pbutton_press(pbutton);
[a2f173b]398 return ui_claimed;
399 }
[8ef48ece]400 break;
401 case POS_RELEASE:
[a2f173b]402 if (pbutton->held) {
403 ui_pbutton_release(pbutton);
404 return ui_claimed;
405 }
[8ef48ece]406 break;
407 case POS_UPDATE:
408 if (inside && !pbutton->inside) {
409 ui_pbutton_enter(pbutton);
[a2f173b]410 return ui_claimed;
[8ef48ece]411 } else if (!inside && pbutton->inside) {
412 ui_pbutton_leave(pbutton);
413 }
414 break;
[faca61b8]415 }
[a2f173b]416
417 return ui_unclaimed;
[faca61b8]418}
419
[4df6607]420/** Paint push button control.
421 *
422 * @param arg Argument (ui_pbutton_t *)
423 * @return EOK on success or an error code
424 */
425errno_t ui_pbutton_ctl_paint(void *arg)
426{
427 ui_pbutton_t *pbutton = (ui_pbutton_t *) arg;
428
429 return ui_pbutton_paint(pbutton);
430}
431
[8009dc27]432/** Handle push button control position event.
433 *
434 * @param arg Argument (ui_pbutton_t *)
435 * @param pos_event Position event
436 * @return @c ui_claimed iff the event is claimed
437 */
438ui_evclaim_t ui_pbutton_ctl_pos_event(void *arg, pos_event_t *event)
439{
440 ui_pbutton_t *pbutton = (ui_pbutton_t *) arg;
441
442 return ui_pbutton_pos_event(pbutton, event);
443}
444
[f80690a]445/** @}
446 */
Note: See TracBrowser for help on using the repository browser.