コード例 #1
0
struct result
selection_add_item(struct selection *selection,
                   char const *description,
                   selection_action_fn *action)
{
    if (!selection) return result_set_system_error(EINVAL);
    if (!description) return result_set_system_error(EINVAL);
    if (!description[0]) return result_set_system_error(EINVAL);
        
    int index = selection->items_count;
    int null_index = index + 1;
    ++selection->items_count;
    selection->items = reallocarray_or_die(selection->items,
                                           selection->items_count + 1,
                                           sizeof(ITEM *));
    
    char name[] = "1";
    name[0] += index;
    char *name_dup = strdup_or_die(name);
    char *description_dup = strdup_or_die(description);
    selection->items[index] = new_item(name_dup, description_dup);
    if (!selection->items[index]) {
        free_or_die(description_dup);
        free_or_die(name_dup);
        return result_system_error();
    }
    
    struct selection_item *selection_item = calloc_or_die(1, sizeof(struct selection_item));
    selection_item->action = action;
    set_item_userptr(selection->items[index], selection_item);
    
    selection->items[null_index] = NULL;
    
    return result_success();
}
コード例 #2
0
ファイル: app.c プロジェクト: donmccaughey/FiendsAndFortune
struct result
app_add_view(struct app *app, struct view *view)
{
    int index = app->views_count;
    ++app->views_count;
    app->views = reallocarray_or_die(app->views, app->views_count, sizeof(struct view *));
    app->views[index] = view;
    return result_success();
}
コード例 #3
0
ファイル: app.c プロジェクト: donmccaughey/FiendsAndFortune
struct result
app_activate_view(struct app *app, struct view *view)
{
    struct result result = view_enable_keyboard(view);
    if (!result_is_success(result)) return result;
    
    app->active_view = view;
    return result_success();
}
コード例 #4
0
ファイル: app.c プロジェクト: donmccaughey/FiendsAndFortune
struct result
app_ring_bell(struct app *app)
{
    int code = cbreak();
    if (ERR == code) return result_ncurses_err();
    
    code = beep();
    if (ERR == code) return result_ncurses_err();
    
    code = raw();
    if (ERR == code) return result_ncurses_err();
    
    return result_success();
}
コード例 #5
0
static struct result
get_selection(struct selection *selection)
{
    while (true) {
        int ch = wgetch(selection->window);
        if (ERR == ch) return result_ncurses_err();
        
        if (KEY_DOWN == ch) {
            int result = menu_driver(selection->menu, REQ_DOWN_ITEM);
            if (E_OK != result && E_REQUEST_DENIED != result) {
                return result_ncurses_error(result);
            }
        }
        
        if (KEY_UP == ch) {
            int result = menu_driver(selection->menu, REQ_UP_ITEM);
            if (E_OK != result && E_REQUEST_DENIED != result) {
                return result_ncurses_error(result);
            }
        }
        
        if ('\r' == ch) break;
        
        if (!isalnum(ch)) continue;
        
        for (int i = 0; i < selection->items_count; ++i) {
            char const *name = item_name(selection->items[i]);
            if (name && ch == name[0]) {
                set_current_item(selection->menu, selection->items[i]);
                return result_success();
            }
        }
    }
    
    return result_success();
}
コード例 #6
0
static struct result
draw_window(struct selection *selection)
{
    int result = wborder(selection->window, '|', '|', '-', '-', '+', '+', '+', '+');
    if (OK != result) return result_ncurses_err();
        
    // TODO: handle UTF-8 correctly
    size_t title_string_length = strlen(selection->title);
    if (title_string_length > (size_t)INT_MAX) {
        return result_set_system_error(ERANGE);
    }
    
    if (title_string_length) {
        int title_string_width = (int)title_string_length;
        int window_height;
        int window_width;
        getmaxyx(selection->window, window_height, window_width);
        
        char const left_frame[] = "- ";
        char const right_frame[] = " -";
        
        int const left_frame_width = sizeof(left_frame) - 1;
        int const right_frame_width = sizeof(right_frame) - 1;
        
        int const left_border_width = 1;
        int const right_border_width = 1;
        
        int window_top_width = window_width - left_border_width - right_border_width;
        int title_width = left_frame_width + title_string_width + right_frame_width;
        if (window_top_width >= title_width) {
            int start = left_border_width + (window_top_width - title_width) / 2;
            result = mvwprintw(selection->window, 0, start, "%s%s%s",
                               left_frame, selection->title, right_frame);
            if (ERR == result) return result_ncurses_err();
        } else {
            // TODO: elide title
        }
    }
    
    result = wrefresh(selection->window);
    if (ERR == result) return result_ncurses_err();
    
    return result_success();
}
コード例 #7
0
ファイル: app.c プロジェクト: donmccaughey/FiendsAndFortune
struct result
app_run(struct app *app)
{
    sig_t previous_sigwinch_handler = signal(SIGWINCH, terminal_window_did_change);
    if (SIG_ERR == previous_sigwinch_handler) {
        return result_system_error();
    }
    
    struct result result = result_success();
    
    for (int i = 0; i < app->views_count; ++i) {
        result = app->views[i]->create(app->views[i], app);
        if (!result_is_success(result)) break;
    }
    
    if (result_is_success(result)) {
        for (int i = 0; i < app->views_count; ++i) {
            result = app->views[i]->draw(app->views[i], app);
            if (!result_is_success(result)) break;
            wnoutrefresh(app->views[i]->window);
        }
    }
    
    if (!app->active_view) {
        int i = app->views_count - 1;
        result = app_activate_view(app, app->views[i]);
    }
    
    doupdate();
    
    if (result_is_success(result)) {
        result = dispatch_events(app);
    }
    
    for (int i = app->views_count - 1; i >= 0; --i) {
        app->views[i]->destroy(app->views[i], app);
    }
    
    signal(SIGWINCH, previous_sigwinch_handler);
    return result;
}
コード例 #8
0
ファイル: app.c プロジェクト: donmccaughey/FiendsAndFortune
static struct result
dispatch_events(struct app *app)
{
    struct result result = result_success();
    app->is_running = true;
    do {
        int key = view_read_key(app->active_view);
        if (ERR == key) {
            result = result_ncurses_err();
            app_quit(app);
            break;
        }
        
        result = app->active_view->on_key(app->active_view, app, key);
        if (!result_is_success(result)) {
            app_quit(app);
            break;
        }
    } while (app->is_running);
    return result;
}
コード例 #9
0
struct result
selection_show(struct selection *selection, WINDOW *parent)
{
    if (!selection) return result_set_system_error(EINVAL);
    
    selection->menu = new_menu(selection->items);
    if (!selection->menu) return result_ncurses_errno();
    
    int menu_height;
    int menu_width;
    int code = scale_menu(selection->menu, &menu_height, &menu_width);
    if (E_OK != code) return result_ncurses_error(code);
    
    int title_width = (int)strlen(selection->title) + 1;
    if (title_width > menu_width) menu_width = title_width;
    
    int main_window_height;
    int main_window_width;
    getmaxyx(parent, main_window_height, main_window_width);
    
    int menu_window_height = menu_height + 4;
    int menu_window_width = menu_width + 5;
    int menu_window_y = (main_window_height - menu_window_height) / 2;
    int menu_window_x = (main_window_width - menu_window_width) / 2;
    
    selection->window = newwin(menu_window_height, menu_window_width,
                               menu_window_y, menu_window_x);
    if (!selection->window) return result_ncurses_err();
    
    code = keypad(selection->window, TRUE);
    if (ERR == code) return result_ncurses_err();
        
    struct result result = draw_window(selection);
    if (!result_is_success(result)) return result;
    
    code = set_menu_win(selection->menu, selection->window);
    if (E_OK != code) return result_ncurses_error(code);
    
    int menu_sub_height = menu_height;
    int menu_sub_width = menu_width;
    int menu_sub_y = 2;
    int menu_sub_x = 2;
    
    selection->sub_window = derwin(selection->window,
                                   menu_sub_height, menu_sub_width,
                                   menu_sub_y, menu_sub_x);
    if (!selection->sub_window) return result_ncurses_err();
    
    code = set_menu_sub(selection->menu, selection->sub_window);
    if (E_OK != code) return result_ncurses_error(code);
    
    selection->index = 0;
    code = post_menu(selection->menu);
    if (E_OK != code) return result_ncurses_error(code);
    
    code = wrefresh(selection->window);
    if (ERR == code) return result_ncurses_err();
        
    result = get_selection(selection);
    if (!result_is_success(result)) return result;
    
    ITEM *selected_item = current_item(selection->menu);
    if (selected_item) selection->index = item_index(selected_item);
    
    code = unpost_menu(selection->menu);
    if (E_OK != code) return result_ncurses_error(code);
    
    code = wclear(selection->window);
    if (ERR == code) return result_ncurses_err();
        
    code = wrefresh(selection->window);
    if (ERR == code) return result_ncurses_err();
    
    code = free_menu(selection->menu);
    if (E_OK != code) return result_ncurses_error(code);
    selection->menu = NULL;
    
    code = delwin(selection->sub_window);
    if (E_OK != code) return result_ncurses_error(code);
    selection->sub_window = NULL;
        
    code = delwin(selection->window);
    if (E_OK != code) return result_ncurses_error(code);
    selection->window = NULL;
    
    return result_success();
}