Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset 7481ee19 in mainline


Ignore:
Timestamp:
2021-06-23T08:15:00Z (4 months ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master
Children:
a977e37
Parents:
034ce6bb
git-author:
Jiri Svoboda <jiri@…> (2021-06-22 17:14:40)
git-committer:
Jiri Svoboda <jiri@…> (2021-06-23 08:15:00)
Message:

Basic editable text entry

Location:
uspace
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/calculator/calculator.c

    r034ce6bb r7481ee19  
    945945        ui_entry_set_rect(display, &calc.geom.entry_rect);
    946946        ui_entry_set_halign(display, gfx_halign_right);
     947        ui_entry_set_read_only(display, true);
    947948
    948949        rc = ui_fixed_add(fixed, ui_entry_ctl(display));
  • uspace/lib/ui/include/types/ui/control.h

    r034ce6bb r7481ee19  
    11/*
    2  * Copyright (c) 2020 Jiri Svoboda
     2 * Copyright (c) 2021 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3838
    3939#include <errno.h>
     40#include <io/kbd_event.h>
    4041#include <io/pos_event.h>
    4142#include <types/ui/event.h>
     
    5051        /** Paint */
    5152        errno_t (*paint)(void *);
     53        /** Keyboard event */
     54        ui_evclaim_t (*kbd_event)(void *, kbd_event_t *);
    5255        /** Position event */
    5356        ui_evclaim_t (*pos_event)(void *, pos_event_t *);
  • uspace/lib/ui/include/ui/control.h

    r034ce6bb r7481ee19  
    11/*
    2  * Copyright (c) 2020 Jiri Svoboda
     2 * Copyright (c) 2021 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3838
    3939#include <errno.h>
     40#include <io/kbd_event.h>
    4041#include <io/pos_event.h>
    4142#include <types/ui/control.h>
     
    4647extern void ui_control_destroy(ui_control_t *);
    4748extern errno_t ui_control_paint(ui_control_t *);
     49extern ui_evclaim_t ui_control_kbd_event(ui_control_t *, kbd_event_t *);
    4850extern ui_evclaim_t ui_control_pos_event(ui_control_t *, pos_event_t *);
    4951extern void ui_control_unfocus(ui_control_t *);
  • uspace/lib/ui/include/ui/entry.h

    r034ce6bb r7481ee19  
    5050extern void ui_entry_set_rect(ui_entry_t *, gfx_rect_t *);
    5151extern void ui_entry_set_halign(ui_entry_t *, gfx_halign_t);
     52extern void ui_entry_set_read_only(ui_entry_t *, bool);
    5253extern errno_t ui_entry_set_text(ui_entry_t *, const char *);
    5354extern errno_t ui_entry_paint(ui_entry_t *);
     55extern ui_evclaim_t ui_entry_kbd_event(ui_entry_t *, kbd_event_t *);
     56extern ui_evclaim_t ui_entry_pos_event(ui_entry_t *, pos_event_t *);
    5457
    5558#endif
  • uspace/lib/ui/include/ui/fixed.h

    r034ce6bb r7481ee19  
    11/*
    2  * Copyright (c) 2020 Jiri Svoboda
     2 * Copyright (c) 2021 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4949extern void ui_fixed_remove(ui_fixed_t *, ui_control_t *);
    5050extern errno_t ui_fixed_paint(ui_fixed_t *);
     51extern ui_evclaim_t ui_fixed_kbd_event(ui_fixed_t *, kbd_event_t *);
    5152extern ui_evclaim_t ui_fixed_pos_event(ui_fixed_t *, pos_event_t *);
    5253extern void ui_fixed_unfocus(ui_fixed_t *);
  • uspace/lib/ui/include/ui/window.h

    r034ce6bb r7481ee19  
    4040#include <gfx/context.h>
    4141#include <gfx/coord.h>
     42#include <io/kbd_event.h>
    4243#include <io/pos_event.h>
    4344#include <types/ui/control.h>
     
    6263extern void ui_window_set_ctl_cursor(ui_window_t *, ui_stock_cursor_t);
    6364extern errno_t ui_window_paint(ui_window_t *);
     65extern void ui_window_def_kbd(ui_window_t *, kbd_event_t *);
    6466extern errno_t ui_window_def_paint(ui_window_t *);
    6567extern void ui_window_def_pos(ui_window_t *, pos_event_t *);
  • uspace/lib/ui/private/entry.h

    r034ce6bb r7481ee19  
    5454        /** Horizontal alignment */
    5555        gfx_halign_t halign;
     56        /** Text entry is read-only */
     57        bool read_only;
    5658        /** Text */
    5759        char *text;
    5860        /** Pointer is currently inside */
    5961        bool pointer_inside;
     62        /** Entry is activated */
     63        bool active;
    6064};
     65
     66extern errno_t ui_entry_insert_str(ui_entry_t *, const char *);
     67extern void ui_entry_backspace(ui_entry_t *);
     68extern ui_evclaim_t ui_entry_key_press_unmod(ui_entry_t *, kbd_event_t *);
    6169
    6270#endif
  • uspace/lib/ui/src/control.c

    r034ce6bb r7481ee19  
    11/*
    2  * Copyright (c) 2020 Jiri Svoboda
     2 * Copyright (c) 2021 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3535
    3636#include <errno.h>
     37#include <io/kbd_event.h>
    3738#include <io/pos_event.h>
    3839#include <stdlib.h>
     
    9192}
    9293
     94/** Deliver keyboard event to UI control.
     95 *
     96 * @param control Control
     97 * @param kbd_event Keyboard event
     98 * @return @c ui_claimed iff the event is claimed
     99 */
     100ui_evclaim_t ui_control_kbd_event(ui_control_t *control, kbd_event_t *event)
     101{
     102        if (control->ops->kbd_event != NULL)
     103                return control->ops->kbd_event(control->ext, event);
     104        else
     105                return ui_unclaimed;
     106}
     107
    93108/** Paint UI control.
    94109 *
  • uspace/lib/ui/src/entry.c

    r034ce6bb r7481ee19  
    5353static void ui_entry_ctl_destroy(void *);
    5454static errno_t ui_entry_ctl_paint(void *);
     55static ui_evclaim_t ui_entry_ctl_kbd_event(void *, kbd_event_t *);
    5556static ui_evclaim_t ui_entry_ctl_pos_event(void *, pos_event_t *);
    5657
     
    6667        .destroy = ui_entry_ctl_destroy,
    6768        .paint = ui_entry_ctl_paint,
     69        .kbd_event = ui_entry_ctl_kbd_event,
    6870        .pos_event = ui_entry_ctl_pos_event
    6971};
     
    148150}
    149151
     152/** Set text entry read-only flag.
     153 *
     154 * @param entry Text entry
     155 * @param read_only True iff entry is to be read-only.
     156 */
     157void ui_entry_set_read_only(ui_entry_t *entry, bool read_only)
     158{
     159        entry->read_only = read_only;
     160}
     161
    150162/** Set entry text.
    151163 *
     
    180192        gfx_coord_t hpad;
    181193        gfx_coord_t vpad;
     194        gfx_coord_t width;
    182195        gfx_rect_t inside;
    183196        errno_t rc;
     
    212225                goto error;
    213226
     227        width = gfx_text_width(res->font, entry->text);
     228
    214229        switch (entry->halign) {
    215230        case gfx_halign_left:
     
    218233                break;
    219234        case gfx_halign_center:
    220                 pos.x = (inside.p0.x + inside.p1.x) / 2;
     235                pos.x = (inside.p0.x + inside.p1.x) / 2 - width / 2;
    221236                break;
    222237        case gfx_halign_right:
    223                 pos.x = inside.p1.x - hpad - 1;
     238                pos.x = inside.p1.x - hpad - 1 - width;
    224239                break;
    225240        }
     
    229244        gfx_text_fmt_init(&fmt);
    230245        fmt.color = res->entry_fg_color;
    231         fmt.halign = entry->halign;
     246        fmt.halign = gfx_halign_left;
    232247        fmt.valign = gfx_valign_top;
    233248
     249        rc = gfx_set_clip_rect(res->gc, &inside);
     250        if (rc != EOK)
     251                goto error;
     252
    234253        rc = gfx_puttext(res->font, &pos, &fmt, entry->text);
     254        if (rc != EOK) {
     255                (void) gfx_set_clip_rect(res->gc, NULL);
     256                goto error;
     257        }
     258
     259        if (entry->active) {
     260                /* Cursor */
     261                pos.x += width;
     262
     263                rc = gfx_puttext(res->font, &pos, &fmt, "_");
     264                if (rc != EOK) {
     265                        (void) gfx_set_clip_rect(res->gc, NULL);
     266                        goto error;
     267                }
     268        }
     269
     270        rc = gfx_set_clip_rect(res->gc, NULL);
    235271        if (rc != EOK)
    236272                goto error;
     
    268304}
    269305
    270 /** Handle text entry control position event.
    271  *
    272  * @param arg Argument (ui_entry_t *)
     306/** Insert string at cursor position.
     307 *
     308 * @param entry Text entry
     309 * @param str String
     310 * @return EOK on success, ENOMEM if out of memory
     311 */
     312errno_t ui_entry_insert_str(ui_entry_t *entry, const char *str)
     313{
     314        char *newtext;
     315        char *oldtext;
     316        int rc;
     317
     318        rc = asprintf(&newtext, "%s%s", entry->text, str);
     319        if (rc < 0)
     320                return ENOMEM;
     321
     322        oldtext = entry->text;
     323        entry->text = newtext;
     324        free(oldtext);
     325        ui_entry_paint(entry);
     326
     327        return EOK;
     328}
     329
     330/** Delete character before cursor.
     331 *
     332 * @param entry Text entry
     333 */
     334void ui_entry_backspace(ui_entry_t *entry)
     335{
     336        size_t off;
     337
     338        off = str_size(entry->text);
     339        (void) str_decode_reverse(entry->text, &off,
     340            str_size(entry->text));
     341        entry->text[off] = '\0';
     342        ui_entry_paint(entry);
     343}
     344
     345/** Handle text entry key press without modifiers.
     346 *
     347 * @param entry Text entry
     348 * @param kbd_event Keyboard event
     349 * @return @c ui_claimed iff the event is claimed
     350 */
     351ui_evclaim_t ui_entry_key_press_unmod(ui_entry_t *entry, kbd_event_t *event)
     352{
     353        assert(event->type == KEY_PRESS);
     354
     355        if (event->key == KC_BACKSPACE)
     356                ui_entry_backspace(entry);
     357
     358        if (event->key == KC_ESCAPE) {
     359                entry->active = false;
     360                (void) ui_entry_paint(entry);
     361        }
     362
     363        return ui_claimed;
     364}
     365
     366/** Handle text entry keyboard event.
     367 *
     368 * @param entry Text entry
     369 * @param kbd_event Keyboard event
     370 * @return @c ui_claimed iff the event is claimed
     371 */
     372ui_evclaim_t ui_entry_kbd_event(ui_entry_t *entry, kbd_event_t *event)
     373{
     374        char buf[STR_BOUNDS(1) + 1];
     375        size_t off;
     376        errno_t rc;
     377
     378        if (!entry->active)
     379                return ui_unclaimed;
     380
     381        if (event->type == KEY_PRESS && event->c >= ' ') {
     382                off = 0;
     383                rc = chr_encode(event->c, buf, &off, sizeof(buf));
     384                if (rc == EOK) {
     385                        buf[off] = '\0';
     386                        (void) ui_entry_insert_str(entry, buf);
     387                }
     388        }
     389
     390        if (event->type == KEY_PRESS &&
     391            (event->mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0)
     392                return ui_entry_key_press_unmod(entry, event);
     393
     394        return ui_claimed;
     395}
     396
     397/** Handle text entry position event.
     398 *
     399 * @param entry Text entry
    273400 * @param pos_event Position event
    274401 * @return @c ui_claimed iff the event is claimed
    275402 */
    276 ui_evclaim_t ui_entry_ctl_pos_event(void *arg, pos_event_t *event)
    277 {
    278         ui_entry_t *entry = (ui_entry_t *) arg;
     403ui_evclaim_t ui_entry_pos_event(ui_entry_t *entry, pos_event_t *event)
     404{
    279405        gfx_coord2_t pos;
     406
     407        if (entry->read_only)
     408                return ui_unclaimed;
    280409
    281410        if (event->type == POS_UPDATE) {
     
    298427        }
    299428
     429        if (event->type == POS_PRESS) {
     430                pos.x = event->hpos;
     431                pos.y = event->vpos;
     432
     433                if (gfx_pix_inside_rect(&pos, &entry->rect)) {
     434                        if (!entry->active) {
     435                                entry->active = true;
     436                                (void) ui_entry_paint(entry);
     437                        }
     438
     439                        return ui_claimed;
     440                } else {
     441                        if (entry->active) {
     442                                entry->active = false;
     443                                (void) ui_entry_paint(entry);
     444                        }
     445                }
     446        }
     447
    300448        return ui_unclaimed;
    301449}
    302450
     451/** Handle text entry control keyboard event.
     452 *
     453 * @param arg Argument (ui_entry_t *)
     454 * @param kbd_event Keyboard event
     455 * @return @c ui_claimed iff the event is claimed
     456 */
     457static ui_evclaim_t ui_entry_ctl_kbd_event(void *arg, kbd_event_t *event)
     458{
     459        ui_entry_t *entry = (ui_entry_t *) arg;
     460
     461        return ui_entry_kbd_event(entry, event);
     462}
     463
     464/** Handle text entry control position event.
     465 *
     466 * @param arg Argument (ui_entry_t *)
     467 * @param pos_event Position event
     468 * @return @c ui_claimed iff the event is claimed
     469 */
     470static ui_evclaim_t ui_entry_ctl_pos_event(void *arg, pos_event_t *event)
     471{
     472        ui_entry_t *entry = (ui_entry_t *) arg;
     473
     474        return ui_entry_pos_event(entry, event);
     475}
     476
    303477/** @}
    304478 */
  • uspace/lib/ui/src/fixed.c

    r034ce6bb r7481ee19  
    11/*
    2  * Copyright (c) 2020 Jiri Svoboda
     2 * Copyright (c) 2021 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    4646static void ui_fixed_ctl_destroy(void *);
    4747static errno_t ui_fixed_ctl_paint(void *);
     48static ui_evclaim_t ui_fixed_ctl_kbd_event(void *, kbd_event_t *);
    4849static ui_evclaim_t ui_fixed_ctl_pos_event(void *, pos_event_t *);
    4950static void ui_fixed_ctl_unfocus(void *);
     
    5354        .destroy = ui_fixed_ctl_destroy,
    5455        .paint = ui_fixed_ctl_paint,
     56        .kbd_event = ui_fixed_ctl_kbd_event,
    5557        .pos_event = ui_fixed_ctl_pos_event,
    5658        .unfocus = ui_fixed_ctl_unfocus
     
    211213}
    212214
     215/** Handle fixed layout keyboard event.
     216 *
     217 * @param fixed Fixed layout
     218 * @param kbd_event Keyboard event
     219 * @return @c ui_claimed iff the event is claimed
     220 */
     221ui_evclaim_t ui_fixed_kbd_event(ui_fixed_t *fixed, kbd_event_t *event)
     222{
     223        ui_fixed_elem_t *elem;
     224        ui_evclaim_t claimed;
     225
     226        elem = ui_fixed_first(fixed);
     227        while (elem != NULL) {
     228                claimed = ui_control_kbd_event(elem->control, event);
     229                if (claimed == ui_claimed)
     230                        return ui_claimed;
     231
     232                elem = ui_fixed_next(elem);
     233        }
     234
     235        return ui_unclaimed;
     236}
     237
    213238/** Handle fixed layout position event.
    214239 *
     
    273298}
    274299
     300/** Handle fixed layout control keyboard event.
     301 *
     302 * @param arg Argument (ui_fixed_t *)
     303 * @param kbd_event Keyboard event
     304 * @return @c ui_claimed iff the event is claimed
     305 */
     306ui_evclaim_t ui_fixed_ctl_kbd_event(void *arg, kbd_event_t *event)
     307{
     308        ui_fixed_t *fixed = (ui_fixed_t *) arg;
     309
     310        return ui_fixed_kbd_event(fixed, event);
     311}
     312
    275313/** Handle fixed layout control position event.
    276314 *
  • uspace/lib/ui/src/window.c

    r034ce6bb r7481ee19  
    871871        if (window->cb != NULL && window->cb->kbd != NULL)
    872872                window->cb->kbd(window, window->arg, kbd);
     873        else
     874                return ui_window_def_kbd(window, kbd);
    873875}
    874876
     
    907909        else
    908910                return ui_window_def_unfocus(window);
     911}
     912
     913/** Default window keyboard event routine.
     914 *
     915 * @param window Window
     916 */
     917void ui_window_def_kbd(ui_window_t *window, kbd_event_t *kbd)
     918{
     919        if (window->control != NULL)
     920                ui_control_kbd_event(window->control, kbd);
    909921}
    910922
  • uspace/lib/ui/test/control.c

    r034ce6bb r7481ee19  
    11/*
    2  * Copyright (c) 2020 Jiri Svoboda
     2 * Copyright (c) 2021 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    2929#include <errno.h>
    3030#include <mem.h>
     31#include <io/kbd_event.h>
    3132#include <io/pos_event.h>
    3233#include <pcut/pcut.h>
     
    4142static void test_ctl_destroy(void *);
    4243static errno_t test_ctl_paint(void *);
     44static ui_evclaim_t test_ctl_kbd_event(void *, kbd_event_t *);
    4345static ui_evclaim_t test_ctl_pos_event(void *, pos_event_t *);
    4446static void test_ctl_unfocus(void *);
     
    4749        .destroy = test_ctl_destroy,
    4850        .paint = test_ctl_paint,
     51        .kbd_event = test_ctl_kbd_event,
    4952        .pos_event = test_ctl_pos_event,
    5053        .unfocus = test_ctl_unfocus
     
    6467        bool paint;
    6568
     69        /** @c true iff kbd_event was called */
     70        bool kbd;
     71        /** Keyboard event that was sent */
     72        kbd_event_t kevent;
     73
    6674        /** @c true iff pos_event was called */
    6775        bool pos;
     
    134142        PCUT_ASSERT_ERRNO_VAL(resp.rc, rc);
    135143        PCUT_ASSERT_TRUE(resp.paint);
     144
     145        ui_control_delete(control);
     146}
     147
     148/** Test sending keyboard event to control */
     149PCUT_TEST(kbd_event)
     150{
     151        ui_control_t *control = NULL;
     152        test_resp_t resp;
     153        kbd_event_t event;
     154        ui_evclaim_t claim;
     155        errno_t rc;
     156
     157        rc = ui_control_new(&test_ctl_ops, &resp, &control);
     158        PCUT_ASSERT_ERRNO_VAL(EOK, rc);
     159        PCUT_ASSERT_NOT_NULL(control);
     160
     161        resp.claim = ui_claimed;
     162        resp.kbd = false;
     163        event.type = KEY_PRESS;
     164        event.key = KC_2;
     165        event.mods = KM_LSHIFT;
     166        event.c = '@';
     167
     168        claim = ui_control_kbd_event(control, &event);
     169        PCUT_ASSERT_EQUALS(resp.claim, claim);
     170        PCUT_ASSERT_TRUE(resp.kbd);
     171        PCUT_ASSERT_EQUALS(resp.kevent.type, event.type);
     172        PCUT_ASSERT_INT_EQUALS(resp.kevent.key, event.key);
     173        PCUT_ASSERT_INT_EQUALS(resp.kevent.mods, event.mods);
     174        PCUT_ASSERT_INT_EQUALS(resp.kevent.c, event.c);
    136175
    137176        ui_control_delete(control);
     
    205244}
    206245
     246static ui_evclaim_t test_ctl_kbd_event(void *arg, kbd_event_t *event)
     247{
     248        test_resp_t *resp = (test_resp_t *) arg;
     249
     250        resp->kbd = true;
     251        resp->kevent = *event;
     252
     253        return resp->claim;
     254}
     255
    207256static ui_evclaim_t test_ctl_pos_event(void *arg, pos_event_t *event)
    208257{
  • uspace/lib/ui/test/entry.c

    r034ce6bb r7481ee19  
    119119}
    120120
     121/** Set entry read only flag sets internal field */
     122PCUT_TEST(set_read_only)
     123{
     124        ui_entry_t *entry;
     125        errno_t rc;
     126
     127        rc = ui_entry_create(NULL, "Hello", &entry);
     128        PCUT_ASSERT_ERRNO_VAL(EOK, rc);
     129
     130        ui_entry_set_read_only(entry, true);
     131        PCUT_ASSERT_TRUE(entry->read_only);
     132        ui_entry_set_read_only(entry, false);
     133        PCUT_ASSERT_FALSE(entry->read_only);
     134
     135        ui_entry_destroy(entry);
     136}
     137
    121138/** Set text entry rectangle sets internal field */
    122139PCUT_TEST(set_text)
     
    173190}
    174191
     192/** ui_entry_insert_str() inserts string at cursor. */
     193PCUT_TEST(insert_str)
     194{
     195        errno_t rc;
     196        ui_t *ui = NULL;
     197        ui_window_t *window = NULL;
     198        ui_wnd_params_t params;
     199        ui_entry_t *entry;
     200
     201        rc = ui_create_disp(NULL, &ui);
     202        PCUT_ASSERT_ERRNO_VAL(EOK, rc);
     203
     204        ui_wnd_params_init(&params);
     205        params.caption = "Hello";
     206
     207        rc = ui_window_create(ui, &params, &window);
     208        PCUT_ASSERT_ERRNO_VAL(EOK, rc);
     209        PCUT_ASSERT_NOT_NULL(window);
     210
     211        rc = ui_entry_create(window, "A", &entry);
     212        PCUT_ASSERT_ERRNO_VAL(EOK, rc);
     213
     214        PCUT_ASSERT_STR_EQUALS("A", entry->text);
     215
     216        rc = ui_entry_insert_str(entry, "B");
     217        PCUT_ASSERT_ERRNO_VAL(EOK, rc);
     218
     219        PCUT_ASSERT_STR_EQUALS("AB", entry->text);
     220
     221        rc = ui_entry_insert_str(entry, "CD");
     222        PCUT_ASSERT_ERRNO_VAL(EOK, rc);
     223
     224        PCUT_ASSERT_STR_EQUALS("ABCD", entry->text);
     225
     226        ui_entry_destroy(entry);
     227        ui_window_destroy(window);
     228        ui_destroy(ui);
     229}
     230
     231/** ui_entry_backspace() deletes character before cursor. */
     232PCUT_TEST(backspace)
     233{
     234        errno_t rc;
     235        ui_t *ui = NULL;
     236        ui_window_t *window = NULL;
     237        ui_wnd_params_t params;
     238        ui_entry_t *entry;
     239
     240        rc = ui_create_disp(NULL, &ui);
     241        PCUT_ASSERT_ERRNO_VAL(EOK, rc);
     242
     243        ui_wnd_params_init(&params);
     244        params.caption = "Hello";
     245
     246        rc = ui_window_create(ui, &params, &window);
     247        PCUT_ASSERT_ERRNO_VAL(EOK, rc);
     248        PCUT_ASSERT_NOT_NULL(window);
     249
     250        rc = ui_entry_create(window, "ABC", &entry);
     251        PCUT_ASSERT_ERRNO_VAL(EOK, rc);
     252
     253        PCUT_ASSERT_STR_EQUALS("ABC", entry->text);
     254
     255        ui_entry_backspace(entry);
     256        PCUT_ASSERT_STR_EQUALS("AB", entry->text);
     257
     258        ui_entry_backspace(entry);
     259        PCUT_ASSERT_STR_EQUALS("A", entry->text);
     260
     261        ui_entry_backspace(entry);
     262        PCUT_ASSERT_STR_EQUALS("", entry->text);
     263
     264        ui_entry_backspace(entry);
     265        PCUT_ASSERT_STR_EQUALS("", entry->text);
     266
     267        ui_entry_destroy(entry);
     268        ui_window_destroy(window);
     269        ui_destroy(ui);
     270}
     271
    175272PCUT_EXPORT(entry);
Note: See TracChangeset for help on using the changeset viewer.