Changeset 9eb8d12 in mainline for uspace/lib/ui/src/entry.c


Ignore:
Timestamp:
2021-07-19T22:35:19Z (4 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
c9722c1
Parents:
ead72f2
Message:

Entry text selection (using keyboard)

Text can be selected with movement keys while holding down Shift.
Selection can be deleted by pressing Backspace, Delete or typing
in replacement text.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/ui/src/entry.c

    read72f2 r9eb8d12  
    4242#include <gfx/render.h>
    4343#include <gfx/text.h>
     44#include <macros.h>
    4445#include <stdlib.h>
    4546#include <str.h>
     
    6364        ui_entry_vpad_text = 0,
    6465        ui_entry_cursor_overshoot = 1,
    65         ui_entry_cursor_width = 2
     66        ui_entry_cursor_width = 2,
     67        ui_entry_sel_hpad = 0,
     68        ui_entry_sel_vpad = 2
    6669};
    6770
     
    181184        entry->text = tcopy;
    182185        entry->pos = str_size(text);
     186        entry->sel_start = entry->pos;
    183187
    184188        return EOK;
     
    259263        gfx_text_fmt_t fmt;
    260264        gfx_coord2_t pos;
     265        gfx_text_fmt_t cfmt;
     266        gfx_coord2_t cpos;
    261267        gfx_rect_t inside;
     268        unsigned off1, off2;
     269        gfx_rect_t sel;
     270        char c;
    262271        errno_t rc;
    263272
     
    296305                goto error;
    297306
     307        off1 = min(entry->pos, entry->sel_start);
     308        off2 = max(entry->pos, entry->sel_start);
     309
     310        /* Render initial segment before start of selection */
     311        c = entry->text[off1];
     312        entry->text[off1] = '\0';
     313
    298314        rc = gfx_puttext(res->font, &pos, &fmt, entry->text);
     315        if (rc != EOK) {
     316                (void) gfx_set_clip_rect(res->gc, NULL);
     317                goto error;
     318        }
     319
     320        gfx_text_cont(res->font, &pos, &fmt, entry->text, &cpos, &cfmt);
     321        entry->text[off1] = c;
     322
     323        /* Render selected text */
     324
     325        if (off1 != off2) {
     326                c = entry->text[off2];
     327                entry->text[off2] = '\0';
     328                cfmt.color = res->entry_bg_color;
     329
     330                gfx_text_rect(res->font, &cpos, &cfmt, entry->text + off1, &sel);
     331                sel.p0.x -= ui_entry_sel_hpad;
     332                sel.p0.y -= ui_entry_sel_vpad;
     333                sel.p1.x += ui_entry_sel_hpad;
     334                sel.p1.y += ui_entry_sel_vpad;
     335
     336                rc = gfx_set_color(res->gc, res->entry_fg_color);
     337                if (rc != EOK)
     338                        goto error;
     339
     340                rc = gfx_fill_rect(res->gc, &sel);
     341                if (rc != EOK)
     342                        goto error;
     343
     344                rc = gfx_puttext(res->font, &cpos, &cfmt, entry->text + off1);
     345                if (rc != EOK) {
     346                        (void) gfx_set_clip_rect(res->gc, NULL);
     347                        goto error;
     348                }
     349
     350                gfx_text_cont(res->font, &cpos, &cfmt, entry->text + off1,
     351                    &cpos, &cfmt);
     352
     353                entry->text[off2] = c;
     354        }
     355
     356        /* Render trailing, non-selected text */
     357        cfmt.color = res->entry_fg_color;
     358
     359        rc = gfx_puttext(res->font, &cpos, &cfmt, entry->text + off2);
    299360        if (rc != EOK) {
    300361                (void) gfx_set_clip_rect(res->gc, NULL);
     
    373434}
    374435
     436/** Delete selected text.
     437 *
     438 * @param entry Text entry
     439 */
     440void ui_entry_delete_sel(ui_entry_t *entry)
     441{
     442        size_t off1;
     443        size_t off2;
     444
     445        off1 = min(entry->sel_start, entry->pos);
     446        off2 = max(entry->sel_start, entry->pos);
     447
     448        memmove(entry->text + off1, entry->text + off2,
     449            str_size(entry->text + off2) + 1);
     450
     451        entry->pos = off1;
     452        entry->sel_start = off1;
     453        ui_entry_paint(entry);
     454}
     455
    375456/** Insert string at cursor position.
    376457 *
     
    387468        int rc;
    388469
     470        /* Do we have a selection? */
     471        if (entry->sel_start != entry->pos)
     472                ui_entry_delete_sel(entry);
     473
    389474        tmp = entry->text[entry->pos];
    390475        entry->text[entry->pos] = '\0';
     
    407492        free(ltext);
    408493
     494        entry->sel_start = entry->pos;
    409495        ui_entry_paint(entry);
    410496
     
    419505{
    420506        size_t off;
     507
     508        /* Do we have a selection? */
     509        if (entry->sel_start != entry->pos) {
     510                ui_entry_delete_sel(entry);
     511                return;
     512        }
    421513
    422514        if (entry->pos == 0)
     
    431523            str_size(entry->text + entry->pos) + 1);
    432524        entry->pos = off;
     525        entry->sel_start = off;
    433526
    434527        ui_entry_paint(entry);
     
    443536        size_t off;
    444537
    445         /* Find offset where character after cursor end */
     538        /* Do we have a selection? */
     539        if (entry->sel_start != entry->pos) {
     540                ui_entry_delete_sel(entry);
     541                return;
     542        }
     543
     544        /* Find offset where character after cursor ends */
    446545        off = entry->pos;
    447546        (void) str_decode(entry->text, &off,
     
    478577
    479578        case KC_HOME:
    480                 ui_entry_seek_start(entry);
     579                ui_entry_seek_start(entry, false);
    481580                break;
    482581
    483582        case KC_END:
    484                 ui_entry_seek_end(entry);
     583                ui_entry_seek_end(entry, false);
    485584                break;
    486585
    487586        case KC_LEFT:
    488                 ui_entry_seek_prev_char(entry);
     587                ui_entry_seek_prev_char(entry, false);
    489588                break;
    490589
    491590        case KC_RIGHT:
    492                 ui_entry_seek_next_char(entry);
     591                ui_entry_seek_next_char(entry, false);
     592                break;
     593
     594        default:
     595                break;
     596        }
     597
     598        return ui_claimed;
     599}
     600
     601/** Handle text entry key press with shift modifier.
     602 *
     603 * @param entry Text entry
     604 * @param kbd_event Keyboard event
     605 * @return @c ui_claimed iff the event is claimed
     606 */
     607ui_evclaim_t ui_entry_key_press_shift(ui_entry_t *entry, kbd_event_t *event)
     608{
     609        assert(event->type == KEY_PRESS);
     610
     611        switch (event->key) {
     612        case KC_HOME:
     613                ui_entry_seek_start(entry, true);
     614                break;
     615
     616        case KC_END:
     617                ui_entry_seek_end(entry, true);
     618                break;
     619
     620        case KC_LEFT:
     621                ui_entry_seek_prev_char(entry, true);
     622                break;
     623
     624        case KC_RIGHT:
     625                ui_entry_seek_next_char(entry, true);
    493626                break;
    494627
     
    527660            (event->mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0)
    528661                return ui_entry_key_press_unmod(entry, event);
     662
     663        if (event->type == KEY_PRESS &&
     664            (event->mods & KM_SHIFT) != 0 &&
     665            (event->mods & (KM_CTRL | KM_ALT)) == 0)
     666                return ui_entry_key_press_shift(entry, event);
    529667
    530668        return ui_claimed;
     
    569707                if (gfx_pix_inside_rect(&pos, &entry->rect)) {
    570708                        entry->pos = ui_entry_find_pos(entry, &pos);
     709                        entry->sel_start = entry->pos;
    571710                        if (entry->active)
    572711                                ui_entry_paint(entry);
     
    680819 *
    681820 * @param entry Text entry
    682  */
    683 void ui_entry_seek_start(ui_entry_t *entry)
     821 * @param shift @c true iff shift key is pressed
     822 */
     823void ui_entry_seek_start(ui_entry_t *entry, bool shift)
    684824{
    685825        entry->pos = 0;
     826
     827        if (!shift)
     828                entry->sel_start = entry->pos;
    686829        (void) ui_entry_paint(entry);
    687830}
     
    690833 *
    691834 * @param entry Text entry
    692  */
    693 void ui_entry_seek_end(ui_entry_t *entry)
     835 * @param shift @c true iff shift key is pressed
     836 */
     837void ui_entry_seek_end(ui_entry_t *entry, bool shift)
    694838{
    695839        entry->pos = str_size(entry->text);
     840
     841        if (!shift)
     842                entry->sel_start = entry->pos;
    696843        (void) ui_entry_paint(entry);
    697844}
     
    700847 *
    701848 * @param entry Text entry
    702  */
    703 void ui_entry_seek_prev_char(ui_entry_t *entry)
     849 * @param shift @c true iff shift key is pressed
     850 */
     851void ui_entry_seek_prev_char(ui_entry_t *entry, bool shift)
    704852{
    705853        size_t off;
     
    709857            str_size(entry->text));
    710858        entry->pos = off;
     859
     860        if (!shift)
     861                entry->sel_start = entry->pos;
    711862        (void) ui_entry_paint(entry);
    712863}
     
    715866 *
    716867 * @param entry Text entry
    717  */
    718 void ui_entry_seek_next_char(ui_entry_t *entry)
     868 * @param shift @c true iff shift key is pressed
     869 */
     870void ui_entry_seek_next_char(ui_entry_t *entry, bool shift)
    719871{
    720872        size_t off;
     
    724876            str_size(entry->text));
    725877        entry->pos = off;
     878
     879        if (!shift)
     880                entry->sel_start = entry->pos;
    726881        (void) ui_entry_paint(entry);
    727882}
     
    741896
    742897        entry->active = false;
     898        entry->sel_start = entry->pos;
    743899        (void) ui_entry_paint(entry);
    744900
Note: See TracChangeset for help on using the changeset viewer.