Skip to content

Instantly share code, notes, and snippets.

@alan-mushi
Created July 24, 2014 10:22
Show Gist options
  • Save alan-mushi/8df30ee3af1c93348fa4 to your computer and use it in GitHub Desktop.
Save alan-mushi/8df30ee3af1c93348fa4 to your computer and use it in GitHub Desktop.
Simple pop-up using ncurses form and menu library (not CDK) in C. This is a bit more oriented towards easy integration rather than a stand-alone example.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "popup.h"
static WINDOW *win_body;
static WINDOW *win_form;
static WINDOW *win_menu;
static bool is_on_button;
static MENU *popup_menu;
static ITEM **popup_items;
extern FORM *popup_form;
extern FIELD **popup_fields;
extern struct actions **button_actions;
void popup_new(int rows, int cols, int posy, int posx, int nb_buttons,
char **requests, int nb_fields)
{
int i, cury = 0, curx = 1, tmp;
WINDOW *inner;
win_body = newwin(rows, cols, posy, posx);
assert(win_body != NULL);
box(win_body, 0, 0);
popup_items = malloc(sizeof(ITEM *) * (nb_buttons+1));
assert(popup_items);
for (i = 0; i < nb_buttons; i++) {
popup_items[i] = new_item(button_actions[i]->key, "");
assert(popup_items[i] != NULL);
}
popup_items[i] = NULL;
popup_menu = new_menu(popup_items);
win_menu = derwin(win_body, 3, cols-2, rows-4, 1);
assert(popup_menu != NULL && win_menu != NULL);
box(win_menu, 0, 0);
set_menu_win(popup_menu, win_menu);
set_menu_format(popup_menu, 1, nb_buttons);
tmp = popup_menu->fcols * (popup_menu->namelen + popup_menu->spc_rows);
tmp--;
inner = derwin(win_menu, 1, tmp, 1, (cols-3-tmp)/2);
assert(inner != NULL);
set_menu_sub(popup_menu, inner);
set_menu_mark(popup_menu, "");
popup_fields = malloc(sizeof(FIELD *) * (nb_fields+1));
assert(popup_fields);
for (i = 0; i < nb_fields; i++) {
popup_fields[i] = new_field(1, 10, cury, curx, 0, 0);
assert(popup_fields[i] != NULL);
set_field_buffer(popup_fields[i], 0, requests[i]);
if (i % 2 == 1) {
cury = cury+1;
curx = 1;
field_opts_on(popup_fields[i], O_ACTIVE);
field_opts_on(popup_fields[i], O_EDIT);
set_field_back(popup_fields[i], A_UNDERLINE);
} else {
curx = 20;
field_opts_off(popup_fields[i], O_ACTIVE);
field_opts_off(popup_fields[i], O_EDIT);
}
}
popup_fields[i] = NULL;
popup_form = new_form(popup_fields);
assert(popup_form != NULL);
win_form = derwin(win_body, rows-5, cols-2, 1, 1);
box(win_form, 0, 0);
assert(popup_form != NULL && win_form != NULL);
set_form_win(popup_form, win_form);
inner = derwin(win_form, popup_form->rows+1, popup_form->cols+1, 1, 1);
assert(inner != NULL);
set_form_sub(popup_form, inner);
assert(post_form(popup_form) == E_OK);
assert(post_menu(popup_menu) == E_OK);
is_on_button = true;
pos_menu_cursor(popup_menu);
}
void popup_delete(void)
{
int i;
unpost_form(popup_form);
unpost_menu(popup_menu);
for (i = 0; popup_fields[i] != NULL; i++) {
free_field(popup_fields[i]);
}
for (i = 0; popup_items[i] != NULL; i++) {
free_item(popup_items[i]);
}
free_menu(popup_menu);
free_form(popup_form);
delwin(win_form);
delwin(win_menu);
delwin(win_body);
win_body = NULL;
button_actions = NULL;
}
static void driver_buttons(ITEM *item)
{
const char *name = item_name(item);
int i = 0;
while (button_actions[i] && strcmp(button_actions[i]->key, name) != 0)
i++;
if (button_actions[i])
button_actions[i]->func();
}
static void switch_to_buttons(void)
{
// Those 2 lines allow the field buffer to be set
form_driver(popup_form, REQ_PREV_FIELD);
form_driver(popup_form, REQ_NEXT_FIELD);
menu_driver(popup_menu, REQ_FIRST_ITEM);
is_on_button = true;
set_menu_fore(popup_menu, A_REVERSE); // "show" the button
}
void popup_driver(int ch)
{
switch (ch) {
case KEY_DOWN:
if (is_on_button)
break;
if (popup_form->current == popup_fields[popup_form->maxfield-1])
switch_to_buttons();
else
form_driver(popup_form, REQ_NEXT_FIELD);
break;
case KEY_UP:
if (is_on_button) {
is_on_button = false;
set_menu_fore(popup_menu, A_NORMAL); // "hide" the button
} else
form_driver(popup_form, REQ_PREV_FIELD);
break;
case KEY_LEFT:
if (is_on_button)
menu_driver(popup_menu, REQ_LEFT_ITEM);
else
form_driver(popup_form, REQ_LEFT_FIELD);
break;
case KEY_RIGHT:
if (is_on_button)
menu_driver(popup_menu, REQ_RIGHT_ITEM);
else
form_driver(popup_form, REQ_RIGHT_FIELD);
break;
case 10:
if (!is_on_button)
switch_to_buttons();
else
driver_buttons(current_item(popup_menu));
break;
default:
if (!is_on_button)
form_driver(popup_form, ch);
break;
}
if (is_on_button)
pos_menu_cursor(popup_menu);
else
pos_form_cursor(popup_form);
wrefresh(win_body);
}
void popup_refresh(void)
{
wrefresh(win_body);
}
bool popup_exists(void)
{
return (win_body != NULL);
}
#ifndef __CONNMAN_POPUP_H
#define __CONNMAN_POPUP_H
#include <ncurses/form.h>
#include <ncurses/menu.h>
#ifdef __cplusplus
extern "C" {
#endif
struct actions {
char *key; // Button name
void (*func)(); // Execute on 'return'
};
void popup_new(int rows, int cols, int posy, int posx, int nb_buttons,
char **requests, int nb_fields);
void popup_delete(void);
void popup_refresh(void);
bool popup_exists(void);
void popup_driver(int ch);
#ifdef __cplusplus
}
#endif
#endif
/*
* clang -o test using_popup.c popup.c -ltinfo -lform -lmenu -lncurses -Wall -Werror -g
*/
#include <stdlib.h>
#include "popup.h"
FORM *popup_form;
FIELD **popup_fields;
struct actions **button_actions;
void action_btn_ok(void)
{
int i;
mvprintw(LINES-2, 1, "[*] OK: ");
for (i = 0; i < popup_form->maxfield; i++) {
printw("%s", field_buffer(popup_fields[i], 0));
if (field_opts(popup_fields[i]) & O_ACTIVE)
printw("\t");
}
refresh();
}
void action_btn_quit(void)
{
mvprintw(LINES-2, 1, "[*] QUIT: F1 to quit");
refresh();
}
int main()
{
char *requests[] = { "Password:", "pass", "Id:", "id" };
int ch;
struct actions act_ok, act_quit;
act_ok.key = "OK";
act_ok.func = action_btn_ok;
act_quit.key = "QUIT";
act_quit.func = action_btn_quit;
button_actions = malloc(sizeof(struct action *) * 3);
button_actions[0] = &act_ok;
button_actions[1] = &act_quit;
button_actions[2] = NULL;
initscr();
noecho();
cbreak();
keypad(stdscr, TRUE);
popup_new(24, 80, (LINES-25)/2, (COLS-81)/2, 2, requests, 4);
refresh();
popup_refresh();
while((ch = getch()) != KEY_F(1))
popup_driver(ch);
popup_delete();
endwin();
free(button_actions[0]);
free(button_actions[1]);
free(button_actions);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment