Changes in uspace/app/edit/edit.c [994f87b:87822ce] in mainline


Ignore:
File:
1 edited

Legend:

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

    r994f87b r87822ce  
    11/*
    2  * Copyright (c) 2024 Jiri Svoboda
     2 * Copyright (c) 2009 Jiri Svoboda
    33 * Copyright (c) 2012 Martin Sucha
    44 * All rights reserved.
     
    3636 */
    3737
    38 #include <align.h>
    39 #include <clipboard.h>
    40 #include <errno.h>
    41 #include <gfx/color.h>
    42 #include <gfx/cursor.h>
    43 #include <gfx/font.h>
    44 #include <gfx/render.h>
    45 #include <gfx/text.h>
    46 #include <io/kbd_event.h>
    47 #include <io/keycode.h>
    48 #include <io/pos_event.h>
    49 #include <io/style.h>
    50 #include <macros.h>
    5138#include <stdio.h>
    5239#include <stdlib.h>
    5340#include <stddef.h>
    5441#include <stdbool.h>
     42#include <vfs/vfs.h>
     43#include <io/console.h>
     44#include <io/style.h>
     45#include <io/keycode.h>
     46#include <errno.h>
     47#include <align.h>
     48#include <macros.h>
     49#include <clipboard.h>
    5550#include <types/common.h>
    56 #include <ui/control.h>
    57 #include <ui/filedialog.h>
    58 #include <ui/fixed.h>
    59 #include <ui/label.h>
    60 #include <ui/menu.h>
    61 #include <ui/menubar.h>
    62 #include <ui/menudd.h>
    63 #include <ui/menuentry.h>
    64 #include <ui/promptdialog.h>
    65 #include <ui/resource.h>
    66 #include <ui/ui.h>
    67 #include <ui/window.h>
    68 #include <vfs/vfs.h>
    6951
    7052#include "sheet.h"
     
    8163 *
    8264 * A rectangular area of the screen used to edit a document. Different
    83  * panes can be possibly used to edit the same document. This is a custom
    84  * UI control.
     65 * panes can be possibly used to edit the same document.
    8566 */
    8667typedef struct {
    87         /** Base control object */
    88         struct ui_control *control;
    89 
    90         /** Containing window */
    91         ui_window_t *window;
    92 
    93         /** UI resource */
    94         struct ui_resource *res;
    95 
    96         /** Pane rectangle */
    97         gfx_rect_t rect;
    98 
    99         /** Pane color */
    100         gfx_color_t *color;
    101 
    102         /** Selection color */
    103         gfx_color_t *sel_color;
    104 
    10568        /* Pane dimensions */
    10669        int rows, columns;
     
    12790        int ideal_column;
    12891
    129         bool search_reverse;
    13092        char *previous_search;
    13193        bool previous_search_reverse;
    13294} pane_t;
    133 
    134 /** Text editor */
    135 typedef struct {
    136         /** User interface */
    137         ui_t *ui;
    138         /** Editor window */
    139         ui_window_t *window;
    140         /** UI resource */
    141         ui_resource_t *ui_res;
    142         /** Menu bar */
    143         ui_menu_bar_t *menubar;
    144         /** Status bar */
    145         ui_label_t *status;
    146 } edit_t;
    14795
    14896/** Document
     
    155103} doc_t;
    156104
    157 static edit_t edit;
     105static console_ctrl_t *con;
    158106static doc_t doc;
     107static bool done;
    159108static pane_t pane;
     109static bool cursor_visible;
     110
     111static sysarg_t scr_rows;
     112static sysarg_t scr_columns;
    160113
    161114#define ROW_BUF_SIZE 4096
     
    166119#define INFNAME_MAX_LEN 128
    167120
     121static void cursor_show(void);
     122static void cursor_hide(void);
    168123static void cursor_setvis(bool visible);
    169124
     
    177132static void pos_handle(pos_event_t *ev);
    178133
    179 static errno_t file_new(void);
    180 static void file_open(void);
    181 static errno_t file_open_file(const char *fname);
    182134static errno_t file_save(char const *fname);
    183135static void file_save_as(void);
    184 static errno_t file_insert(const char *fname);
     136static errno_t file_insert(char *fname);
    185137static errno_t file_save_range(char const *fname, spt_t const *spos,
    186138    spt_t const *epos);
    187139static char *range_get_str(spt_t const *spos, spt_t const *epos);
    188140
    189 static errno_t pane_init(ui_window_t *, pane_t *);
    190 static void pane_fini(pane_t *);
    191 static ui_control_t *pane_ctl(pane_t *);
    192 static errno_t pane_update(pane_t *);
    193 static errno_t pane_text_display(pane_t *);
     141static char *prompt(char const *prompt, char const *init_value);
     142
     143static void pane_text_display(void);
    194144static void pane_row_display(void);
    195 static errno_t pane_row_range_display(pane_t *, int r0, int r1);
    196 static void pane_status_display(pane_t *);
    197 static void pane_caret_display(pane_t *);
     145static void pane_row_range_display(int r0, int r1);
     146static void pane_status_display(void);
     147static void pane_caret_display(void);
    198148
    199149static void insert_char(char32_t c);
     
    214164static void selection_delete(void);
    215165static void selection_copy(void);
    216 static void edit_cut(void);
    217 static void edit_paste(void);
    218166static void insert_clipboard_data(void);
    219167
     
    237185
    238186static void status_display(char const *str);
    239 static errno_t edit_ui_create(edit_t *);
    240 static void edit_ui_destroy(edit_t *);
    241 
    242 static void edit_wnd_close(ui_window_t *, void *);
    243 static void edit_wnd_focus(ui_window_t *, void *, unsigned);
    244 static void edit_wnd_kbd_event(ui_window_t *, void *, kbd_event_t *);
    245 static void edit_wnd_unfocus(ui_window_t *, void *, unsigned);
    246 
    247 static ui_window_cb_t edit_window_cb = {
    248         .close = edit_wnd_close,
    249         .focus = edit_wnd_focus,
    250         .kbd = edit_wnd_kbd_event,
    251         .unfocus = edit_wnd_unfocus
    252 };
    253 
    254 static void edit_menubar_activate(ui_menu_bar_t *, void *);
    255 static void edit_menubar_deactivate(ui_menu_bar_t *, void *);
    256 
    257 static ui_menu_bar_cb_t edit_menubar_cb = {
    258         .activate = edit_menubar_activate,
    259         .deactivate = edit_menubar_deactivate
    260 };
    261 
    262 static void edit_file_new(ui_menu_entry_t *, void *);
    263 static void edit_file_open(ui_menu_entry_t *, void *);
    264 static void edit_file_save(ui_menu_entry_t *, void *);
    265 static void edit_file_save_as(ui_menu_entry_t *, void *);
    266 static void edit_file_exit(ui_menu_entry_t *, void *);
    267 static void edit_edit_cut(ui_menu_entry_t *, void *);
    268 static void edit_edit_copy(ui_menu_entry_t *, void *);
    269 static void edit_edit_paste(ui_menu_entry_t *, void *);
    270 static void edit_edit_delete(ui_menu_entry_t *, void *);
    271 static void edit_edit_select_all(ui_menu_entry_t *, void *);
    272 static void edit_search_find(ui_menu_entry_t *, void *);
    273 static void edit_search_reverse_find(ui_menu_entry_t *, void *);
    274 static void edit_search_find_next(ui_menu_entry_t *, void *);
    275 static void edit_search_go_to_line(ui_menu_entry_t *, void *);
    276 
    277 static void pane_ctl_destroy(void *);
    278 static errno_t pane_ctl_paint(void *);
    279 static ui_evclaim_t pane_ctl_pos_event(void *, pos_event_t *);
    280 
    281 /** Pabe control ops */
    282 ui_control_ops_t pane_ctl_ops = {
    283         .destroy = pane_ctl_destroy,
    284         .paint = pane_ctl_paint,
    285         .pos_event = pane_ctl_pos_event
    286 };
    287 
    288 static void open_dialog_bok(ui_file_dialog_t *, void *, const char *);
    289 static void open_dialog_bcancel(ui_file_dialog_t *, void *);
    290 static void open_dialog_close(ui_file_dialog_t *, void *);
    291 
    292 static ui_file_dialog_cb_t open_dialog_cb = {
    293         .bok = open_dialog_bok,
    294         .bcancel = open_dialog_bcancel,
    295         .close = open_dialog_close
    296 };
    297 
    298 static void save_as_dialog_bok(ui_file_dialog_t *, void *, const char *);
    299 static void save_as_dialog_bcancel(ui_file_dialog_t *, void *);
    300 static void save_as_dialog_close(ui_file_dialog_t *, void *);
    301 
    302 static ui_file_dialog_cb_t save_as_dialog_cb = {
    303         .bok = save_as_dialog_bok,
    304         .bcancel = save_as_dialog_bcancel,
    305         .close = save_as_dialog_close
    306 };
    307 
    308 static void go_to_line_dialog_bok(ui_prompt_dialog_t *, void *, const char *);
    309 static void go_to_line_dialog_bcancel(ui_prompt_dialog_t *, void *);
    310 static void go_to_line_dialog_close(ui_prompt_dialog_t *, void *);
    311 
    312 static ui_prompt_dialog_cb_t go_to_line_dialog_cb = {
    313         .bok = go_to_line_dialog_bok,
    314         .bcancel = go_to_line_dialog_bcancel,
    315         .close =  go_to_line_dialog_close
    316 };
    317 
    318 static void search_dialog_bok(ui_prompt_dialog_t *, void *, const char *);
    319 static void search_dialog_bcancel(ui_prompt_dialog_t *, void *);
    320 static void search_dialog_close(ui_prompt_dialog_t *, void *);
    321 
    322 static ui_prompt_dialog_cb_t search_dialog_cb = {
    323         .bok = search_dialog_bok,
    324         .bcancel = search_dialog_bcancel,
    325         .close =  search_dialog_close
    326 };
    327187
    328188int main(int argc, char *argv[])
    329189{
     190        cons_event_t ev;
     191        bool new_file;
    330192        errno_t rc;
    331193
     194        con = console_init(stdin, stdout);
     195        console_clear(con);
     196
     197        console_get_size(con, &scr_columns, &scr_rows);
     198
     199        pane.rows = scr_rows - 1;
     200        pane.columns = scr_columns;
    332201        pane.sh_row = 1;
    333202        pane.sh_column = 1;
    334203
    335         /* Create UI */
    336         rc = edit_ui_create(&edit);
    337         if (rc != EOK)
    338                 return 1;
     204        /* Start with an empty sheet. */
     205        rc = sheet_create(&doc.sh);
     206        if (rc != EOK) {
     207                printf("Out of memory.\n");
     208                return -1;
     209        }
     210
     211        /* Place caret at the beginning of file. */
     212        spt_t sof;
     213        pt_get_sof(&sof);
     214        sheet_place_tag(doc.sh, &sof, &pane.caret_pos);
     215        pane.ideal_column = 1;
    339216
    340217        if (argc == 2) {
    341218                doc.file_name = str_dup(argv[1]);
    342                 rc = file_open_file(argv[1]);
    343                 if (rc != EOK) {
    344                         status_display("File not found. Starting empty file.");
    345                         rc = file_new();
    346                 }
    347219        } else if (argc > 1) {
    348220                printf("Invalid arguments.\n");
    349221                return -2;
    350222        } else {
    351                 rc = file_new();
    352         }
     223                doc.file_name = NULL;
     224        }
     225
     226        new_file = false;
     227
     228        if (doc.file_name == NULL || file_insert(doc.file_name) != EOK)
     229                new_file = true;
     230
     231        /* Place selection start tag. */
     232        sheet_place_tag(doc.sh, &sof, &pane.sel_start);
     233
     234        /* Move to beginning of file. */
     235        pt_get_sof(&sof);
     236        caret_move(sof, true, true);
    353237
    354238        /* Initial display */
    355         rc = ui_window_paint(edit.window);
    356         if (rc != EOK) {
    357                 printf("Error painting window.\n");
    358                 return rc;
    359         }
    360 
    361         ui_run(edit.ui);
    362 
    363         edit_ui_destroy(&edit);
     239        cursor_visible = true;
     240
     241        cursor_hide();
     242        console_clear(con);
     243        pane_text_display();
     244        pane_status_display();
     245        if (new_file && doc.file_name != NULL)
     246                status_display("File not found. Starting empty file.");
     247        pane_caret_display();
     248        cursor_show();
     249
     250        done = false;
     251
     252        while (!done) {
     253                rc = console_get_event(con, &ev);
     254                if (rc != EOK)
     255                        break;
     256
     257                pane.rflags = 0;
     258
     259                switch (ev.type) {
     260                case CEV_KEY:
     261                        pane.keymod = ev.ev.key.mods;
     262                        if (ev.ev.key.type == KEY_PRESS)
     263                                key_handle_press(&ev.ev.key);
     264                        break;
     265                case CEV_POS:
     266                        pos_handle(&ev.ev.pos);
     267                        break;
     268                }
     269
     270                /* Redraw as necessary. */
     271
     272                cursor_hide();
     273
     274                if (pane.rflags & REDRAW_TEXT)
     275                        pane_text_display();
     276                if (pane.rflags & REDRAW_ROW)
     277                        pane_row_display();
     278                if (pane.rflags & REDRAW_STATUS)
     279                        pane_status_display();
     280                if (pane.rflags & REDRAW_CARET)
     281                        pane_caret_display();
     282
     283                cursor_show();
     284        }
     285
     286        console_clear(con);
     287
    364288        return 0;
    365 }
    366 
    367 /** Create text editor UI.
    368  *
    369  * @param edit Editor
    370  * @return EOK on success or an error code
    371  */
    372 static errno_t edit_ui_create(edit_t *edit)
    373 {
    374         errno_t rc;
    375         ui_wnd_params_t params;
    376         ui_fixed_t *fixed = NULL;
    377         ui_menu_t *mfile = NULL;
    378         ui_menu_t *medit = NULL;
    379         ui_menu_entry_t *mnew = NULL;
    380         ui_menu_entry_t *mopen = NULL;
    381         ui_menu_entry_t *msave = NULL;
    382         ui_menu_entry_t *msaveas = NULL;
    383         ui_menu_entry_t *mfsep = NULL;
    384         ui_menu_entry_t *mexit = NULL;
    385         ui_menu_entry_t *mcut = NULL;
    386         ui_menu_entry_t *mcopy = NULL;
    387         ui_menu_entry_t *mpaste = NULL;
    388         ui_menu_entry_t *mdelete = NULL;
    389         ui_menu_entry_t *mesep = NULL;
    390         ui_menu_entry_t *mselall = NULL;
    391         ui_menu_t *msearch = NULL;
    392         ui_menu_entry_t *mfind = NULL;
    393         ui_menu_entry_t *mfindr = NULL;
    394         ui_menu_entry_t *mfindn = NULL;
    395         ui_menu_entry_t *mssep = NULL;
    396         ui_menu_entry_t *mgoto = NULL;
    397         gfx_rect_t arect;
    398         gfx_rect_t rect;
    399 
    400         rc = ui_create(UI_CONSOLE_DEFAULT, &edit->ui);
    401         if (rc != EOK) {
    402                 printf("Error creating UI on display %s.\n",
    403                     UI_CONSOLE_DEFAULT);
    404                 goto error;
    405         }
    406 
    407         ui_wnd_params_init(&params);
    408         params.caption = "Text Editor";
    409         params.style &= ~ui_wds_decorated;
    410         params.placement = ui_wnd_place_full_screen;
    411 
    412         rc = ui_window_create(edit->ui, &params, &edit->window);
    413         if (rc != EOK) {
    414                 printf("Error creating window.\n");
    415                 goto error;
    416         }
    417 
    418         ui_window_set_cb(edit->window, &edit_window_cb, (void *) edit);
    419 
    420         edit->ui_res = ui_window_get_res(edit->window);
    421 
    422         rc = ui_fixed_create(&fixed);
    423         if (rc != EOK) {
    424                 printf("Error creating fixed layout.\n");
    425                 return rc;
    426         }
    427 
    428         rc = ui_menu_bar_create(edit->ui, edit->window, &edit->menubar);
    429         if (rc != EOK) {
    430                 printf("Error creating menu bar.\n");
    431                 return rc;
    432         }
    433 
    434         ui_menu_bar_set_cb(edit->menubar, &edit_menubar_cb, (void *) edit);
    435 
    436         rc = ui_menu_dd_create(edit->menubar, "~F~ile", NULL, &mfile);
    437         if (rc != EOK) {
    438                 printf("Error creating menu.\n");
    439                 return rc;
    440         }
    441 
    442         rc = ui_menu_entry_create(mfile, "~N~ew", "Ctrl-N", &mnew);
    443         if (rc != EOK) {
    444                 printf("Error creating menu.\n");
    445                 return rc;
    446         }
    447 
    448         ui_menu_entry_set_cb(mnew, edit_file_new, (void *) edit);
    449 
    450         rc = ui_menu_entry_create(mfile, "~O~pen", "Ctrl-O", &mopen);
    451         if (rc != EOK) {
    452                 printf("Error creating menu.\n");
    453                 return rc;
    454         }
    455 
    456         ui_menu_entry_set_cb(mopen, edit_file_open, (void *) edit);
    457 
    458         rc = ui_menu_entry_create(mfile, "~S~ave", "Ctrl-S", &msave);
    459         if (rc != EOK) {
    460                 printf("Error creating menu.\n");
    461                 return rc;
    462         }
    463 
    464         ui_menu_entry_set_cb(msave, edit_file_save, (void *) edit);
    465 
    466         rc = ui_menu_entry_create(mfile, "Save ~A~s", "Ctrl-E", &msaveas);
    467         if (rc != EOK) {
    468                 printf("Error creating menu.\n");
    469                 return rc;
    470         }
    471 
    472         ui_menu_entry_set_cb(msaveas, edit_file_save_as, (void *) edit);
    473 
    474         rc = ui_menu_entry_sep_create(mfile, &mfsep);
    475         if (rc != EOK) {
    476                 printf("Error creating menu.\n");
    477                 return rc;
    478         }
    479 
    480         rc = ui_menu_entry_create(mfile, "E~x~it", "Ctrl-Q", &mexit);
    481         if (rc != EOK) {
    482                 printf("Error creating menu.\n");
    483                 return rc;
    484         }
    485 
    486         ui_menu_entry_set_cb(mexit, edit_file_exit, (void *) edit);
    487 
    488         rc = ui_menu_dd_create(edit->menubar, "~E~dit", NULL, &medit);
    489         if (rc != EOK) {
    490                 printf("Error creating menu.\n");
    491                 return rc;
    492         }
    493 
    494         rc = ui_menu_entry_create(medit, "Cu~t~", "Ctrl-X", &mcut);
    495         if (rc != EOK) {
    496                 printf("Error creating menu.\n");
    497                 return rc;
    498         }
    499 
    500         ui_menu_entry_set_cb(mcut, edit_edit_cut, (void *) edit);
    501 
    502         rc = ui_menu_entry_create(medit, "~C~opy", "Ctrl-C", &mcopy);
    503         if (rc != EOK) {
    504                 printf("Error creating menu.\n");
    505                 return rc;
    506         }
    507 
    508         ui_menu_entry_set_cb(mcopy, edit_edit_copy, (void *) edit);
    509 
    510         rc = ui_menu_entry_create(medit, "~P~aste", "Ctrl-V", &mpaste);
    511         if (rc != EOK) {
    512                 printf("Error creating menu.\n");
    513                 return rc;
    514         }
    515 
    516         ui_menu_entry_set_cb(mpaste, edit_edit_paste, (void *) edit);
    517 
    518         rc = ui_menu_entry_create(medit, "~D~elete", "Del", &mdelete);
    519         if (rc != EOK) {
    520                 printf("Error creating menu.\n");
    521                 return rc;
    522         }
    523 
    524         ui_menu_entry_set_cb(mdelete, edit_edit_delete, (void *) edit);
    525 
    526         rc = ui_menu_entry_sep_create(medit, &mesep);
    527         if (rc != EOK) {
    528                 printf("Error creating menu.\n");
    529                 return rc;
    530         }
    531 
    532         rc = ui_menu_entry_create(medit, "Select ~A~ll", "Ctrl-A", &mselall);
    533         if (rc != EOK) {
    534                 printf("Error creating menu.\n");
    535                 return rc;
    536         }
    537 
    538         ui_menu_entry_set_cb(mselall, edit_edit_select_all, (void *) edit);
    539 
    540         rc = ui_menu_dd_create(edit->menubar, "~S~earch", NULL, &msearch);
    541         if (rc != EOK) {
    542                 printf("Error creating menu.\n");
    543                 return rc;
    544         }
    545 
    546         rc = ui_menu_entry_create(msearch, "~F~ind", "Ctrl-F", &mfind);
    547         if (rc != EOK) {
    548                 printf("Error creating menu.\n");
    549                 return rc;
    550         }
    551 
    552         ui_menu_entry_set_cb(mfind, edit_search_find, (void *) edit);
    553 
    554         rc = ui_menu_entry_create(msearch, "~R~everse Find", "Ctrl-Shift-F", &mfindr);
    555         if (rc != EOK) {
    556                 printf("Error creating menu.\n");
    557                 return rc;
    558         }
    559 
    560         ui_menu_entry_set_cb(mfindr, edit_search_reverse_find, (void *) edit);
    561 
    562         rc = ui_menu_entry_create(msearch, "Find ~N~ext", "Ctrl-R", &mfindn);
    563         if (rc != EOK) {
    564                 printf("Error creating menu.\n");
    565                 return rc;
    566         }
    567 
    568         ui_menu_entry_set_cb(mfindn, edit_search_find_next, (void *) edit);
    569 
    570         rc = ui_menu_entry_sep_create(msearch, &mssep);
    571         if (rc != EOK) {
    572                 printf("Error creating menu.\n");
    573                 return rc;
    574         }
    575 
    576         rc = ui_menu_entry_create(msearch, "Go To ~L~ine", "Ctrl-L", &mgoto);
    577         if (rc != EOK) {
    578                 printf("Error creating menu.\n");
    579                 return rc;
    580         }
    581 
    582         ui_menu_entry_set_cb(mgoto, edit_search_go_to_line, (void *) edit);
    583 
    584         ui_window_get_app_rect(edit->window, &arect);
    585 
    586         rect.p0 = arect.p0;
    587         rect.p1.x = arect.p1.x;
    588         rect.p1.y = arect.p0.y + 1;
    589         ui_menu_bar_set_rect(edit->menubar, &rect);
    590 
    591         rc = ui_fixed_add(fixed, ui_menu_bar_ctl(edit->menubar));
    592         if (rc != EOK) {
    593                 printf("Error adding control to layout.\n");
    594                 return rc;
    595         }
    596 
    597         rc = pane_init(edit->window, &pane);
    598         if (rc != EOK) {
    599                 printf("Error initializing pane.\n");
    600                 return rc;
    601         }
    602 
    603         rc = ui_fixed_add(fixed, pane_ctl(&pane));
    604         if (rc != EOK) {
    605                 printf("Error adding control to layout.\n");
    606                 return rc;
    607         }
    608 
    609         rc = ui_label_create(edit->ui_res, "", &edit->status);
    610         if (rc != EOK) {
    611                 printf("Error creating menu bar.\n");
    612                 return rc;
    613         }
    614 
    615         rect.p0.x = arect.p0.x;
    616         rect.p0.y = arect.p1.y - 1;
    617         rect.p1 = arect.p1;
    618         ui_label_set_rect(edit->status, &rect);
    619 
    620         rc = ui_fixed_add(fixed, ui_label_ctl(edit->status));
    621         if (rc != EOK) {
    622                 printf("Error adding control to layout.\n");
    623                 return rc;
    624         }
    625 
    626         ui_window_add(edit->window, ui_fixed_ctl(fixed));
    627         return EOK;
    628 error:
    629         if (edit->window != NULL)
    630                 ui_window_destroy(edit->window);
    631         if (edit->ui != NULL)
    632                 ui_destroy(edit->ui);
    633         return rc;
    634 }
    635 
    636 /** Destroy text editor UI.
    637  *
    638  * @param edit Editor
    639  */
    640 static void edit_ui_destroy(edit_t *edit)
    641 {
    642         ui_window_destroy(edit->window);
    643         ui_destroy(edit->ui);
    644289}
    645290
     
    664309}
    665310
     311static void cursor_show(void)
     312{
     313        cursor_setvis(true);
     314}
     315
     316static void cursor_hide(void)
     317{
     318        cursor_setvis(false);
     319}
     320
    666321static void cursor_setvis(bool visible)
    667322{
    668         gfx_context_t *gc = ui_window_get_gc(edit.window);
    669 
    670         (void) gfx_cursor_set_visible(gc, visible);
     323        if (cursor_visible != visible) {
     324                console_cursor_visibility(con, visible);
     325                cursor_visible = visible;
     326        }
    671327}
    672328
     
    744400        switch (ev->key) {
    745401        case KC_Q:
    746                 ui_quit(edit.ui);
    747                 break;
    748         case KC_N:
    749                 file_new();
    750                 break;
    751         case KC_O:
    752                 file_open();
     402                done = true;
    753403                break;
    754404        case KC_S:
     
    765415                break;
    766416        case KC_V:
    767                 edit_paste();
     417                selection_delete();
     418                insert_clipboard_data();
     419                pane.rflags |= REDRAW_TEXT;
     420                caret_update();
    768421                break;
    769422        case KC_X:
    770                 edit_cut();
     423                selection_copy();
     424                selection_delete();
     425                pane.rflags |= REDRAW_TEXT;
     426                caret_update();
    771427                break;
    772428        case KC_A:
     
    785441                search_prompt(false);
    786442                break;
    787         case KC_R:
     443        case KC_N:
    788444                search_repeat();
    789445                break;
     
    834490
    835491        if (ev->type == POS_PRESS && ev->vpos < (unsigned)pane.rows) {
    836                 bc.row = pane.sh_row + ev->vpos - pane.rect.p0.y;
    837                 bc.column = pane.sh_column + ev->hpos - pane.rect.p0.x;
     492                bc.row = pane.sh_row + ev->vpos;
     493                bc.column = pane.sh_column + ev->hpos;
    838494                sheet_get_cell_pt(doc.sh, &bc, dir_before, &pt);
    839495
     
    841497
    842498                caret_move(pt, select, true);
    843                 pane_update(&pane);
    844499        }
    845500}
     
    924579}
    925580
    926 /** Create new document. */
    927 static errno_t file_new(void)
    928 {
    929         errno_t rc;
    930         sheet_t *sh;
    931 
    932         /* Create empty sheet. */
    933         rc = sheet_create(&sh);
    934         if (rc != EOK) {
    935                 printf("Out of memory.\n");
    936                 return ENOMEM;
    937         }
    938 
    939         if (doc.sh != NULL)
    940                 sheet_destroy(doc.sh);
    941 
    942         doc.sh = sh;
    943 
    944         /* Place caret at the beginning of file. */
    945         spt_t sof;
    946         pt_get_sof(&sof);
    947         sheet_place_tag(doc.sh, &sof, &pane.caret_pos);
    948         pane.ideal_column = 1;
    949 
    950         doc.file_name = NULL;
    951 
    952         /* Place selection start tag. */
    953         sheet_place_tag(doc.sh, &sof, &pane.sel_start);
    954 
    955         /* Move to beginning of file. */
    956         pt_get_sof(&sof);
    957 
    958         caret_move(sof, true, true);
    959 
    960         pane_status_display(&pane);
    961         pane_caret_display(&pane);
    962         pane_text_display(&pane);
    963         cursor_setvis(true);
    964 
    965         return EOK;
    966 }
    967 
    968 /** Open Open File dialog. */
    969 static void file_open(void)
    970 {
    971         const char *old_fname = (doc.file_name != NULL) ? doc.file_name : "";
    972         ui_file_dialog_params_t fdparams;
    973         ui_file_dialog_t *dialog;
    974         errno_t rc;
    975 
    976         ui_file_dialog_params_init(&fdparams);
    977         fdparams.caption = "Open File";
    978         fdparams.ifname = old_fname;
    979 
    980         rc = ui_file_dialog_create(edit.ui, &fdparams, &dialog);
    981         if (rc != EOK) {
    982                 printf("Error creating message dialog.\n");
    983                 return;
    984         }
    985 
    986         ui_file_dialog_set_cb(dialog, &open_dialog_cb, &edit);
    987 }
    988 
    989 /** Open exising document. */
    990 static errno_t file_open_file(const char *fname)
    991 {
    992         errno_t rc;
    993         sheet_t *sh;
    994         char *fn;
    995 
    996         /* Create empty sheet. */
    997         rc = sheet_create(&sh);
    998         if (rc != EOK) {
    999                 printf("Out of memory.\n");
    1000                 return ENOMEM;
    1001         }
    1002 
    1003         fn = str_dup(fname);
    1004         if (fn == NULL) {
    1005                 sheet_destroy(sh);
    1006                 return ENOMEM;
    1007         }
    1008 
    1009         if (doc.sh != NULL)
    1010                 sheet_destroy(doc.sh);
    1011 
    1012         doc.sh = sh;
    1013 
    1014         /* Place caret at the beginning of file. */
    1015         spt_t sof;
    1016         pt_get_sof(&sof);
    1017         sheet_place_tag(doc.sh, &sof, &pane.caret_pos);
    1018         pane.ideal_column = 1;
    1019 
    1020         rc = file_insert(fname);
    1021         if (rc != EOK)
    1022                 return rc;
    1023 
    1024         doc.file_name = fn;
    1025 
    1026         /* Place selection start tag. */
    1027         sheet_place_tag(doc.sh, &sof, &pane.sel_start);
    1028 
    1029         /* Move to beginning of file. */
    1030         pt_get_sof(&sof);
    1031 
    1032         caret_move(sof, true, true);
    1033 
    1034         pane_status_display(&pane);
    1035         pane_caret_display(&pane);
    1036         pane_text_display(&pane);
    1037         cursor_setvis(true);
    1038 
    1039         return EOK;
    1040 }
    1041 
    1042581/** Save the document. */
    1043582static errno_t file_save(char const *fname)
     
    1067606}
    1068607
    1069 /** Open Save As dialog. */
     608/** Change document name and save. */
    1070609static void file_save_as(void)
    1071610{
    1072611        const char *old_fname = (doc.file_name != NULL) ? doc.file_name : "";
    1073         ui_file_dialog_params_t fdparams;
    1074         ui_file_dialog_t *dialog;
     612        char *fname;
     613
     614        fname = prompt("Save As", old_fname);
     615        if (fname == NULL) {
     616                status_display("Save cancelled.");
     617                return;
     618        }
     619
     620        errno_t rc = file_save(fname);
     621        if (rc != EOK)
     622                return;
     623
     624        if (doc.file_name != NULL)
     625                free(doc.file_name);
     626        doc.file_name = fname;
     627}
     628
     629/** Ask for a string. */
     630static char *prompt(char const *prompt, char const *init_value)
     631{
     632        cons_event_t ev;
     633        kbd_event_t *kev;
     634        char *str;
     635        char32_t buffer[INFNAME_MAX_LEN + 1];
     636        int max_len;
     637        int nc;
     638        bool done;
    1075639        errno_t rc;
    1076640
    1077         ui_file_dialog_params_init(&fdparams);
    1078         fdparams.caption = "Save As";
    1079         fdparams.ifname = old_fname;
    1080 
    1081         rc = ui_file_dialog_create(edit.ui, &fdparams, &dialog);
    1082         if (rc != EOK) {
    1083                 printf("Error creating message dialog.\n");
    1084                 return;
    1085         }
    1086 
    1087         ui_file_dialog_set_cb(dialog, &save_as_dialog_cb, &edit);
     641        asprintf(&str, "%s: %s", prompt, init_value);
     642        status_display(str);
     643        console_set_pos(con, 1 + str_length(str), scr_rows - 1);
     644        free(str);
     645
     646        console_set_style(con, STYLE_INVERTED);
     647
     648        max_len = min(INFNAME_MAX_LEN, scr_columns - 4 - str_length(prompt));
     649        str_to_wstr(buffer, max_len + 1, init_value);
     650        nc = wstr_length(buffer);
     651        done = false;
     652
     653        while (!done) {
     654                rc = console_get_event(con, &ev);
     655                if (rc != EOK)
     656                        return NULL;
     657
     658                if (ev.type == CEV_KEY && ev.ev.key.type == KEY_PRESS) {
     659                        kev = &ev.ev.key;
     660
     661                        /* Handle key press. */
     662                        if ((kev->mods & (KM_CTRL | KM_ALT)) == 0) {
     663                                switch (kev->key) {
     664                                case KC_ESCAPE:
     665                                        return NULL;
     666                                case KC_BACKSPACE:
     667                                        if (nc > 0) {
     668                                                putchar('\b');
     669                                                console_flush(con);
     670                                                --nc;
     671                                        }
     672                                        break;
     673                                case KC_ENTER:
     674                                        done = true;
     675                                        break;
     676                                default:
     677                                        if (kev->c >= 32 && nc < max_len) {
     678                                                putuchar(kev->c);
     679                                                console_flush(con);
     680                                                buffer[nc++] = kev->c;
     681                                        }
     682                                        break;
     683                                }
     684                        }
     685                }
     686        }
     687
     688        buffer[nc] = '\0';
     689        str = wstr_to_astr(buffer);
     690
     691        console_set_style(con, STYLE_NORMAL);
     692
     693        return str;
    1088694}
    1089695
     
    1093699 * of the caret.
    1094700 */
    1095 static errno_t file_insert(const char *fname)
     701static errno_t file_insert(char *fname)
    1096702{
    1097703        FILE *f;
     
    1120726
    1121727                bcnt -= off;
    1122                 memmove(buf, buf + off, bcnt);
     728                memcpy(buf, buf + off, bcnt);
    1123729
    1124730                insert_char(c);
     
    1202808}
    1203809
    1204 /** Initialize pane.
    1205  *
    1206  * TODO: Replace with pane_create() that allocates the pane.
    1207  *
    1208  * @param window Editor window
    1209  * @param pane Pane
    1210  * @return EOK on success or an error code
    1211  */
    1212 static errno_t pane_init(ui_window_t *window, pane_t *pane)
    1213 {
    1214         errno_t rc;
    1215         gfx_rect_t arect;
    1216 
    1217         pane->control = NULL;
    1218         pane->color = NULL;
    1219         pane->sel_color = NULL;
    1220 
    1221         rc = ui_control_new(&pane_ctl_ops, (void *) pane, &pane->control);
    1222         if (rc != EOK)
    1223                 goto error;
    1224 
    1225         rc = gfx_color_new_ega(0x07, &pane->color);
    1226         if (rc != EOK)
    1227                 goto error;
    1228 
    1229         rc = gfx_color_new_ega(0x1e, &pane->sel_color);
    1230         if (rc != EOK)
    1231                 goto error;
    1232 
    1233         pane->res = ui_window_get_res(window);
    1234         pane->window = window;
    1235 
    1236         ui_window_get_app_rect(window, &arect);
    1237         pane->rect.p0.x = arect.p0.x;
    1238         pane->rect.p0.y = arect.p0.y + 1;
    1239         pane->rect.p1.x = arect.p1.x;
    1240         pane->rect.p1.y = arect.p1.y - 1;
    1241 
    1242         pane->columns = pane->rect.p1.x - pane->rect.p0.x;
    1243         pane->rows = pane->rect.p1.y - pane->rect.p0.y;
    1244 
    1245         return EOK;
    1246 error:
    1247         if (pane->control != NULL) {
    1248                 ui_control_delete(pane->control);
    1249                 pane->control = NULL;
    1250         }
    1251 
    1252         if (pane->color != NULL) {
    1253                 gfx_color_delete(pane->color);
    1254                 pane->color = NULL;
    1255         }
    1256 
    1257         return rc;
    1258 }
    1259 
    1260 /** Finalize pane.
    1261  *
    1262  * TODO: Replace with pane_destroy() that deallocates the pane.
    1263  *
    1264  * @param pane Pane
    1265  */
    1266 static void pane_fini(pane_t *pane)
    1267 {
    1268         gfx_color_delete(pane->color);
    1269         pane->color = NULL;
    1270         gfx_color_delete(pane->sel_color);
    1271         pane->sel_color = NULL;
    1272         ui_control_delete(pane->control);
    1273         pane->control = NULL;
    1274 }
    1275 
    1276 /** Return base control object for a pane.
    1277  *
    1278  * @param pane Pane
    1279  * @return Base UI cntrol
    1280  */
    1281 static ui_control_t *pane_ctl(pane_t *pane)
    1282 {
    1283         return pane->control;
    1284 }
    1285 
    1286 /** Repaint parts of pane that need updating.
    1287  *
    1288  * @param pane Pane
    1289  * @return EOK on succes or an error code
    1290  */
    1291 static errno_t pane_update(pane_t *pane)
    1292 {
    1293         errno_t rc;
    1294 
    1295         if (pane->rflags & REDRAW_TEXT) {
    1296                 rc = pane_text_display(pane);
    1297                 if (rc != EOK)
    1298                         return rc;
    1299         }
    1300 
    1301         if (pane->rflags & REDRAW_ROW)
    1302                 pane_row_display();
    1303 
    1304         if (pane->rflags & REDRAW_STATUS)
    1305                 pane_status_display(pane);
    1306 
    1307         if (pane->rflags & REDRAW_CARET)
    1308                 pane_caret_display(pane);
    1309 
    1310         pane->rflags &= ~(REDRAW_TEXT | REDRAW_ROW | REDRAW_STATUS |
    1311             REDRAW_CARET);
    1312         return EOK;
    1313 }
    1314 
    1315 /** Display pane text.
    1316  *
    1317  * @param pane Pane
    1318  * @return EOK on success or an error code
    1319  */
    1320 static errno_t pane_text_display(pane_t *pane)
    1321 {
    1322         gfx_rect_t rect;
    1323         gfx_context_t *gc;
    1324         errno_t rc;
     810static void pane_text_display(void)
     811{
    1325812        int sh_rows, rows;
    1326813
    1327814        sheet_get_num_rows(doc.sh, &sh_rows);
    1328         rows = min(sh_rows - pane->sh_row + 1, pane->rows);
     815        rows = min(sh_rows - pane.sh_row + 1, pane.rows);
    1329816
    1330817        /* Draw rows from the sheet. */
    1331818
    1332         rc = pane_row_range_display(pane, 0, rows);
    1333         if (rc != EOK)
    1334                 return rc;
     819        console_set_pos(con, 0, 0);
     820        pane_row_range_display(0, rows);
    1335821
    1336822        /* Clear the remaining rows if file is short. */
    1337823
    1338         gc = ui_window_get_gc(pane->window);
    1339 
    1340         rc = gfx_set_color(gc, pane->color);
    1341         if (rc != EOK)
    1342                 goto error;
    1343 
    1344         rect.p0.x = pane->rect.p0.x;
    1345         rect.p0.y = pane->rect.p0.y + rows;
    1346         rect.p1.x = pane->rect.p1.x;
    1347         rect.p1.y = pane->rect.p1.y;
    1348 
    1349         rc = gfx_fill_rect(gc, &rect);
    1350         if (rc != EOK)
    1351                 goto error;
    1352 
    1353         pane->rflags &= ~REDRAW_ROW;
    1354         return EOK;
    1355 error:
    1356         return rc;
     824        int i;
     825        sysarg_t j;
     826        for (i = rows; i < pane.rows; ++i) {
     827                console_set_pos(con, 0, i);
     828                for (j = 0; j < scr_columns; ++j)
     829                        putchar(' ');
     830                console_flush(con);
     831        }
     832
     833        pane.rflags |= (REDRAW_STATUS | REDRAW_CARET);
     834        pane.rflags &= ~REDRAW_ROW;
    1357835}
    1358836
     
    1368846
    1369847        ridx = coord.row - pane.sh_row;
    1370         (void) pane_row_range_display(&pane, ridx, ridx + 1);
     848        pane_row_range_display(ridx, ridx + 1);
    1371849        pane.rflags |= (REDRAW_STATUS | REDRAW_CARET);
    1372850}
    1373851
    1374 /** Display a range of rows of text.
    1375  *
    1376  * @param r0 Start row (inclusive)
    1377  * @param r1 End row (exclusive)
    1378  * @return EOk on success or an error code
    1379  */
    1380 static errno_t pane_row_range_display(pane_t *pane, int r0, int r1)
    1381 {
    1382         int i, fill;
     852static void pane_row_range_display(int r0, int r1)
     853{
     854        int i, j, fill;
    1383855        spt_t rb, re, dep, pt;
    1384856        coord_t rbc, rec;
    1385857        char row_buf[ROW_BUF_SIZE];
    1386         char cbuf[STR_BOUNDS(1) + 1];
    1387858        char32_t c;
    1388859        size_t pos, size;
    1389         size_t cpos;
    1390860        int s_column;
    1391861        coord_t csel_start, csel_end, ctmp;
    1392         gfx_font_t *font;
    1393         gfx_context_t *gc;
    1394         gfx_text_fmt_t fmt;
    1395         gfx_coord2_t tpos;
    1396         gfx_rect_t rect;
    1397         errno_t rc;
    1398 
    1399         font = ui_resource_get_font(edit.ui_res);
    1400         gc = ui_window_get_gc(edit.window);
    1401 
    1402         gfx_text_fmt_init(&fmt);
    1403         fmt.font = font;
    1404         fmt.color = pane->color;
    1405862
    1406863        /* Determine selection start and end. */
    1407864
    1408         tag_get_pt(&pane->sel_start, &pt);
     865        tag_get_pt(&pane.sel_start, &pt);
    1409866        spt_get_coord(&pt, &csel_start);
    1410867
    1411         tag_get_pt(&pane->caret_pos, &pt);
     868        tag_get_pt(&pane.caret_pos, &pt);
    1412869        spt_get_coord(&pt, &csel_end);
    1413870
     
    1420877        /* Draw rows from the sheet. */
    1421878
     879        console_set_pos(con, 0, 0);
    1422880        for (i = r0; i < r1; ++i) {
    1423                 tpos.x = pane->rect.p0.x;
    1424                 tpos.y = pane->rect.p0.y + i;
    1425 
    1426881                /* Starting point for row display */
    1427                 rbc.row = pane->sh_row + i;
    1428                 rbc.column = pane->sh_column;
     882                rbc.row = pane.sh_row + i;
     883                rbc.column = pane.sh_column;
    1429884                sheet_get_cell_pt(doc.sh, &rbc, dir_before, &rb);
    1430885
    1431886                /* Ending point for row display */
    1432                 rec.row = pane->sh_row + i;
    1433                 rec.column = pane->sh_column + pane->columns;
     887                rec.row = pane.sh_row + i;
     888                rec.column = pane.sh_column + pane.columns;
    1434889                sheet_get_cell_pt(doc.sh, &rec, dir_before, &re);
    1435890
     
    1441896                if (coord_cmp(&csel_start, &rbc) <= 0 &&
    1442897                    coord_cmp(&rbc, &csel_end) < 0) {
    1443                         fmt.color = pane->sel_color;
     898                        console_flush(con);
     899                        console_set_style(con, STYLE_SELECTED);
     900                        console_flush(con);
    1444901                }
    1445902
     903                console_set_pos(con, 0, i);
    1446904                size = str_size(row_buf);
    1447905                pos = 0;
    1448                 s_column = pane->sh_column;
     906                s_column = pane.sh_column;
    1449907                while (pos < size) {
    1450                         if ((csel_start.row == rbc.row) && (csel_start.column == s_column))
    1451                                 fmt.color = pane->sel_color;
    1452 
    1453                         if ((csel_end.row == rbc.row) && (csel_end.column == s_column))
    1454                                 fmt.color = pane->color;
     908                        if ((csel_start.row == rbc.row) && (csel_start.column == s_column)) {
     909                                console_flush(con);
     910                                console_set_style(con, STYLE_SELECTED);
     911                                console_flush(con);
     912                        }
     913
     914                        if ((csel_end.row == rbc.row) && (csel_end.column == s_column)) {
     915                                console_flush(con);
     916                                console_set_style(con, STYLE_NORMAL);
     917                                console_flush(con);
     918                        }
    1455919
    1456920                        c = str_decode(row_buf, &pos, size);
    1457921                        if (c != '\t') {
    1458                                 cpos = 0;
    1459                                 rc = chr_encode(c, cbuf, &cpos, sizeof(cbuf));
    1460                                 if (rc != EOK)
    1461                                         return rc;
    1462 
    1463                                 rc = gfx_puttext(&tpos, &fmt, cbuf);
    1464                                 if (rc != EOK)
    1465                                         return rc;
    1466 
     922                                printf("%lc", (wint_t) c);
    1467923                                s_column += 1;
    1468                                 tpos.x++;
    1469924                        } else {
    1470925                                fill = 1 + ALIGN_UP(s_column, TAB_WIDTH) -
    1471926                                    s_column;
    1472927
    1473                                 rc = gfx_set_color(gc, fmt.color);
    1474                                 if (rc != EOK)
    1475                                         return rc;
    1476 
    1477                                 rect.p0.x = tpos.x;
    1478                                 rect.p0.y = tpos.y;
    1479                                 rect.p1.x = tpos.x + fill;
    1480                                 rect.p1.y = tpos.y + 1;
    1481 
    1482                                 rc = gfx_fill_rect(gc, &rect);
    1483                                 if (rc != EOK)
    1484                                         return rc;
    1485 
     928                                for (j = 0; j < fill; ++j)
     929                                        putchar(' ');
    1486930                                s_column += fill;
    1487                                 tpos.x += fill;
    1488931                        }
    1489932                }
    1490933
    1491                 if ((csel_end.row == rbc.row) && (csel_end.column == s_column))
    1492                         fmt.color = pane->color;
     934                if ((csel_end.row == rbc.row) && (csel_end.column == s_column)) {
     935                        console_flush(con);
     936                        console_set_style(con, STYLE_NORMAL);
     937                        console_flush(con);
     938                }
    1493939
    1494940                /* Fill until the end of display area. */
    1495941
    1496                 rc = gfx_set_color(gc, fmt.color);
    1497                 if (rc != EOK)
    1498                         return rc;
    1499 
    1500                 rect.p0.x = tpos.x;
    1501                 rect.p0.y = tpos.y;
    1502                 rect.p1.x = pane->rect.p1.x;
    1503                 rect.p1.y = tpos.y + 1;
    1504 
    1505                 rc = gfx_fill_rect(gc, &rect);
    1506                 if (rc != EOK)
    1507                         return rc;
    1508         }
    1509 
    1510         return EOK;
    1511 }
    1512 
    1513 /** Display pane status in the status line.
    1514  *
    1515  * @param pane Pane
    1516  */
    1517 static void pane_status_display(pane_t *pane)
     942                if ((unsigned)s_column - 1 < scr_columns)
     943                        fill = scr_columns - (s_column - 1);
     944                else
     945                        fill = 0;
     946
     947                for (j = 0; j < fill; ++j)
     948                        putchar(' ');
     949                console_flush(con);
     950                console_set_style(con, STYLE_NORMAL);
     951        }
     952
     953        pane.rflags |= REDRAW_CARET;
     954}
     955
     956/** Display pane status in the status line. */
     957static void pane_status_display(void)
    1518958{
    1519959        spt_t caret_pt;
     
    1524964        char *text;
    1525965        size_t n;
     966        int pos;
    1526967        size_t nextra;
    1527968        size_t fnw;
    1528969
    1529         tag_get_pt(&pane->caret_pos, &caret_pt);
     970        tag_get_pt(&pane.caret_pos, &caret_pt);
    1530971        spt_get_coord(&caret_pt, &coord);
    1531972
     
    1546987                return;
    1547988
     989        console_set_pos(con, 0, scr_rows - 1);
     990        console_set_style(con, STYLE_INVERTED);
     991
    1548992        /*
    1549993         * Make sure the status fits on the screen. This loop should
     
    1551995         */
    1552996        while (true) {
    1553                 int rc = asprintf(&text, "%d, %d (%d): File '%s'. Ctrl-Q Quit  "
    1554                     "F10 Menu", coord.row, coord.column, last_row, fname);
     997                int rc = asprintf(&text, " %d, %d (%d): File '%s'. Ctrl-Q Quit  Ctrl-S Save  "
     998                    "Ctrl-E Save As", coord.row, coord.column, last_row, fname);
    1555999                if (rc < 0) {
    15561000                        n = 0;
     
    15601004                /* If it already fits, we're done */
    15611005                n = str_width(text);
    1562                 if ((int)n <= pane->columns - 2)
     1006                if (n <= scr_columns - 2)
    15631007                        break;
    15641008
    15651009                /* Compute number of excess characters */
    1566                 nextra = n - (pane->columns - 2);
     1010                nextra = n - (scr_columns - 2);
    15671011                /** With of the file name part */
    15681012                fnw = str_width(fname);
     
    15721016                 * just give up and print a blank status.
    15731017                 */
    1574                 if (nextra > fnw - 2) {
    1575                         text[0] = '\0';
     1018                if (nextra > fnw - 2)
    15761019                        goto finish;
    1577                 }
    15781020
    15791021                /* Compute position where we overwrite with '..\0' */
     
    15921034        }
    15931035
    1594 finish:
    1595         (void) ui_label_set_text(edit.status, text);
    1596         (void) ui_label_paint(edit.status);
     1036        printf("%s", text);
    15971037        free(text);
    15981038        free(fname);
    1599 }
    1600 
    1601 /** Set cursor to reflect position of the caret.
    1602  *
    1603  * @param pane Pane
    1604  */
    1605 static void pane_caret_display(pane_t *pane)
     1039finish:
     1040        /* Fill the rest of the line */
     1041        pos = scr_columns - 1 - n;
     1042        printf("%*s", pos, "");
     1043        console_flush(con);
     1044        console_set_style(con, STYLE_NORMAL);
     1045
     1046        pane.rflags |= REDRAW_CARET;
     1047}
     1048
     1049/** Set cursor to reflect position of the caret. */
     1050static void pane_caret_display(void)
    16061051{
    16071052        spt_t caret_pt;
    16081053        coord_t coord;
    1609         gfx_coord2_t pos;
    1610         gfx_context_t *gc;
    1611 
    1612         tag_get_pt(&pane->caret_pos, &caret_pt);
     1054
     1055        tag_get_pt(&pane.caret_pos, &caret_pt);
    16131056
    16141057        spt_get_coord(&caret_pt, &coord);
    1615 
    1616         gc = ui_window_get_gc(edit.window);
    1617         pos.x = pane->rect.p0.x + coord.column - pane->sh_column;
    1618         pos.y = pane->rect.p0.y + coord.row - pane->sh_row;
    1619 
    1620         (void) gfx_cursor_set_pos(gc, &pos);
    1621 }
    1622 
    1623 /** Destroy pane control.
    1624  *
    1625  * @param arg Argument (pane_t *)
    1626  */
    1627 static void pane_ctl_destroy(void *arg)
    1628 {
    1629         pane_t *pane = (pane_t *)arg;
    1630 
    1631         pane_fini(pane);
    1632 }
    1633 
    1634 /** Paint pane control.
    1635  *
    1636  * @param arg Argument (pane_t *)
    1637  */
    1638 static errno_t pane_ctl_paint(void *arg)
    1639 {
    1640         pane_t *pane = (pane_t *)arg;
    1641         gfx_context_t *gc;
    1642         errno_t rc;
    1643 
    1644         gc = ui_window_get_gc(pane->window);
    1645 
    1646         rc = pane_text_display(pane);
    1647         if (rc != EOK)
    1648                 goto error;
    1649 
    1650         rc = gfx_update(gc);
    1651         if (rc != EOK)
    1652                 goto error;
    1653 
    1654 error:
    1655         return rc;
    1656 }
    1657 
    1658 /** Handle pane control position event.
    1659  *
    1660  * @param arg Argument (pane_t *)
    1661  * @param event Position event
    1662  */
    1663 static ui_evclaim_t pane_ctl_pos_event(void *arg, pos_event_t *event)
    1664 {
    1665         gfx_coord2_t pos;
    1666 
    1667         pos.x = event->hpos;
    1668         pos.y = event->vpos;
    1669 
    1670         if (!gfx_pix_inside_rect(&pos, &pane.rect))
    1671                 return ui_unclaimed;
    1672 
    1673         pos_handle(event);
    1674         (void) gfx_update(ui_window_get_gc(edit.window));
    1675         return ui_claimed;
     1058        console_set_pos(con, coord.column - pane.sh_column,
     1059            coord.row - pane.sh_row);
    16761060}
    16771061
     
    18861270static void caret_go_to_line_ask(void)
    18871271{
    1888         ui_prompt_dialog_params_t pdparams;
    1889         ui_prompt_dialog_t *dialog;
    1890         errno_t rc;
    1891 
    1892         ui_prompt_dialog_params_init(&pdparams);
    1893         pdparams.caption = "Go To Line";
    1894         pdparams.prompt = "Line Number";
    1895 
    1896         rc = ui_prompt_dialog_create(edit.ui, &pdparams, &dialog);
    1897         if (rc != EOK) {
    1898                 printf("Error creating prompt dialog.\n");
     1272        char *sline;
     1273
     1274        sline = prompt("Go to line", "");
     1275        if (sline == NULL) {
     1276                status_display("Go to line cancelled.");
    18991277                return;
    19001278        }
    19011279
    1902         ui_prompt_dialog_set_cb(dialog, &go_to_line_dialog_cb, &edit);
     1280        char *endptr;
     1281        int line = strtol(sline, &endptr, 10);
     1282        if (*endptr != '\0') {
     1283                free(sline);
     1284                status_display("Invalid number entered.");
     1285                return;
     1286        }
     1287        free(sline);
     1288
     1289        caret_move_absolute(line, pane.ideal_column, dir_before, false);
    19031290}
    19041291
     
    19571344static void search_prompt(bool reverse)
    19581345{
    1959         ui_prompt_dialog_params_t pdparams;
    1960         ui_prompt_dialog_t *dialog;
    1961         errno_t rc;
    1962 
    1963         ui_prompt_dialog_params_init(&pdparams);
    1964         pdparams.caption = reverse ? "Reverse Search" : "Search";
    1965         pdparams.prompt = "Search text";
    1966         pdparams.itext = "";
    1967 
     1346        char *pattern;
     1347
     1348        const char *prompt_text = "Find next";
     1349        if (reverse)
     1350                prompt_text = "Find previous";
     1351
     1352        const char *default_value = "";
    19681353        if (pane.previous_search)
    1969                 pdparams.itext = pane.previous_search;
    1970 
    1971         rc = ui_prompt_dialog_create(edit.ui, &pdparams, &dialog);
    1972         if (rc != EOK) {
    1973                 printf("Error creating prompt dialog.\n");
     1354                default_value = pane.previous_search;
     1355
     1356        pattern = prompt(prompt_text, default_value);
     1357        if (pattern == NULL) {
     1358                status_display("Search cancelled.");
    19741359                return;
    19751360        }
    19761361
    1977         ui_prompt_dialog_set_cb(dialog, &search_dialog_cb, &edit);
    1978         pane.search_reverse = reverse;
     1362        if (pane.previous_search)
     1363                free(pane.previous_search);
     1364        pane.previous_search = pattern;
     1365        pane.previous_search_reverse = reverse;
     1366
     1367        search(pattern, reverse);
    19791368}
    19801369
     
    21241513        }
    21251514        free(str);
    2126 }
    2127 
    2128 static void edit_paste(void)
    2129 {
    2130         selection_delete();
    2131         insert_clipboard_data();
    2132         pane.rflags |= (REDRAW_TEXT | REDRAW_CARET);
    2133         pane_update(&pane);
    2134 }
    2135 
    2136 static void edit_cut(void)
    2137 {
    2138         selection_copy();
    2139         selection_delete();
    2140         pane.rflags |= (REDRAW_TEXT | REDRAW_CARET);
    2141         pane_update(&pane);
    21421515}
    21431516
     
    23461719static void status_display(char const *str)
    23471720{
    2348         (void) ui_label_set_text(edit.status, str);
    2349         (void) ui_label_paint(edit.status);
    2350 }
    2351 
    2352 /** Window close request
    2353  *
    2354  * @param window Window
    2355  * @param arg Argument (edit_t *)
    2356  */
    2357 static void edit_wnd_close(ui_window_t *window, void *arg)
    2358 {
    2359         edit_t *edit = (edit_t *) arg;
    2360 
    2361         ui_quit(edit->ui);
    2362 }
    2363 
    2364 /** Window focus event
    2365  *
    2366  * @param window Window
    2367  * @param arg Argument (edit_t *)
    2368  * @param focus Focus number
    2369  */
    2370 static void edit_wnd_focus(ui_window_t *window, void *arg, unsigned focus)
    2371 {
    2372         edit_t *edit = (edit_t *)arg;
    2373 
    2374         (void)edit;
    2375         pane_caret_display(&pane);
    2376         cursor_setvis(true);
    2377 }
    2378 
    2379 /** Window keyboard event
    2380  *
    2381  * @param window Window
    2382  * @param arg Argument (edit_t *)
    2383  * @param event Keyboard event
    2384  */
    2385 static void edit_wnd_kbd_event(ui_window_t *window, void *arg,
    2386     kbd_event_t *event)
    2387 {
    2388         pane.keymod = event->mods;
    2389 
    2390         if (ui_window_def_kbd(window, event) == ui_claimed)
    2391                 return;
    2392 
    2393         if (event->type == KEY_PRESS) {
    2394                 key_handle_press(event);
    2395                 (void) pane_update(&pane);
    2396                 (void) gfx_update(ui_window_get_gc(window));
    2397         }
    2398 }
    2399 
    2400 /** Window unfocus event
    2401  *
    2402  * @param window Window
    2403  * @param arg Argument (edit_t *)
    2404  * @param focus Focus number
    2405  */
    2406 static void edit_wnd_unfocus(ui_window_t *window, void *arg, unsigned focus)
    2407 {
    2408         edit_t *edit = (edit_t *) arg;
    2409 
    2410         (void)edit;
    2411         cursor_setvis(false);
    2412 }
    2413 
    2414 /** Menu bar activate event
    2415  *
    2416  * @param mbar Menu bar
    2417  * @param arg Argument (edit_t *)
    2418  */
    2419 static void edit_menubar_activate(ui_menu_bar_t *mbar, void *arg)
    2420 {
    2421         edit_t *edit = (edit_t *)arg;
    2422 
    2423         (void)edit;
    2424         cursor_setvis(false);
    2425 }
    2426 
    2427 /** Menu bar deactivate event
    2428  *
    2429  * @param mbar Menu bar
    2430  * @param arg Argument (edit_t *)
    2431  */
    2432 static void edit_menubar_deactivate(ui_menu_bar_t *mbar, void *arg)
    2433 {
    2434         edit_t *edit = (edit_t *)arg;
    2435 
    2436         (void)edit;
    2437         pane_caret_display(&pane);
    2438         cursor_setvis(true);
    2439 }
    2440 
    2441 /** File / New menu entry selected.
    2442  *
    2443  * @param mentry Menu entry
    2444  * @param arg Argument (edit_t *)
    2445  */
    2446 static void edit_file_new(ui_menu_entry_t *mentry, void *arg)
    2447 {
    2448         edit_t *edit = (edit_t *) arg;
    2449 
    2450         (void)edit;
    2451         file_new();
    2452         (void) gfx_update(ui_window_get_gc(edit->window));
    2453 }
    2454 
    2455 /** File / Open menu entry selected.
    2456  *
    2457  * @param mentry Menu entry
    2458  * @param arg Argument (edit_t *)
    2459  */
    2460 static void edit_file_open(ui_menu_entry_t *mentry, void *arg)
    2461 {
    2462         edit_t *edit = (edit_t *) arg;
    2463 
    2464         (void)edit;
    2465         file_open();
    2466 }
    2467 
    2468 /** File / Save menu entry selected.
    2469  *
    2470  * @param mentry Menu entry
    2471  * @param arg Argument (edit_t *)
    2472  */
    2473 static void edit_file_save(ui_menu_entry_t *mentry, void *arg)
    2474 {
    2475         edit_t *edit = (edit_t *) arg;
    2476 
    2477         (void)edit;
    2478 
    2479         if (doc.file_name != NULL)
    2480                 file_save(doc.file_name);
    2481         else
    2482                 file_save_as();
    2483 }
    2484 
    2485 /** File / Save As menu entry selected.
    2486  *
    2487  * @param mentry Menu entry
    2488  * @param arg Argument (edit_t *)
    2489  */
    2490 static void edit_file_save_as(ui_menu_entry_t *mentry, void *arg)
    2491 {
    2492         edit_t *edit = (edit_t *) arg;
    2493 
    2494         (void)edit;
    2495         file_save_as();
    2496 }
    2497 
    2498 /** File / Exit menu entry selected.
    2499  *
    2500  * @param mentry Menu entry
    2501  * @param arg Argument (edit_t *)
    2502  */
    2503 static void edit_file_exit(ui_menu_entry_t *mentry, void *arg)
    2504 {
    2505         edit_t *edit = (edit_t *) arg;
    2506 
    2507         ui_quit(edit->ui);
    2508 }
    2509 
    2510 /** Edit / Cut menu entry selected.
    2511  *
    2512  * @param mentry Menu entry
    2513  * @param arg Argument (edit_t *)
    2514  */
    2515 static void edit_edit_cut(ui_menu_entry_t *mentry, void *arg)
    2516 {
    2517         (void) arg;
    2518         edit_cut();
    2519         (void) gfx_update(ui_window_get_gc(edit.window));
    2520 }
    2521 
    2522 /** Edit / Copy menu entry selected.
    2523  *
    2524  * @param mentry Menu entry
    2525  * @param arg Argument (edit_t *)
    2526  */
    2527 static void edit_edit_copy(ui_menu_entry_t *mentry, void *arg)
    2528 {
    2529         (void) arg;
    2530         selection_copy();
    2531 }
    2532 
    2533 /** Edit / Paste menu entry selected.
    2534  *
    2535  * @param mentry Menu entry
    2536  * @param arg Argument (edit_t *)
    2537  */
    2538 static void edit_edit_paste(ui_menu_entry_t *mentry, void *arg)
    2539 {
    2540         (void) arg;
    2541         edit_paste();
    2542         (void) gfx_update(ui_window_get_gc(edit.window));
    2543 }
    2544 
    2545 /** Edit / Delete menu entry selected.
    2546  *
    2547  * @param mentry Menu entry
    2548  * @param arg Argument (edit_t *)
    2549  */
    2550 static void edit_edit_delete(ui_menu_entry_t *mentry, void *arg)
    2551 {
    2552         (void) arg;
    2553 
    2554         if (selection_active())
    2555                 selection_delete();
     1721        console_set_pos(con, 0, scr_rows - 1);
     1722        console_set_style(con, STYLE_INVERTED);
     1723
     1724        int pos = -(scr_columns - 3);
     1725        printf(" %*s ", pos, str);
     1726        console_flush(con);
     1727        console_set_style(con, STYLE_NORMAL);
    25561728
    25571729        pane.rflags |= REDRAW_CARET;
    2558         (void) pane_update(&pane);
    2559         (void) gfx_update(ui_window_get_gc(edit.window));
    2560 }
    2561 
    2562 /** Edit / Select All menu entry selected.
    2563  *
    2564  * @param mentry Menu entry
    2565  * @param arg Argument (edit_t *)
    2566  */
    2567 static void edit_edit_select_all(ui_menu_entry_t *mentry, void *arg)
    2568 {
    2569         (void) arg;
    2570 
    2571         selection_sel_all();
    2572         pane.rflags |= (REDRAW_CARET | REDRAW_TEXT | REDRAW_STATUS);
    2573         pane_update(&pane);
    2574         (void) gfx_update(ui_window_get_gc(edit.window));
    2575 }
    2576 
    2577 /** Search / Find menu entry selected.
    2578  *
    2579  * @param mentry Menu entry
    2580  * @param arg Argument (edit_t *)
    2581  */
    2582 static void edit_search_find(ui_menu_entry_t *mentry, void *arg)
    2583 {
    2584         (void) arg;
    2585         search_prompt(false);
    2586 }
    2587 
    2588 /** Search / Reverse Find menu entry selected.
    2589  *
    2590  * @param mentry Menu entry
    2591  * @param arg Argument (edit_t *)
    2592  */
    2593 static void edit_search_reverse_find(ui_menu_entry_t *mentry, void *arg)
    2594 {
    2595         (void) arg;
    2596         search_prompt(true);
    2597 }
    2598 
    2599 /** Search / Find Next menu entry selected.
    2600  *
    2601  * @param mentry Menu entry
    2602  * @param arg Argument (edit_t *)
    2603  */
    2604 static void edit_search_find_next(ui_menu_entry_t *mentry, void *arg)
    2605 {
    2606         (void) arg;
    2607         search_repeat();
    2608         (void) pane_update(&pane);
    2609         (void) gfx_update(ui_window_get_gc(edit.window));
    2610 }
    2611 
    2612 /** Search / Go To Line menu entry selected.
    2613  *
    2614  * @param mentry Menu entry
    2615  * @param arg Argument (edit_t *)
    2616  */
    2617 static void edit_search_go_to_line(ui_menu_entry_t *mentry, void *arg)
    2618 {
    2619         (void) arg;
    2620         caret_go_to_line_ask();
    2621 }
    2622 
    2623 /** Open File dialog OK button press.
    2624  *
    2625  * @param dialog Open File dialog
    2626  * @param arg Argument (ui_demo_t *)
    2627  * @param fname File name
    2628  */
    2629 static void open_dialog_bok(ui_file_dialog_t *dialog, void *arg,
    2630     const char *fname)
    2631 {
    2632         edit_t *edit = (edit_t *)arg;
    2633         char *cname;
    2634         errno_t rc;
    2635 
    2636         (void)edit;
    2637         ui_file_dialog_destroy(dialog);
    2638 
    2639         cname = str_dup(fname);
    2640         if (cname == NULL) {
    2641                 printf("Out of memory.\n");
    2642                 return;
    2643         }
    2644 
    2645         rc = file_open_file(fname);
    2646         if (rc != EOK)
    2647                 return;
    2648 
    2649         if (doc.file_name != NULL)
    2650                 free(doc.file_name);
    2651         doc.file_name = cname;
    2652 
    2653         (void) gfx_update(ui_window_get_gc(edit->window));
    2654 }
    2655 
    2656 /** Open File dialog cancel button press.
    2657  *
    2658  * @param dialog File dialog
    2659  * @param arg Argument (ui_demo_t *)
    2660  */
    2661 static void open_dialog_bcancel(ui_file_dialog_t *dialog, void *arg)
    2662 {
    2663         edit_t *edit = (edit_t *)arg;
    2664 
    2665         (void)edit;
    2666         ui_file_dialog_destroy(dialog);
    2667 }
    2668 
    2669 /** Open File dialog close request.
    2670  *
    2671  * @param dialog File dialog
    2672  * @param arg Argument (ui_demo_t *)
    2673  */
    2674 static void open_dialog_close(ui_file_dialog_t *dialog, void *arg)
    2675 {
    2676         edit_t *edit = (edit_t *)arg;
    2677 
    2678         (void)edit;
    2679         ui_file_dialog_destroy(dialog);
    2680 }
    2681 
    2682 /** Save As dialog OK button press.
    2683  *
    2684  * @param dialog Save As dialog
    2685  * @param arg Argument (ui_demo_t *)
    2686  * @param fname File name
    2687  */
    2688 static void save_as_dialog_bok(ui_file_dialog_t *dialog, void *arg,
    2689     const char *fname)
    2690 {
    2691         edit_t *edit = (edit_t *)arg;
    2692         char *cname;
    2693         errno_t rc;
    2694 
    2695         (void)edit;
    2696         ui_file_dialog_destroy(dialog);
    2697 
    2698         cname = str_dup(fname);
    2699         if (cname == NULL) {
    2700                 printf("Out of memory.\n");
    2701                 return;
    2702         }
    2703 
    2704         rc = file_save(fname);
    2705         if (rc != EOK)
    2706                 return;
    2707 
    2708         if (doc.file_name != NULL)
    2709                 free(doc.file_name);
    2710         doc.file_name = cname;
    2711 
    2712 }
    2713 
    2714 /** Save As dialog cancel button press.
    2715  *
    2716  * @param dialog File dialog
    2717  * @param arg Argument (ui_demo_t *)
    2718  */
    2719 static void save_as_dialog_bcancel(ui_file_dialog_t *dialog, void *arg)
    2720 {
    2721         edit_t *edit = (edit_t *)arg;
    2722 
    2723         (void)edit;
    2724         ui_file_dialog_destroy(dialog);
    2725 }
    2726 
    2727 /** Save As dialog close request.
    2728  *
    2729  * @param dialog File dialog
    2730  * @param arg Argument (ui_demo_t *)
    2731  */
    2732 static void save_as_dialog_close(ui_file_dialog_t *dialog, void *arg)
    2733 {
    2734         edit_t *edit = (edit_t *)arg;
    2735 
    2736         (void)edit;
    2737         ui_file_dialog_destroy(dialog);
    2738 }
    2739 
    2740 /** Go To Line dialog OK button press.
    2741  *
    2742  * @param dialog Go To Line dialog
    2743  * @param arg Argument (ui_demo_t *)
    2744  * @param text Submitted text
    2745  */
    2746 static void go_to_line_dialog_bok(ui_prompt_dialog_t *dialog, void *arg,
    2747     const char *text)
    2748 {
    2749         edit_t *edit = (edit_t *) arg;
    2750         char *endptr;
    2751         int line;
    2752 
    2753         ui_prompt_dialog_destroy(dialog);
    2754         line = strtol(text, &endptr, 10);
    2755         if (*endptr != '\0') {
    2756                 status_display("Invalid number entered.");
    2757                 return;
    2758         }
    2759 
    2760         caret_move_absolute(line, pane.ideal_column, dir_before, false);
    2761         (void)edit;
    2762         (void) pane_update(&pane);
    2763 }
    2764 
    2765 /** Go To Line dialog cancel button press.
    2766  *
    2767  * @param dialog File dialog
    2768  * @param arg Argument (ui_demo_t *)
    2769  */
    2770 static void go_to_line_dialog_bcancel(ui_prompt_dialog_t *dialog, void *arg)
    2771 {
    2772         edit_t *edit = (edit_t *) arg;
    2773 
    2774         (void)edit;
    2775         ui_prompt_dialog_destroy(dialog);
    2776 }
    2777 
    2778 /** Go To Line dialog close request.
    2779  *
    2780  * @param dialog File dialog
    2781  * @param arg Argument (ui_demo_t *)
    2782  */
    2783 static void go_to_line_dialog_close(ui_prompt_dialog_t *dialog, void *arg)
    2784 {
    2785         edit_t *edit = (edit_t *) arg;
    2786 
    2787         (void)edit;
    2788         ui_prompt_dialog_destroy(dialog);
    2789 }
    2790 
    2791 /** Search dialog OK button press.
    2792  *
    2793  * @param dialog Search dialog
    2794  * @param arg Argument (ui_demo_t *)
    2795  * @param text Submitted text
    2796  */
    2797 static void search_dialog_bok(ui_prompt_dialog_t *dialog, void *arg,
    2798     const char *text)
    2799 {
    2800         edit_t *edit = (edit_t *) arg;
    2801         char *pattern;
    2802         bool reverse;
    2803 
    2804         (void)edit;
    2805         ui_prompt_dialog_destroy(dialog);
    2806 
    2807         /* Abort if search phrase is empty */
    2808         if (text[0] == '\0')
    2809                 return;
    2810 
    2811         pattern = str_dup(text);
    2812         reverse = pane.search_reverse;
    2813 
    2814         if (pane.previous_search)
    2815                 free(pane.previous_search);
    2816         pane.previous_search = pattern;
    2817         pane.previous_search_reverse = reverse;
    2818 
    2819         search(pattern, reverse);
    2820 
    2821         (void) pane_update(&pane);
    2822 }
    2823 
    2824 /** Search dialog cancel button press.
    2825  *
    2826  * @param dialog File dialog
    2827  * @param arg Argument (ui_demo_t *)
    2828  */
    2829 static void search_dialog_bcancel(ui_prompt_dialog_t *dialog, void *arg)
    2830 {
    2831         edit_t *edit = (edit_t *) arg;
    2832 
    2833         (void)edit;
    2834         ui_prompt_dialog_destroy(dialog);
    2835 }
    2836 
    2837 /** Search dialog close request.
    2838  *
    2839  * @param dialog File dialog
    2840  * @param arg Argument (ui_demo_t *)
    2841  */
    2842 static void search_dialog_close(ui_prompt_dialog_t *dialog, void *arg)
    2843 {
    2844         edit_t *edit = (edit_t *) arg;
    2845 
    2846         (void)edit;
    2847         ui_prompt_dialog_destroy(dialog);
    28481730}
    28491731
Note: See TracChangeset for help on using the changeset viewer.