Ignore:
File:
1 edited

Legend:

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

    r87822ce r3c22438a  
    11/*
    2  * Copyright (c) 2009 Jiri Svoboda
     2 * Copyright (c) 2026 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>
    3851#include <stdio.h>
    3952#include <stdlib.h>
    4053#include <stddef.h>
    4154#include <stdbool.h>
     55#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>
    4268#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>
    50 #include <types/common.h>
    5169
    5270#include "sheet.h"
     
    6381 *
    6482 * A rectangular area of the screen used to edit a document. Different
    65  * panes can be possibly used to edit the same document.
     83 * panes can be possibly used to edit the same document. This is a custom
     84 * UI control.
    6685 */
    6786typedef 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
    68105        /* Pane dimensions */
    69106        int rows, columns;
     
    90127        int ideal_column;
    91128
     129        bool search_reverse;
    92130        char *previous_search;
    93131        bool previous_search_reverse;
    94132} pane_t;
     133
     134/** Text editor */
     135typedef 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;
    95147
    96148/** Document
     
    103155} doc_t;
    104156
    105 static console_ctrl_t *con;
     157static edit_t edit;
    106158static doc_t doc;
    107 static bool done;
    108159static pane_t pane;
    109 static bool cursor_visible;
    110 
    111 static sysarg_t scr_rows;
    112 static sysarg_t scr_columns;
    113160
    114161#define ROW_BUF_SIZE 4096
     
    119166#define INFNAME_MAX_LEN 128
    120167
    121 static void cursor_show(void);
    122 static void cursor_hide(void);
    123168static void cursor_setvis(bool visible);
    124169
     
    132177static void pos_handle(pos_event_t *ev);
    133178
     179static errno_t file_new(void);
     180static void file_open(void);
     181static errno_t file_open_file(const char *fname);
    134182static errno_t file_save(char const *fname);
    135183static void file_save_as(void);
    136 static errno_t file_insert(char *fname);
     184static errno_t file_insert(const char *fname);
    137185static errno_t file_save_range(char const *fname, spt_t const *spos,
    138186    spt_t const *epos);
    139187static char *range_get_str(spt_t const *spos, spt_t const *epos);
    140188
    141 static char *prompt(char const *prompt, char const *init_value);
    142 
    143 static void pane_text_display(void);
     189static errno_t pane_init(ui_window_t *, pane_t *);
     190static void pane_fini(pane_t *);
     191static ui_control_t *pane_ctl(pane_t *);
     192static errno_t pane_update(pane_t *);
     193static errno_t pane_text_display(pane_t *);
    144194static void pane_row_display(void);
    145 static void pane_row_range_display(int r0, int r1);
    146 static void pane_status_display(void);
    147 static void pane_caret_display(void);
     195static errno_t pane_row_range_display(pane_t *, int r0, int r1);
     196static void pane_status_display(pane_t *);
     197static void pane_caret_display(pane_t *);
    148198
    149199static void insert_char(char32_t c);
     
    164214static void selection_delete(void);
    165215static void selection_copy(void);
     216static void edit_cut(void);
     217static void edit_paste(void);
    166218static void insert_clipboard_data(void);
    167219
     
    185237
    186238static void status_display(char const *str);
     239static errno_t edit_ui_create(edit_t *);
     240static void edit_ui_destroy(edit_t *);
     241
     242static void edit_wnd_resize(ui_window_t *, void *);
     243static void edit_wnd_close(ui_window_t *, void *);
     244static void edit_wnd_focus(ui_window_t *, void *, unsigned);
     245static void edit_wnd_kbd_event(ui_window_t *, void *, kbd_event_t *);
     246static void edit_wnd_unfocus(ui_window_t *, void *, unsigned);
     247
     248static ui_window_cb_t edit_window_cb = {
     249        .resize = edit_wnd_resize,
     250        .close = edit_wnd_close,
     251        .focus = edit_wnd_focus,
     252        .kbd = edit_wnd_kbd_event,
     253        .unfocus = edit_wnd_unfocus
     254};
     255
     256static void edit_menubar_activate(ui_menu_bar_t *, void *);
     257static void edit_menubar_deactivate(ui_menu_bar_t *, void *);
     258
     259static ui_menu_bar_cb_t edit_menubar_cb = {
     260        .activate = edit_menubar_activate,
     261        .deactivate = edit_menubar_deactivate
     262};
     263
     264static void edit_file_new(ui_menu_entry_t *, void *);
     265static void edit_file_open(ui_menu_entry_t *, void *);
     266static void edit_file_save(ui_menu_entry_t *, void *);
     267static void edit_file_save_as(ui_menu_entry_t *, void *);
     268static void edit_file_exit(ui_menu_entry_t *, void *);
     269static void edit_edit_cut(ui_menu_entry_t *, void *);
     270static void edit_edit_copy(ui_menu_entry_t *, void *);
     271static void edit_edit_paste(ui_menu_entry_t *, void *);
     272static void edit_edit_delete(ui_menu_entry_t *, void *);
     273static void edit_edit_select_all(ui_menu_entry_t *, void *);
     274static void edit_search_find(ui_menu_entry_t *, void *);
     275static void edit_search_reverse_find(ui_menu_entry_t *, void *);
     276static void edit_search_find_next(ui_menu_entry_t *, void *);
     277static void edit_search_go_to_line(ui_menu_entry_t *, void *);
     278
     279static void pane_ctl_destroy(void *);
     280static errno_t pane_ctl_paint(void *);
     281static ui_evclaim_t pane_ctl_pos_event(void *, pos_event_t *);
     282
     283/** Pabe control ops */
     284ui_control_ops_t pane_ctl_ops = {
     285        .destroy = pane_ctl_destroy,
     286        .paint = pane_ctl_paint,
     287        .pos_event = pane_ctl_pos_event
     288};
     289
     290static void open_dialog_bok(ui_file_dialog_t *, void *, const char *);
     291static void open_dialog_bcancel(ui_file_dialog_t *, void *);
     292static void open_dialog_close(ui_file_dialog_t *, void *);
     293
     294static ui_file_dialog_cb_t open_dialog_cb = {
     295        .bok = open_dialog_bok,
     296        .bcancel = open_dialog_bcancel,
     297        .close = open_dialog_close
     298};
     299
     300static void save_as_dialog_bok(ui_file_dialog_t *, void *, const char *);
     301static void save_as_dialog_bcancel(ui_file_dialog_t *, void *);
     302static void save_as_dialog_close(ui_file_dialog_t *, void *);
     303
     304static ui_file_dialog_cb_t save_as_dialog_cb = {
     305        .bok = save_as_dialog_bok,
     306        .bcancel = save_as_dialog_bcancel,
     307        .close = save_as_dialog_close
     308};
     309
     310static void go_to_line_dialog_bok(ui_prompt_dialog_t *, void *, const char *);
     311static void go_to_line_dialog_bcancel(ui_prompt_dialog_t *, void *);
     312static void go_to_line_dialog_close(ui_prompt_dialog_t *, void *);
     313
     314static ui_prompt_dialog_cb_t go_to_line_dialog_cb = {
     315        .bok = go_to_line_dialog_bok,
     316        .bcancel = go_to_line_dialog_bcancel,
     317        .close =  go_to_line_dialog_close
     318};
     319
     320static void search_dialog_bok(ui_prompt_dialog_t *, void *, const char *);
     321static void search_dialog_bcancel(ui_prompt_dialog_t *, void *);
     322static void search_dialog_close(ui_prompt_dialog_t *, void *);
     323
     324static ui_prompt_dialog_cb_t search_dialog_cb = {
     325        .bok = search_dialog_bok,
     326        .bcancel = search_dialog_bcancel,
     327        .close =  search_dialog_close
     328};
    187329
    188330int main(int argc, char *argv[])
    189331{
    190         cons_event_t ev;
    191         bool new_file;
    192332        errno_t rc;
    193333
    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;
    201334        pane.sh_row = 1;
    202335        pane.sh_column = 1;
    203336
    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;
     337        /* Create UI */
     338        rc = edit_ui_create(&edit);
     339        if (rc != EOK)
     340                return 1;
    216341
    217342        if (argc == 2) {
    218343                doc.file_name = str_dup(argv[1]);
     344                rc = file_open_file(argv[1]);
     345                if (rc != EOK) {
     346                        status_display("File not found. Starting empty file.");
     347                        rc = file_new();
     348                }
    219349        } else if (argc > 1) {
    220350                printf("Invalid arguments.\n");
    221351                return -2;
    222352        } else {
    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);
     353                rc = file_new();
     354        }
    237355
    238356        /* Initial display */
    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 
     357        rc = ui_window_paint(edit.window);
     358        if (rc != EOK) {
     359                printf("Error painting window.\n");
     360                return rc;
     361        }
     362
     363        ui_run(edit.ui);
     364
     365        edit_ui_destroy(&edit);
    288366        return 0;
     367}
     368
     369/** Set menu bar rectangle.
     370 *
     371 * Set the menu bar rectangle based on editor window dimensions.
     372 * Used when window is created or resized.
     373 *
     374 * @param edit Editor
     375 */
     376static void edit_menubar_set_rect(edit_t *edit)
     377{
     378        gfx_rect_t arect;
     379        gfx_rect_t rect;
     380
     381        ui_window_get_app_rect(edit->window, &arect);
     382
     383        rect.p0 = arect.p0;
     384        rect.p1.x = arect.p1.x;
     385        rect.p1.y = arect.p0.y + 1;
     386        ui_menu_bar_set_rect(edit->menubar, &rect);
     387}
     388
     389/** Set status bar rectangle.
     390 *
     391 * Set the status bar rectangle based on editor window dimensions.
     392 * Used when window is created or resized.
     393 *
     394 * @param edit Editor
     395 */
     396static void edit_status_set_rect(edit_t *edit)
     397{
     398        gfx_rect_t arect;
     399        gfx_rect_t rect;
     400
     401        ui_window_get_app_rect(edit->window, &arect);
     402        rect.p0.x = arect.p0.x;
     403        rect.p0.y = arect.p1.y - 1;
     404        rect.p1 = arect.p1;
     405        ui_label_set_rect(edit->status, &rect);
     406}
     407
     408/** Create text editor UI.
     409 *
     410 * @param edit Editor
     411 * @return EOK on success or an error code
     412 */
     413static errno_t edit_ui_create(edit_t *edit)
     414{
     415        errno_t rc;
     416        ui_wnd_params_t params;
     417        ui_fixed_t *fixed = NULL;
     418        ui_menu_t *mfile = NULL;
     419        ui_menu_t *medit = NULL;
     420        ui_menu_entry_t *mnew = NULL;
     421        ui_menu_entry_t *mopen = NULL;
     422        ui_menu_entry_t *msave = NULL;
     423        ui_menu_entry_t *msaveas = NULL;
     424        ui_menu_entry_t *mfsep = NULL;
     425        ui_menu_entry_t *mexit = NULL;
     426        ui_menu_entry_t *mcut = NULL;
     427        ui_menu_entry_t *mcopy = NULL;
     428        ui_menu_entry_t *mpaste = NULL;
     429        ui_menu_entry_t *mdelete = NULL;
     430        ui_menu_entry_t *mesep = NULL;
     431        ui_menu_entry_t *mselall = NULL;
     432        ui_menu_t *msearch = NULL;
     433        ui_menu_entry_t *mfind = NULL;
     434        ui_menu_entry_t *mfindr = NULL;
     435        ui_menu_entry_t *mfindn = NULL;
     436        ui_menu_entry_t *mssep = NULL;
     437        ui_menu_entry_t *mgoto = NULL;
     438
     439        rc = ui_create(UI_CONSOLE_DEFAULT, &edit->ui);
     440        if (rc != EOK) {
     441                printf("Error creating UI on display %s.\n",
     442                    UI_CONSOLE_DEFAULT);
     443                goto error;
     444        }
     445
     446        ui_wnd_params_init(&params);
     447        params.caption = "Text Editor";
     448        params.style &= ~ui_wds_decorated;
     449        params.placement = ui_wnd_place_full_screen;
     450
     451        rc = ui_window_create(edit->ui, &params, &edit->window);
     452        if (rc != EOK) {
     453                printf("Error creating window.\n");
     454                goto error;
     455        }
     456
     457        ui_window_set_cb(edit->window, &edit_window_cb, (void *) edit);
     458
     459        edit->ui_res = ui_window_get_res(edit->window);
     460
     461        rc = ui_fixed_create(&fixed);
     462        if (rc != EOK) {
     463                printf("Error creating fixed layout.\n");
     464                return rc;
     465        }
     466
     467        rc = ui_menu_bar_create(edit->ui, edit->window, &edit->menubar);
     468        if (rc != EOK) {
     469                printf("Error creating menu bar.\n");
     470                return rc;
     471        }
     472
     473        ui_menu_bar_set_cb(edit->menubar, &edit_menubar_cb, (void *) edit);
     474
     475        rc = ui_menu_dd_create(edit->menubar, "~F~ile", NULL, &mfile);
     476        if (rc != EOK) {
     477                printf("Error creating menu.\n");
     478                return rc;
     479        }
     480
     481        rc = ui_menu_entry_create(mfile, "~N~ew", "Ctrl-N", &mnew);
     482        if (rc != EOK) {
     483                printf("Error creating menu.\n");
     484                return rc;
     485        }
     486
     487        ui_menu_entry_set_cb(mnew, edit_file_new, (void *) edit);
     488
     489        rc = ui_menu_entry_create(mfile, "~O~pen", "Ctrl-O", &mopen);
     490        if (rc != EOK) {
     491                printf("Error creating menu.\n");
     492                return rc;
     493        }
     494
     495        ui_menu_entry_set_cb(mopen, edit_file_open, (void *) edit);
     496
     497        rc = ui_menu_entry_create(mfile, "~S~ave", "Ctrl-S", &msave);
     498        if (rc != EOK) {
     499                printf("Error creating menu.\n");
     500                return rc;
     501        }
     502
     503        ui_menu_entry_set_cb(msave, edit_file_save, (void *) edit);
     504
     505        rc = ui_menu_entry_create(mfile, "Save ~A~s", "Ctrl-E", &msaveas);
     506        if (rc != EOK) {
     507                printf("Error creating menu.\n");
     508                return rc;
     509        }
     510
     511        ui_menu_entry_set_cb(msaveas, edit_file_save_as, (void *) edit);
     512
     513        rc = ui_menu_entry_sep_create(mfile, &mfsep);
     514        if (rc != EOK) {
     515                printf("Error creating menu.\n");
     516                return rc;
     517        }
     518
     519        rc = ui_menu_entry_create(mfile, "E~x~it", "Ctrl-Q", &mexit);
     520        if (rc != EOK) {
     521                printf("Error creating menu.\n");
     522                return rc;
     523        }
     524
     525        ui_menu_entry_set_cb(mexit, edit_file_exit, (void *) edit);
     526
     527        rc = ui_menu_dd_create(edit->menubar, "~E~dit", NULL, &medit);
     528        if (rc != EOK) {
     529                printf("Error creating menu.\n");
     530                return rc;
     531        }
     532
     533        rc = ui_menu_entry_create(medit, "Cu~t~", "Ctrl-X", &mcut);
     534        if (rc != EOK) {
     535                printf("Error creating menu.\n");
     536                return rc;
     537        }
     538
     539        ui_menu_entry_set_cb(mcut, edit_edit_cut, (void *) edit);
     540
     541        rc = ui_menu_entry_create(medit, "~C~opy", "Ctrl-C", &mcopy);
     542        if (rc != EOK) {
     543                printf("Error creating menu.\n");
     544                return rc;
     545        }
     546
     547        ui_menu_entry_set_cb(mcopy, edit_edit_copy, (void *) edit);
     548
     549        rc = ui_menu_entry_create(medit, "~P~aste", "Ctrl-V", &mpaste);
     550        if (rc != EOK) {
     551                printf("Error creating menu.\n");
     552                return rc;
     553        }
     554
     555        ui_menu_entry_set_cb(mpaste, edit_edit_paste, (void *) edit);
     556
     557        rc = ui_menu_entry_create(medit, "~D~elete", "Del", &mdelete);
     558        if (rc != EOK) {
     559                printf("Error creating menu.\n");
     560                return rc;
     561        }
     562
     563        ui_menu_entry_set_cb(mdelete, edit_edit_delete, (void *) edit);
     564
     565        rc = ui_menu_entry_sep_create(medit, &mesep);
     566        if (rc != EOK) {
     567                printf("Error creating menu.\n");
     568                return rc;
     569        }
     570
     571        rc = ui_menu_entry_create(medit, "Select ~A~ll", "Ctrl-A", &mselall);
     572        if (rc != EOK) {
     573                printf("Error creating menu.\n");
     574                return rc;
     575        }
     576
     577        ui_menu_entry_set_cb(mselall, edit_edit_select_all, (void *) edit);
     578
     579        rc = ui_menu_dd_create(edit->menubar, "~S~earch", NULL, &msearch);
     580        if (rc != EOK) {
     581                printf("Error creating menu.\n");
     582                return rc;
     583        }
     584
     585        rc = ui_menu_entry_create(msearch, "~F~ind", "Ctrl-F", &mfind);
     586        if (rc != EOK) {
     587                printf("Error creating menu.\n");
     588                return rc;
     589        }
     590
     591        ui_menu_entry_set_cb(mfind, edit_search_find, (void *) edit);
     592
     593        rc = ui_menu_entry_create(msearch, "~R~everse Find", "Ctrl-Shift-F", &mfindr);
     594        if (rc != EOK) {
     595                printf("Error creating menu.\n");
     596                return rc;
     597        }
     598
     599        ui_menu_entry_set_cb(mfindr, edit_search_reverse_find, (void *) edit);
     600
     601        rc = ui_menu_entry_create(msearch, "Find ~N~ext", "Ctrl-R", &mfindn);
     602        if (rc != EOK) {
     603                printf("Error creating menu.\n");
     604                return rc;
     605        }
     606
     607        ui_menu_entry_set_cb(mfindn, edit_search_find_next, (void *) edit);
     608
     609        rc = ui_menu_entry_sep_create(msearch, &mssep);
     610        if (rc != EOK) {
     611                printf("Error creating menu.\n");
     612                return rc;
     613        }
     614
     615        rc = ui_menu_entry_create(msearch, "Go To ~L~ine", "Ctrl-L", &mgoto);
     616        if (rc != EOK) {
     617                printf("Error creating menu.\n");
     618                return rc;
     619        }
     620
     621        ui_menu_entry_set_cb(mgoto, edit_search_go_to_line, (void *) edit);
     622
     623        edit_menubar_set_rect(edit);
     624
     625        rc = ui_fixed_add(fixed, ui_menu_bar_ctl(edit->menubar));
     626        if (rc != EOK) {
     627                printf("Error adding control to layout.\n");
     628                return rc;
     629        }
     630
     631        rc = pane_init(edit->window, &pane);
     632        if (rc != EOK) {
     633                printf("Error initializing pane.\n");
     634                return rc;
     635        }
     636
     637        rc = ui_fixed_add(fixed, pane_ctl(&pane));
     638        if (rc != EOK) {
     639                printf("Error adding control to layout.\n");
     640                return rc;
     641        }
     642
     643        rc = ui_label_create(edit->ui_res, "", &edit->status);
     644        if (rc != EOK) {
     645                printf("Error creating menu bar.\n");
     646                return rc;
     647        }
     648
     649        edit_status_set_rect(edit);
     650
     651        rc = ui_fixed_add(fixed, ui_label_ctl(edit->status));
     652        if (rc != EOK) {
     653                printf("Error adding control to layout.\n");
     654                return rc;
     655        }
     656
     657        ui_window_add(edit->window, ui_fixed_ctl(fixed));
     658        return EOK;
     659error:
     660        if (edit->window != NULL)
     661                ui_window_destroy(edit->window);
     662        if (edit->ui != NULL)
     663                ui_destroy(edit->ui);
     664        return rc;
     665}
     666
     667/** Destroy text editor UI.
     668 *
     669 * @param edit Editor
     670 */
     671static void edit_ui_destroy(edit_t *edit)
     672{
     673        ui_window_destroy(edit->window);
     674        ui_destroy(edit->ui);
    289675}
    290676
     
    309695}
    310696
    311 static void cursor_show(void)
    312 {
    313         cursor_setvis(true);
    314 }
    315 
    316 static void cursor_hide(void)
    317 {
    318         cursor_setvis(false);
    319 }
    320 
    321697static void cursor_setvis(bool visible)
    322698{
    323         if (cursor_visible != visible) {
    324                 console_cursor_visibility(con, visible);
    325                 cursor_visible = visible;
    326         }
     699        gfx_context_t *gc = ui_window_get_gc(edit.window);
     700
     701        (void) gfx_cursor_set_visible(gc, visible);
    327702}
    328703
     
    400775        switch (ev->key) {
    401776        case KC_Q:
    402                 done = true;
     777                ui_quit(edit.ui);
     778                break;
     779        case KC_N:
     780                file_new();
     781                break;
     782        case KC_O:
     783                file_open();
    403784                break;
    404785        case KC_S:
     
    415796                break;
    416797        case KC_V:
    417                 selection_delete();
    418                 insert_clipboard_data();
    419                 pane.rflags |= REDRAW_TEXT;
    420                 caret_update();
     798                edit_paste();
    421799                break;
    422800        case KC_X:
    423                 selection_copy();
    424                 selection_delete();
    425                 pane.rflags |= REDRAW_TEXT;
    426                 caret_update();
     801                edit_cut();
    427802                break;
    428803        case KC_A:
     
    441816                search_prompt(false);
    442817                break;
    443         case KC_N:
     818        case KC_R:
    444819                search_repeat();
    445820                break;
     
    490865
    491866        if (ev->type == POS_PRESS && ev->vpos < (unsigned)pane.rows) {
    492                 bc.row = pane.sh_row + ev->vpos;
    493                 bc.column = pane.sh_column + ev->hpos;
     867                bc.row = pane.sh_row + ev->vpos - pane.rect.p0.y;
     868                bc.column = pane.sh_column + ev->hpos - pane.rect.p0.x;
    494869                sheet_get_cell_pt(doc.sh, &bc, dir_before, &pt);
    495870
     
    497872
    498873                caret_move(pt, select, true);
     874                pane_update(&pane);
    499875        }
    500876}
     
    579955}
    580956
     957/** Create new document. */
     958static errno_t file_new(void)
     959{
     960        errno_t rc;
     961        sheet_t *sh;
     962
     963        /* Create empty sheet. */
     964        rc = sheet_create(&sh);
     965        if (rc != EOK) {
     966                printf("Out of memory.\n");
     967                return ENOMEM;
     968        }
     969
     970        if (doc.sh != NULL)
     971                sheet_destroy(doc.sh);
     972
     973        doc.sh = sh;
     974
     975        /* Place caret at the beginning of file. */
     976        spt_t sof;
     977        pt_get_sof(&sof);
     978        sheet_place_tag(doc.sh, &sof, &pane.caret_pos);
     979        pane.ideal_column = 1;
     980
     981        doc.file_name = NULL;
     982
     983        /* Place selection start tag. */
     984        sheet_place_tag(doc.sh, &sof, &pane.sel_start);
     985
     986        /* Move to beginning of file. */
     987        pt_get_sof(&sof);
     988
     989        caret_move(sof, true, true);
     990
     991        pane_status_display(&pane);
     992        pane_caret_display(&pane);
     993        pane_text_display(&pane);
     994        cursor_setvis(true);
     995
     996        return EOK;
     997}
     998
     999/** Open Open File dialog. */
     1000static void file_open(void)
     1001{
     1002        const char *old_fname = (doc.file_name != NULL) ? doc.file_name : "";
     1003        ui_file_dialog_params_t fdparams;
     1004        ui_file_dialog_t *dialog;
     1005        errno_t rc;
     1006
     1007        ui_file_dialog_params_init(&fdparams);
     1008        fdparams.caption = "Open File";
     1009        fdparams.ifname = old_fname;
     1010
     1011        rc = ui_file_dialog_create(edit.ui, &fdparams, &dialog);
     1012        if (rc != EOK) {
     1013                printf("Error creating message dialog.\n");
     1014                return;
     1015        }
     1016
     1017        ui_file_dialog_set_cb(dialog, &open_dialog_cb, &edit);
     1018}
     1019
     1020/** Open exising document. */
     1021static errno_t file_open_file(const char *fname)
     1022{
     1023        errno_t rc;
     1024        sheet_t *sh;
     1025        char *fn;
     1026
     1027        /* Create empty sheet. */
     1028        rc = sheet_create(&sh);
     1029        if (rc != EOK) {
     1030                printf("Out of memory.\n");
     1031                return ENOMEM;
     1032        }
     1033
     1034        fn = str_dup(fname);
     1035        if (fn == NULL) {
     1036                sheet_destroy(sh);
     1037                return ENOMEM;
     1038        }
     1039
     1040        if (doc.sh != NULL)
     1041                sheet_destroy(doc.sh);
     1042
     1043        doc.sh = sh;
     1044
     1045        /* Place caret at the beginning of file. */
     1046        spt_t sof;
     1047        pt_get_sof(&sof);
     1048        sheet_place_tag(doc.sh, &sof, &pane.caret_pos);
     1049        pane.ideal_column = 1;
     1050
     1051        rc = file_insert(fname);
     1052        if (rc != EOK)
     1053                return rc;
     1054
     1055        doc.file_name = fn;
     1056
     1057        /* Place selection start tag. */
     1058        sheet_place_tag(doc.sh, &sof, &pane.sel_start);
     1059
     1060        /* Move to beginning of file. */
     1061        pt_get_sof(&sof);
     1062
     1063        caret_move(sof, true, true);
     1064
     1065        pane_status_display(&pane);
     1066        pane_caret_display(&pane);
     1067        pane_text_display(&pane);
     1068        cursor_setvis(true);
     1069
     1070        return EOK;
     1071}
     1072
    5811073/** Save the document. */
    5821074static errno_t file_save(char const *fname)
     
    6061098}
    6071099
    608 /** Change document name and save. */
     1100/** Open Save As dialog. */
    6091101static void file_save_as(void)
    6101102{
    6111103        const char *old_fname = (doc.file_name != NULL) ? doc.file_name : "";
    612         char *fname;
    613 
    614         fname = prompt("Save As", old_fname);
    615         if (fname == NULL) {
    616                 status_display("Save cancelled.");
     1104        ui_file_dialog_params_t fdparams;
     1105        ui_file_dialog_t *dialog;
     1106        errno_t rc;
     1107
     1108        ui_file_dialog_params_init(&fdparams);
     1109        fdparams.caption = "Save As";
     1110        fdparams.ifname = old_fname;
     1111
     1112        rc = ui_file_dialog_create(edit.ui, &fdparams, &dialog);
     1113        if (rc != EOK) {
     1114                printf("Error creating message dialog.\n");
    6171115                return;
    6181116        }
    6191117
    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. */
    630 static 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;
    639         errno_t rc;
    640 
    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;
     1118        ui_file_dialog_set_cb(dialog, &save_as_dialog_cb, &edit);
    6941119}
    6951120
     
    6991124 * of the caret.
    7001125 */
    701 static errno_t file_insert(char *fname)
     1126static errno_t file_insert(const char *fname)
    7021127{
    7031128        FILE *f;
     
    7261151
    7271152                bcnt -= off;
    728                 memcpy(buf, buf + off, bcnt);
     1153                memmove(buf, buf + off, bcnt);
    7291154
    7301155                insert_char(c);
     
    8081233}
    8091234
    810 static void pane_text_display(void)
    811 {
     1235static void pane_set_rect(pane_t *pane)
     1236{
     1237        gfx_rect_t arect;
     1238
     1239        ui_window_get_app_rect(pane->window, &arect);
     1240        pane->rect.p0.x = arect.p0.x;
     1241        pane->rect.p0.y = arect.p0.y + 1;
     1242        pane->rect.p1.x = arect.p1.x;
     1243        pane->rect.p1.y = arect.p1.y - 1;
     1244
     1245        pane->columns = pane->rect.p1.x - pane->rect.p0.x;
     1246        pane->rows = pane->rect.p1.y - pane->rect.p0.y;
     1247}
     1248
     1249/** Initialize pane.
     1250 *
     1251 * TODO: Replace with pane_create() that allocates the pane.
     1252 *
     1253 * @param window Editor window
     1254 * @param pane Pane
     1255 * @return EOK on success or an error code
     1256 */
     1257static errno_t pane_init(ui_window_t *window, pane_t *pane)
     1258{
     1259        errno_t rc;
     1260
     1261        pane->control = NULL;
     1262        pane->color = NULL;
     1263        pane->sel_color = NULL;
     1264
     1265        rc = ui_control_new(&pane_ctl_ops, (void *) pane, &pane->control);
     1266        if (rc != EOK)
     1267                goto error;
     1268
     1269        rc = gfx_color_new_ega(0x07, &pane->color);
     1270        if (rc != EOK)
     1271                goto error;
     1272
     1273        rc = gfx_color_new_ega(0x1e, &pane->sel_color);
     1274        if (rc != EOK)
     1275                goto error;
     1276
     1277        pane->res = ui_window_get_res(window);
     1278        pane->window = window;
     1279
     1280        pane_set_rect(pane);
     1281        return EOK;
     1282error:
     1283        if (pane->control != NULL) {
     1284                ui_control_delete(pane->control);
     1285                pane->control = NULL;
     1286        }
     1287
     1288        if (pane->color != NULL) {
     1289                gfx_color_delete(pane->color);
     1290                pane->color = NULL;
     1291        }
     1292
     1293        return rc;
     1294}
     1295
     1296static void pane_resize(pane_t *pane)
     1297{
     1298        pane_set_rect(pane);
     1299
     1300        /* Scroll in case cursor is now outside of the editor pane. */
     1301        caret_move_relative(0, 0, dir_before, true);
     1302
     1303        pane_caret_display(pane);
     1304}
     1305
     1306/** Finalize pane.
     1307 *
     1308 * TODO: Replace with pane_destroy() that deallocates the pane.
     1309 *
     1310 * @param pane Pane
     1311 */
     1312static void pane_fini(pane_t *pane)
     1313{
     1314        gfx_color_delete(pane->color);
     1315        pane->color = NULL;
     1316        gfx_color_delete(pane->sel_color);
     1317        pane->sel_color = NULL;
     1318        ui_control_delete(pane->control);
     1319        pane->control = NULL;
     1320}
     1321
     1322/** Return base control object for a pane.
     1323 *
     1324 * @param pane Pane
     1325 * @return Base UI cntrol
     1326 */
     1327static ui_control_t *pane_ctl(pane_t *pane)
     1328{
     1329        return pane->control;
     1330}
     1331
     1332/** Repaint parts of pane that need updating.
     1333 *
     1334 * @param pane Pane
     1335 * @return EOK on succes or an error code
     1336 */
     1337static errno_t pane_update(pane_t *pane)
     1338{
     1339        errno_t rc;
     1340
     1341        if (pane->rflags & REDRAW_TEXT) {
     1342                rc = pane_text_display(pane);
     1343                if (rc != EOK)
     1344                        return rc;
     1345        }
     1346
     1347        if (pane->rflags & REDRAW_ROW)
     1348                pane_row_display();
     1349
     1350        if (pane->rflags & REDRAW_STATUS)
     1351                pane_status_display(pane);
     1352
     1353        if (pane->rflags & REDRAW_CARET)
     1354                pane_caret_display(pane);
     1355
     1356        pane->rflags &= ~(REDRAW_TEXT | REDRAW_ROW | REDRAW_STATUS |
     1357            REDRAW_CARET);
     1358        return EOK;
     1359}
     1360
     1361/** Display pane text.
     1362 *
     1363 * @param pane Pane
     1364 * @return EOK on success or an error code
     1365 */
     1366static errno_t pane_text_display(pane_t *pane)
     1367{
     1368        gfx_rect_t rect;
     1369        gfx_context_t *gc;
     1370        errno_t rc;
    8121371        int sh_rows, rows;
    8131372
    8141373        sheet_get_num_rows(doc.sh, &sh_rows);
    815         rows = min(sh_rows - pane.sh_row + 1, pane.rows);
     1374        rows = min(sh_rows - pane->sh_row + 1, pane->rows);
    8161375
    8171376        /* Draw rows from the sheet. */
    8181377
    819         console_set_pos(con, 0, 0);
    820         pane_row_range_display(0, rows);
     1378        rc = pane_row_range_display(pane, 0, rows);
     1379        if (rc != EOK)
     1380                return rc;
    8211381
    8221382        /* Clear the remaining rows if file is short. */
    8231383
    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;
     1384        gc = ui_window_get_gc(pane->window);
     1385
     1386        rc = gfx_set_color(gc, pane->color);
     1387        if (rc != EOK)
     1388                goto error;
     1389
     1390        rect.p0.x = pane->rect.p0.x;
     1391        rect.p0.y = pane->rect.p0.y + rows;
     1392        rect.p1.x = pane->rect.p1.x;
     1393        rect.p1.y = pane->rect.p1.y;
     1394
     1395        rc = gfx_fill_rect(gc, &rect);
     1396        if (rc != EOK)
     1397                goto error;
     1398
     1399        pane->rflags &= ~REDRAW_ROW;
     1400        return EOK;
     1401error:
     1402        return rc;
    8351403}
    8361404
     
    8461414
    8471415        ridx = coord.row - pane.sh_row;
    848         pane_row_range_display(ridx, ridx + 1);
     1416        (void) pane_row_range_display(&pane, ridx, ridx + 1);
    8491417        pane.rflags |= (REDRAW_STATUS | REDRAW_CARET);
    8501418}
    8511419
    852 static void pane_row_range_display(int r0, int r1)
    853 {
    854         int i, j, fill;
     1420/** Display a range of rows of text.
     1421 *
     1422 * @param r0 Start row (inclusive)
     1423 * @param r1 End row (exclusive)
     1424 * @return EOk on success or an error code
     1425 */
     1426static errno_t pane_row_range_display(pane_t *pane, int r0, int r1)
     1427{
     1428        int i, fill;
    8551429        spt_t rb, re, dep, pt;
    8561430        coord_t rbc, rec;
    8571431        char row_buf[ROW_BUF_SIZE];
     1432        char cbuf[STR_BOUNDS(1) + 1];
    8581433        char32_t c;
    8591434        size_t pos, size;
     1435        size_t cpos;
    8601436        int s_column;
    8611437        coord_t csel_start, csel_end, ctmp;
     1438        gfx_font_t *font;
     1439        gfx_context_t *gc;
     1440        gfx_text_fmt_t fmt;
     1441        gfx_coord2_t tpos;
     1442        gfx_rect_t rect;
     1443        errno_t rc;
     1444
     1445        font = ui_resource_get_font(edit.ui_res);
     1446        gc = ui_window_get_gc(edit.window);
     1447
     1448        gfx_text_fmt_init(&fmt);
     1449        fmt.font = font;
     1450        fmt.color = pane->color;
    8621451
    8631452        /* Determine selection start and end. */
    8641453
    865         tag_get_pt(&pane.sel_start, &pt);
     1454        tag_get_pt(&pane->sel_start, &pt);
    8661455        spt_get_coord(&pt, &csel_start);
    8671456
    868         tag_get_pt(&pane.caret_pos, &pt);
     1457        tag_get_pt(&pane->caret_pos, &pt);
    8691458        spt_get_coord(&pt, &csel_end);
    8701459
     
    8771466        /* Draw rows from the sheet. */
    8781467
    879         console_set_pos(con, 0, 0);
    8801468        for (i = r0; i < r1; ++i) {
     1469                tpos.x = pane->rect.p0.x;
     1470                tpos.y = pane->rect.p0.y + i;
     1471
    8811472                /* Starting point for row display */
    882                 rbc.row = pane.sh_row + i;
    883                 rbc.column = pane.sh_column;
     1473                rbc.row = pane->sh_row + i;
     1474                rbc.column = pane->sh_column;
    8841475                sheet_get_cell_pt(doc.sh, &rbc, dir_before, &rb);
    8851476
    8861477                /* Ending point for row display */
    887                 rec.row = pane.sh_row + i;
    888                 rec.column = pane.sh_column + pane.columns;
     1478                rec.row = pane->sh_row + i;
     1479                rec.column = pane->sh_column + pane->columns;
    8891480                sheet_get_cell_pt(doc.sh, &rec, dir_before, &re);
    8901481
     
    8961487                if (coord_cmp(&csel_start, &rbc) <= 0 &&
    8971488                    coord_cmp(&rbc, &csel_end) < 0) {
    898                         console_flush(con);
    899                         console_set_style(con, STYLE_SELECTED);
    900                         console_flush(con);
     1489                        fmt.color = pane->sel_color;
    9011490                }
    9021491
    903                 console_set_pos(con, 0, i);
    9041492                size = str_size(row_buf);
    9051493                pos = 0;
    906                 s_column = pane.sh_column;
     1494                s_column = pane->sh_column;
    9071495                while (pos < size) {
    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                         }
     1496                        if ((csel_start.row == rbc.row) && (csel_start.column == s_column))
     1497                                fmt.color = pane->sel_color;
     1498
     1499                        if ((csel_end.row == rbc.row) && (csel_end.column == s_column))
     1500                                fmt.color = pane->color;
    9191501
    9201502                        c = str_decode(row_buf, &pos, size);
    9211503                        if (c != '\t') {
    922                                 printf("%lc", (wint_t) c);
     1504                                cpos = 0;
     1505                                rc = chr_encode(c, cbuf, &cpos, sizeof(cbuf));
     1506                                if (rc != EOK)
     1507                                        return rc;
     1508
     1509                                rc = gfx_puttext(&tpos, &fmt, cbuf);
     1510                                if (rc != EOK)
     1511                                        return rc;
     1512
    9231513                                s_column += 1;
     1514                                tpos.x++;
    9241515                        } else {
    9251516                                fill = 1 + ALIGN_UP(s_column, TAB_WIDTH) -
    9261517                                    s_column;
    9271518
    928                                 for (j = 0; j < fill; ++j)
    929                                         putchar(' ');
     1519                                rc = gfx_set_color(gc, fmt.color);
     1520                                if (rc != EOK)
     1521                                        return rc;
     1522
     1523                                rect.p0.x = tpos.x;
     1524                                rect.p0.y = tpos.y;
     1525                                rect.p1.x = tpos.x + fill;
     1526                                rect.p1.y = tpos.y + 1;
     1527
     1528                                rc = gfx_fill_rect(gc, &rect);
     1529                                if (rc != EOK)
     1530                                        return rc;
     1531
    9301532                                s_column += fill;
     1533                                tpos.x += fill;
    9311534                        }
    9321535                }
    9331536
    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                 }
     1537                if ((csel_end.row == rbc.row) && (csel_end.column == s_column))
     1538                        fmt.color = pane->color;
    9391539
    9401540                /* Fill until the end of display area. */
    9411541
    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. */
    957 static void pane_status_display(void)
     1542                rc = gfx_set_color(gc, fmt.color);
     1543                if (rc != EOK)
     1544                        return rc;
     1545
     1546                rect.p0.x = tpos.x;
     1547                rect.p0.y = tpos.y;
     1548                rect.p1.x = pane->rect.p1.x;
     1549                rect.p1.y = tpos.y + 1;
     1550
     1551                rc = gfx_fill_rect(gc, &rect);
     1552                if (rc != EOK)
     1553                        return rc;
     1554        }
     1555
     1556        return EOK;
     1557}
     1558
     1559/** Display pane status in the status line.
     1560 *
     1561 * @param pane Pane
     1562 */
     1563static void pane_status_display(pane_t *pane)
    9581564{
    9591565        spt_t caret_pt;
     
    9641570        char *text;
    9651571        size_t n;
    966         int pos;
    9671572        size_t nextra;
    9681573        size_t fnw;
    9691574
    970         tag_get_pt(&pane.caret_pos, &caret_pt);
     1575        tag_get_pt(&pane->caret_pos, &caret_pt);
    9711576        spt_get_coord(&caret_pt, &coord);
    9721577
     
    9871592                return;
    9881593
    989         console_set_pos(con, 0, scr_rows - 1);
    990         console_set_style(con, STYLE_INVERTED);
    991 
    9921594        /*
    9931595         * Make sure the status fits on the screen. This loop should
     
    9951597         */
    9961598        while (true) {
    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);
     1599                int rc = asprintf(&text, "%d, %d (%d): File '%s'. Ctrl-Q Quit  "
     1600                    "F10 Menu", coord.row, coord.column, last_row, fname);
    9991601                if (rc < 0) {
    10001602                        n = 0;
     
    10041606                /* If it already fits, we're done */
    10051607                n = str_width(text);
    1006                 if (n <= scr_columns - 2)
     1608                if ((int)n <= pane->columns - 2)
    10071609                        break;
    10081610
    10091611                /* Compute number of excess characters */
    1010                 nextra = n - (scr_columns - 2);
     1612                nextra = n - (pane->columns - 2);
    10111613                /** With of the file name part */
    10121614                fnw = str_width(fname);
     
    10161618                 * just give up and print a blank status.
    10171619                 */
    1018                 if (nextra > fnw - 2)
     1620                if (nextra > fnw - 2) {
     1621                        text[0] = '\0';
    10191622                        goto finish;
     1623                }
    10201624
    10211625                /* Compute position where we overwrite with '..\0' */
     
    10341638        }
    10351639
    1036         printf("%s", text);
     1640finish:
     1641        (void) ui_label_set_text(edit.status, text);
     1642        (void) ui_label_paint(edit.status);
    10371643        free(text);
    10381644        free(fname);
    1039 finish:
    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. */
    1050 static void pane_caret_display(void)
     1645}
     1646
     1647/** Set cursor to reflect position of the caret.
     1648 *
     1649 * @param pane Pane
     1650 */
     1651static void pane_caret_display(pane_t *pane)
    10511652{
    10521653        spt_t caret_pt;
    10531654        coord_t coord;
    1054 
    1055         tag_get_pt(&pane.caret_pos, &caret_pt);
     1655        gfx_coord2_t pos;
     1656        gfx_context_t *gc;
     1657
     1658        tag_get_pt(&pane->caret_pos, &caret_pt);
    10561659
    10571660        spt_get_coord(&caret_pt, &coord);
    1058         console_set_pos(con, coord.column - pane.sh_column,
    1059             coord.row - pane.sh_row);
     1661
     1662        gc = ui_window_get_gc(edit.window);
     1663        pos.x = pane->rect.p0.x + coord.column - pane->sh_column;
     1664        pos.y = pane->rect.p0.y + coord.row - pane->sh_row;
     1665
     1666        (void) gfx_cursor_set_pos(gc, &pos);
     1667}
     1668
     1669/** Destroy pane control.
     1670 *
     1671 * @param arg Argument (pane_t *)
     1672 */
     1673static void pane_ctl_destroy(void *arg)
     1674{
     1675        pane_t *pane = (pane_t *)arg;
     1676
     1677        pane_fini(pane);
     1678}
     1679
     1680/** Paint pane control.
     1681 *
     1682 * @param arg Argument (pane_t *)
     1683 */
     1684static errno_t pane_ctl_paint(void *arg)
     1685{
     1686        pane_t *pane = (pane_t *)arg;
     1687        gfx_context_t *gc;
     1688        errno_t rc;
     1689
     1690        gc = ui_window_get_gc(pane->window);
     1691
     1692        rc = pane_text_display(pane);
     1693        if (rc != EOK)
     1694                goto error;
     1695
     1696        rc = gfx_update(gc);
     1697        if (rc != EOK)
     1698                goto error;
     1699
     1700error:
     1701        return rc;
     1702}
     1703
     1704/** Handle pane control position event.
     1705 *
     1706 * @param arg Argument (pane_t *)
     1707 * @param event Position event
     1708 */
     1709static ui_evclaim_t pane_ctl_pos_event(void *arg, pos_event_t *event)
     1710{
     1711        gfx_coord2_t pos;
     1712
     1713        pos.x = event->hpos;
     1714        pos.y = event->vpos;
     1715
     1716        if (!gfx_pix_inside_rect(&pos, &pane.rect))
     1717                return ui_unclaimed;
     1718
     1719        pos_handle(event);
     1720        (void) gfx_update(ui_window_get_gc(edit.window));
     1721        return ui_claimed;
    10601722}
    10611723
     
    12701932static void caret_go_to_line_ask(void)
    12711933{
    1272         char *sline;
    1273 
    1274         sline = prompt("Go to line", "");
    1275         if (sline == NULL) {
    1276                 status_display("Go to line cancelled.");
     1934        ui_prompt_dialog_params_t pdparams;
     1935        ui_prompt_dialog_t *dialog;
     1936        errno_t rc;
     1937
     1938        ui_prompt_dialog_params_init(&pdparams);
     1939        pdparams.caption = "Go To Line";
     1940        pdparams.prompt = "Line Number";
     1941
     1942        rc = ui_prompt_dialog_create(edit.ui, &pdparams, &dialog);
     1943        if (rc != EOK) {
     1944                printf("Error creating prompt dialog.\n");
    12771945                return;
    12781946        }
    12791947
    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);
     1948        ui_prompt_dialog_set_cb(dialog, &go_to_line_dialog_cb, &edit);
    12901949}
    12911950
     
    13442003static void search_prompt(bool reverse)
    13452004{
    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 = "";
     2005        ui_prompt_dialog_params_t pdparams;
     2006        ui_prompt_dialog_t *dialog;
     2007        errno_t rc;
     2008
     2009        ui_prompt_dialog_params_init(&pdparams);
     2010        pdparams.caption = reverse ? "Reverse Search" : "Search";
     2011        pdparams.prompt = "Search text";
     2012        pdparams.itext = "";
     2013
    13532014        if (pane.previous_search)
    1354                 default_value = pane.previous_search;
    1355 
    1356         pattern = prompt(prompt_text, default_value);
    1357         if (pattern == NULL) {
    1358                 status_display("Search cancelled.");
     2015                pdparams.itext = pane.previous_search;
     2016
     2017        rc = ui_prompt_dialog_create(edit.ui, &pdparams, &dialog);
     2018        if (rc != EOK) {
     2019                printf("Error creating prompt dialog.\n");
    13592020                return;
    13602021        }
    13612022
    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);
     2023        ui_prompt_dialog_set_cb(dialog, &search_dialog_cb, &edit);
     2024        pane.search_reverse = reverse;
    13682025}
    13692026
     
    15132170        }
    15142171        free(str);
     2172}
     2173
     2174static void edit_paste(void)
     2175{
     2176        selection_delete();
     2177        insert_clipboard_data();
     2178        pane.rflags |= (REDRAW_TEXT | REDRAW_CARET);
     2179        pane_update(&pane);
     2180}
     2181
     2182static void edit_cut(void)
     2183{
     2184        selection_copy();
     2185        selection_delete();
     2186        pane.rflags |= (REDRAW_TEXT | REDRAW_CARET);
     2187        pane_update(&pane);
    15152188}
    15162189
     
    17192392static void status_display(char const *str)
    17202393{
    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);
     2394        (void) ui_label_set_text(edit.status, str);
     2395        (void) ui_label_paint(edit.status);
     2396}
     2397
     2398/** Window was resized.
     2399 *
     2400 * @param window Window
     2401 * @param arg Argument (edit_t *)
     2402 */
     2403static void edit_wnd_resize(ui_window_t *window, void *arg)
     2404{
     2405        edit_t *edit = (edit_t *) arg;
     2406
     2407        edit_menubar_set_rect(edit);
     2408        edit_status_set_rect(edit);
     2409        pane_resize(&pane);
     2410}
     2411
     2412/** Window close request
     2413 *
     2414 * @param window Window
     2415 * @param arg Argument (edit_t *)
     2416 */
     2417static void edit_wnd_close(ui_window_t *window, void *arg)
     2418{
     2419        edit_t *edit = (edit_t *) arg;
     2420
     2421        ui_quit(edit->ui);
     2422}
     2423
     2424/** Window focus event
     2425 *
     2426 * @param window Window
     2427 * @param arg Argument (edit_t *)
     2428 * @param focus Focus number
     2429 */
     2430static void edit_wnd_focus(ui_window_t *window, void *arg, unsigned focus)
     2431{
     2432        edit_t *edit = (edit_t *)arg;
     2433
     2434        (void)edit;
     2435        pane_caret_display(&pane);
     2436        cursor_setvis(true);
     2437}
     2438
     2439/** Window keyboard event
     2440 *
     2441 * @param window Window
     2442 * @param arg Argument (edit_t *)
     2443 * @param event Keyboard event
     2444 */
     2445static void edit_wnd_kbd_event(ui_window_t *window, void *arg,
     2446    kbd_event_t *event)
     2447{
     2448        pane.keymod = event->mods;
     2449
     2450        if (ui_window_def_kbd(window, event) == ui_claimed)
     2451                return;
     2452
     2453        if (event->type == KEY_PRESS) {
     2454                key_handle_press(event);
     2455                (void) pane_update(&pane);
     2456                (void) gfx_update(ui_window_get_gc(window));
     2457        }
     2458}
     2459
     2460/** Window unfocus event
     2461 *
     2462 * @param window Window
     2463 * @param arg Argument (edit_t *)
     2464 * @param focus Focus number
     2465 */
     2466static void edit_wnd_unfocus(ui_window_t *window, void *arg, unsigned focus)
     2467{
     2468        edit_t *edit = (edit_t *) arg;
     2469
     2470        (void)edit;
     2471        cursor_setvis(false);
     2472}
     2473
     2474/** Menu bar activate event
     2475 *
     2476 * @param mbar Menu bar
     2477 * @param arg Argument (edit_t *)
     2478 */
     2479static void edit_menubar_activate(ui_menu_bar_t *mbar, void *arg)
     2480{
     2481        edit_t *edit = (edit_t *)arg;
     2482
     2483        (void)edit;
     2484        cursor_setvis(false);
     2485}
     2486
     2487/** Menu bar deactivate event
     2488 *
     2489 * @param mbar Menu bar
     2490 * @param arg Argument (edit_t *)
     2491 */
     2492static void edit_menubar_deactivate(ui_menu_bar_t *mbar, void *arg)
     2493{
     2494        edit_t *edit = (edit_t *)arg;
     2495
     2496        (void)edit;
     2497        pane_caret_display(&pane);
     2498        cursor_setvis(true);
     2499}
     2500
     2501/** File / New menu entry selected.
     2502 *
     2503 * @param mentry Menu entry
     2504 * @param arg Argument (edit_t *)
     2505 */
     2506static void edit_file_new(ui_menu_entry_t *mentry, void *arg)
     2507{
     2508        edit_t *edit = (edit_t *) arg;
     2509
     2510        (void)edit;
     2511        file_new();
     2512        (void) gfx_update(ui_window_get_gc(edit->window));
     2513}
     2514
     2515/** File / Open menu entry selected.
     2516 *
     2517 * @param mentry Menu entry
     2518 * @param arg Argument (edit_t *)
     2519 */
     2520static void edit_file_open(ui_menu_entry_t *mentry, void *arg)
     2521{
     2522        edit_t *edit = (edit_t *) arg;
     2523
     2524        (void)edit;
     2525        file_open();
     2526}
     2527
     2528/** File / Save menu entry selected.
     2529 *
     2530 * @param mentry Menu entry
     2531 * @param arg Argument (edit_t *)
     2532 */
     2533static void edit_file_save(ui_menu_entry_t *mentry, void *arg)
     2534{
     2535        edit_t *edit = (edit_t *) arg;
     2536
     2537        (void)edit;
     2538
     2539        if (doc.file_name != NULL)
     2540                file_save(doc.file_name);
     2541        else
     2542                file_save_as();
     2543}
     2544
     2545/** File / Save As menu entry selected.
     2546 *
     2547 * @param mentry Menu entry
     2548 * @param arg Argument (edit_t *)
     2549 */
     2550static void edit_file_save_as(ui_menu_entry_t *mentry, void *arg)
     2551{
     2552        edit_t *edit = (edit_t *) arg;
     2553
     2554        (void)edit;
     2555        file_save_as();
     2556}
     2557
     2558/** File / Exit menu entry selected.
     2559 *
     2560 * @param mentry Menu entry
     2561 * @param arg Argument (edit_t *)
     2562 */
     2563static void edit_file_exit(ui_menu_entry_t *mentry, void *arg)
     2564{
     2565        edit_t *edit = (edit_t *) arg;
     2566
     2567        ui_quit(edit->ui);
     2568}
     2569
     2570/** Edit / Cut menu entry selected.
     2571 *
     2572 * @param mentry Menu entry
     2573 * @param arg Argument (edit_t *)
     2574 */
     2575static void edit_edit_cut(ui_menu_entry_t *mentry, void *arg)
     2576{
     2577        (void) arg;
     2578        edit_cut();
     2579        (void) gfx_update(ui_window_get_gc(edit.window));
     2580}
     2581
     2582/** Edit / Copy menu entry selected.
     2583 *
     2584 * @param mentry Menu entry
     2585 * @param arg Argument (edit_t *)
     2586 */
     2587static void edit_edit_copy(ui_menu_entry_t *mentry, void *arg)
     2588{
     2589        (void) arg;
     2590        selection_copy();
     2591}
     2592
     2593/** Edit / Paste menu entry selected.
     2594 *
     2595 * @param mentry Menu entry
     2596 * @param arg Argument (edit_t *)
     2597 */
     2598static void edit_edit_paste(ui_menu_entry_t *mentry, void *arg)
     2599{
     2600        (void) arg;
     2601        edit_paste();
     2602        (void) gfx_update(ui_window_get_gc(edit.window));
     2603}
     2604
     2605/** Edit / Delete menu entry selected.
     2606 *
     2607 * @param mentry Menu entry
     2608 * @param arg Argument (edit_t *)
     2609 */
     2610static void edit_edit_delete(ui_menu_entry_t *mentry, void *arg)
     2611{
     2612        (void) arg;
     2613
     2614        if (selection_active())
     2615                selection_delete();
    17282616
    17292617        pane.rflags |= REDRAW_CARET;
     2618        (void) pane_update(&pane);
     2619        (void) gfx_update(ui_window_get_gc(edit.window));
     2620}
     2621
     2622/** Edit / Select All menu entry selected.
     2623 *
     2624 * @param mentry Menu entry
     2625 * @param arg Argument (edit_t *)
     2626 */
     2627static void edit_edit_select_all(ui_menu_entry_t *mentry, void *arg)
     2628{
     2629        (void) arg;
     2630
     2631        selection_sel_all();
     2632        pane.rflags |= (REDRAW_CARET | REDRAW_TEXT | REDRAW_STATUS);
     2633        pane_update(&pane);
     2634        (void) gfx_update(ui_window_get_gc(edit.window));
     2635}
     2636
     2637/** Search / Find menu entry selected.
     2638 *
     2639 * @param mentry Menu entry
     2640 * @param arg Argument (edit_t *)
     2641 */
     2642static void edit_search_find(ui_menu_entry_t *mentry, void *arg)
     2643{
     2644        (void) arg;
     2645        search_prompt(false);
     2646}
     2647
     2648/** Search / Reverse Find menu entry selected.
     2649 *
     2650 * @param mentry Menu entry
     2651 * @param arg Argument (edit_t *)
     2652 */
     2653static void edit_search_reverse_find(ui_menu_entry_t *mentry, void *arg)
     2654{
     2655        (void) arg;
     2656        search_prompt(true);
     2657}
     2658
     2659/** Search / Find Next menu entry selected.
     2660 *
     2661 * @param mentry Menu entry
     2662 * @param arg Argument (edit_t *)
     2663 */
     2664static void edit_search_find_next(ui_menu_entry_t *mentry, void *arg)
     2665{
     2666        (void) arg;
     2667        search_repeat();
     2668        (void) pane_update(&pane);
     2669        (void) gfx_update(ui_window_get_gc(edit.window));
     2670}
     2671
     2672/** Search / Go To Line menu entry selected.
     2673 *
     2674 * @param mentry Menu entry
     2675 * @param arg Argument (edit_t *)
     2676 */
     2677static void edit_search_go_to_line(ui_menu_entry_t *mentry, void *arg)
     2678{
     2679        (void) arg;
     2680        caret_go_to_line_ask();
     2681}
     2682
     2683/** Open File dialog OK button press.
     2684 *
     2685 * @param dialog Open File dialog
     2686 * @param arg Argument (ui_demo_t *)
     2687 * @param fname File name
     2688 */
     2689static void open_dialog_bok(ui_file_dialog_t *dialog, void *arg,
     2690    const char *fname)
     2691{
     2692        edit_t *edit = (edit_t *)arg;
     2693        char *cname;
     2694        errno_t rc;
     2695
     2696        (void)edit;
     2697        ui_file_dialog_destroy(dialog);
     2698
     2699        cname = str_dup(fname);
     2700        if (cname == NULL) {
     2701                printf("Out of memory.\n");
     2702                return;
     2703        }
     2704
     2705        rc = file_open_file(fname);
     2706        if (rc != EOK)
     2707                return;
     2708
     2709        if (doc.file_name != NULL)
     2710                free(doc.file_name);
     2711        doc.file_name = cname;
     2712
     2713        (void) gfx_update(ui_window_get_gc(edit->window));
     2714}
     2715
     2716/** Open File dialog cancel button press.
     2717 *
     2718 * @param dialog File dialog
     2719 * @param arg Argument (ui_demo_t *)
     2720 */
     2721static void open_dialog_bcancel(ui_file_dialog_t *dialog, void *arg)
     2722{
     2723        edit_t *edit = (edit_t *)arg;
     2724
     2725        (void)edit;
     2726        ui_file_dialog_destroy(dialog);
     2727}
     2728
     2729/** Open File dialog close request.
     2730 *
     2731 * @param dialog File dialog
     2732 * @param arg Argument (ui_demo_t *)
     2733 */
     2734static void open_dialog_close(ui_file_dialog_t *dialog, void *arg)
     2735{
     2736        edit_t *edit = (edit_t *)arg;
     2737
     2738        (void)edit;
     2739        ui_file_dialog_destroy(dialog);
     2740}
     2741
     2742/** Save As dialog OK button press.
     2743 *
     2744 * @param dialog Save As dialog
     2745 * @param arg Argument (ui_demo_t *)
     2746 * @param fname File name
     2747 */
     2748static void save_as_dialog_bok(ui_file_dialog_t *dialog, void *arg,
     2749    const char *fname)
     2750{
     2751        edit_t *edit = (edit_t *)arg;
     2752        char *cname;
     2753        errno_t rc;
     2754
     2755        (void)edit;
     2756        ui_file_dialog_destroy(dialog);
     2757
     2758        cname = str_dup(fname);
     2759        if (cname == NULL) {
     2760                printf("Out of memory.\n");
     2761                return;
     2762        }
     2763
     2764        rc = file_save(fname);
     2765        if (rc != EOK)
     2766                return;
     2767
     2768        if (doc.file_name != NULL)
     2769                free(doc.file_name);
     2770        doc.file_name = cname;
     2771
     2772}
     2773
     2774/** Save As dialog cancel button press.
     2775 *
     2776 * @param dialog File dialog
     2777 * @param arg Argument (ui_demo_t *)
     2778 */
     2779static void save_as_dialog_bcancel(ui_file_dialog_t *dialog, void *arg)
     2780{
     2781        edit_t *edit = (edit_t *)arg;
     2782
     2783        (void)edit;
     2784        ui_file_dialog_destroy(dialog);
     2785}
     2786
     2787/** Save As dialog close request.
     2788 *
     2789 * @param dialog File dialog
     2790 * @param arg Argument (ui_demo_t *)
     2791 */
     2792static void save_as_dialog_close(ui_file_dialog_t *dialog, void *arg)
     2793{
     2794        edit_t *edit = (edit_t *)arg;
     2795
     2796        (void)edit;
     2797        ui_file_dialog_destroy(dialog);
     2798}
     2799
     2800/** Go To Line dialog OK button press.
     2801 *
     2802 * @param dialog Go To Line dialog
     2803 * @param arg Argument (ui_demo_t *)
     2804 * @param text Submitted text
     2805 */
     2806static void go_to_line_dialog_bok(ui_prompt_dialog_t *dialog, void *arg,
     2807    const char *text)
     2808{
     2809        edit_t *edit = (edit_t *) arg;
     2810        char *endptr;
     2811        int line;
     2812
     2813        ui_prompt_dialog_destroy(dialog);
     2814        line = strtol(text, &endptr, 10);
     2815        if (*endptr != '\0') {
     2816                status_display("Invalid number entered.");
     2817                return;
     2818        }
     2819
     2820        caret_move_absolute(line, pane.ideal_column, dir_before, false);
     2821        (void)edit;
     2822        (void) pane_update(&pane);
     2823}
     2824
     2825/** Go To Line dialog cancel button press.
     2826 *
     2827 * @param dialog File dialog
     2828 * @param arg Argument (ui_demo_t *)
     2829 */
     2830static void go_to_line_dialog_bcancel(ui_prompt_dialog_t *dialog, void *arg)
     2831{
     2832        edit_t *edit = (edit_t *) arg;
     2833
     2834        (void)edit;
     2835        ui_prompt_dialog_destroy(dialog);
     2836}
     2837
     2838/** Go To Line dialog close request.
     2839 *
     2840 * @param dialog File dialog
     2841 * @param arg Argument (ui_demo_t *)
     2842 */
     2843static void go_to_line_dialog_close(ui_prompt_dialog_t *dialog, void *arg)
     2844{
     2845        edit_t *edit = (edit_t *) arg;
     2846
     2847        (void)edit;
     2848        ui_prompt_dialog_destroy(dialog);
     2849}
     2850
     2851/** Search dialog OK button press.
     2852 *
     2853 * @param dialog Search dialog
     2854 * @param arg Argument (ui_demo_t *)
     2855 * @param text Submitted text
     2856 */
     2857static void search_dialog_bok(ui_prompt_dialog_t *dialog, void *arg,
     2858    const char *text)
     2859{
     2860        edit_t *edit = (edit_t *) arg;
     2861        char *pattern;
     2862        bool reverse;
     2863
     2864        (void)edit;
     2865        ui_prompt_dialog_destroy(dialog);
     2866
     2867        /* Abort if search phrase is empty */
     2868        if (text[0] == '\0')
     2869                return;
     2870
     2871        pattern = str_dup(text);
     2872        reverse = pane.search_reverse;
     2873
     2874        if (pane.previous_search)
     2875                free(pane.previous_search);
     2876        pane.previous_search = pattern;
     2877        pane.previous_search_reverse = reverse;
     2878
     2879        search(pattern, reverse);
     2880
     2881        (void) pane_update(&pane);
     2882}
     2883
     2884/** Search dialog cancel button press.
     2885 *
     2886 * @param dialog File dialog
     2887 * @param arg Argument (ui_demo_t *)
     2888 */
     2889static void search_dialog_bcancel(ui_prompt_dialog_t *dialog, void *arg)
     2890{
     2891        edit_t *edit = (edit_t *) arg;
     2892
     2893        (void)edit;
     2894        ui_prompt_dialog_destroy(dialog);
     2895}
     2896
     2897/** Search dialog close request.
     2898 *
     2899 * @param dialog File dialog
     2900 * @param arg Argument (ui_demo_t *)
     2901 */
     2902static void search_dialog_close(ui_prompt_dialog_t *dialog, void *arg)
     2903{
     2904        edit_t *edit = (edit_t *) arg;
     2905
     2906        (void)edit;
     2907        ui_prompt_dialog_destroy(dialog);
    17302908}
    17312909
Note: See TracChangeset for help on using the changeset viewer.