// move word left static void textbox_cursor_dec_word ( textbox *tb ) { // Find word boundaries, with pango_Break? gchar *n; gchar *c = &( tb->text[tb->cursor] ); while ( ( c = g_utf8_prev_char ( c ) ) && c != tb->text ) { gunichar uc = g_utf8_get_char ( c ); GUnicodeBreakType bt = g_unichar_break_type ( uc ); if ( ( bt == G_UNICODE_BREAK_ALPHABETIC || bt == G_UNICODE_BREAK_HEBREW_LETTER || bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION ) ) { break; } } if ( c != tb->text ) { while ( ( n = g_utf8_prev_char ( c ) ) ) { gunichar uc = g_utf8_get_char ( n ); GUnicodeBreakType bt = g_unichar_break_type ( uc ); if ( !( bt == G_UNICODE_BREAK_ALPHABETIC || bt == G_UNICODE_BREAK_HEBREW_LETTER || bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION ) ) { break; } c = n; if ( n == tb->text ) { break; } } } int index = c - tb->text; textbox_cursor ( tb, index ); }
// Move word right static void textbox_cursor_inc_word ( textbox *tb ) { if ( tb->text == NULL ) { return; } // Find word boundaries, with pango_Break? gchar *c = &( tb->text[tb->cursor] ); while ( ( c = g_utf8_next_char ( c ) ) ) { gunichar uc = g_utf8_get_char ( c ); GUnicodeBreakType bt = g_unichar_break_type ( uc ); if ( ( bt == G_UNICODE_BREAK_ALPHABETIC || bt == G_UNICODE_BREAK_HEBREW_LETTER || bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION ) ) { break; } } if ( c == NULL ) { return; } while ( ( c = g_utf8_next_char ( c ) ) ) { gunichar uc = g_utf8_get_char ( c ); GUnicodeBreakType bt = g_unichar_break_type ( uc ); if ( !( bt == G_UNICODE_BREAK_ALPHABETIC || bt == G_UNICODE_BREAK_HEBREW_LETTER || bt == G_UNICODE_BREAK_NUMERIC || bt == G_UNICODE_BREAK_QUOTATION ) ) { break; } } int index = c - tb->text; textbox_cursor ( tb, index ); }
gboolean textbox_append_char ( textbox *tb, const char *pad, const int pad_len ) { if ( !( tb->flags & TB_EDITABLE ) ) { return FALSE; } // Filter When alt/ctrl is pressed do not accept the character. if ( !g_unichar_iscntrl ( g_utf8_get_char ( pad ) ) ) { textbox_insert ( tb, tb->cursor, pad, pad_len ); textbox_cursor ( tb, tb->cursor + 1 ); return TRUE; } return FALSE; }
// move left void textbox_cursor_dec(textbox *tb) { textbox_cursor(tb, tb->cursor-1); }
// move right void textbox_cursor_inc(textbox *tb) { textbox_cursor(tb, tb->cursor+1); }
// handle a keypress in edit mode // 2 = nav // 0 = unhandled // 1 = handled // -1 = handled and return pressed (finished) int textbox_keypress ( textbox *tb, XIC xic, XEvent *ev ) { KeySym key; Status stat; char pad[32]; int len; if ( !( tb->flags & TB_EDITABLE ) ) { return 0; } len = Xutf8LookupString ( xic, &ev->xkey, pad, sizeof ( pad ), &key, &stat ); pad[len] = 0; // Left or Ctrl-b if ( abe_test_action ( MOVE_CHAR_BACK, ev->xkey.state, key ) ) { textbox_cursor_dec ( tb ); return 2; } // Right or Ctrl-F else if ( abe_test_action ( MOVE_CHAR_FORWARD, ev->xkey.state, key ) ) { textbox_cursor_inc ( tb ); return 2; } // Ctrl-U: Kill from the beginning to the end of the line. else if ( abe_test_action ( CLEAR_LINE, ev->xkey.state, key ) ) { textbox_text ( tb, "" ); return 1; } // Ctrl-A else if ( abe_test_action ( MOVE_FRONT, ev->xkey.state, key ) ) { textbox_cursor ( tb, 0 ); return 2; } // Ctrl-E else if ( abe_test_action ( MOVE_END, ev->xkey.state, key ) ) { textbox_cursor_end ( tb ); return 2; } // Ctrl-Alt-h else if ( abe_test_action ( REMOVE_WORD_BACK, ev->xkey.state, key ) ) { textbox_cursor_bkspc_word ( tb ); return 1; } // Ctrl-Alt-d else if ( abe_test_action ( REMOVE_WORD_FORWARD, ev->xkey.state, key ) ) { textbox_cursor_del_word ( tb ); return 1; } // Delete or Ctrl-D else if ( abe_test_action ( REMOVE_CHAR_FORWARD, ev->xkey.state, key ) ) { textbox_cursor_del ( tb ); return 1; } // Alt-B else if ( abe_test_action ( MOVE_WORD_BACK, ev->xkey.state, key ) ) { textbox_cursor_dec_word ( tb ); return 2; } // Alt-F else if ( abe_test_action ( MOVE_WORD_FORWARD, ev->xkey.state, key ) ) { textbox_cursor_inc_word ( tb ); return 2; } // BackSpace, Ctrl-h else if ( abe_test_action ( REMOVE_CHAR_BACK, ev->xkey.state, key ) ) { textbox_cursor_bkspc ( tb ); return 1; } else if ( abe_test_action ( ACCEPT_CUSTOM, ev->xkey.state, key ) ) { return -2; } else if ( abe_test_action ( ACCEPT_ENTRY_CONTINUE, ev->xkey.state, key ) ) { return -3; } else if ( abe_test_action ( ACCEPT_ENTRY, ev->xkey.state, key ) ) { return -1; } else if ( !iscntrl ( *pad ) ) { textbox_insert ( tb, tb->cursor, pad ); textbox_cursor_inc ( tb ); return 1; } return 0; }
// move left void textbox_cursor_dec ( textbox *tb ) { int index = g_utf8_prev_char ( &( tb->text[tb->cursor] ) ) - tb->text; textbox_cursor ( tb, index ); }
// move right void textbox_cursor_inc ( textbox *tb ) { int index = g_utf8_next_char ( &( tb->text[tb->cursor] ) ) - tb->text; textbox_cursor ( tb, index ); }
// handle a keypress in edit mode // 2 = nav // 0 = unhandled // 1 = handled // -1 = handled and return pressed (finished) int textbox_keybinding ( textbox *tb, KeyBindingAction action ) { if ( !( tb->flags & TB_EDITABLE ) ) { return 0; } switch ( action ) { // Left or Ctrl-b case MOVE_CHAR_BACK: textbox_cursor_dec ( tb ); return 2; // Right or Ctrl-F case MOVE_CHAR_FORWARD: textbox_cursor_inc ( tb ); return 2; // Ctrl-U: Kill from the beginning to the end of the line. case CLEAR_LINE: textbox_text ( tb, "" ); return 1; // Ctrl-A case MOVE_FRONT: textbox_cursor ( tb, 0 ); return 2; // Ctrl-E case MOVE_END: textbox_cursor_end ( tb ); return 2; // Ctrl-Alt-h case REMOVE_WORD_BACK: textbox_cursor_bkspc_word ( tb ); return 1; // Ctrl-Alt-d case REMOVE_WORD_FORWARD: textbox_cursor_del_word ( tb ); return 1; case REMOVE_TO_EOL: textbox_cursor_del_eol ( tb ); return 1; case REMOVE_TO_SOL: textbox_cursor_del_sol ( tb ); return 1; // Delete or Ctrl-D case REMOVE_CHAR_FORWARD: textbox_cursor_del ( tb ); return 1; // Alt-B case MOVE_WORD_BACK: textbox_cursor_dec_word ( tb ); return 2; // Alt-F case MOVE_WORD_FORWARD: textbox_cursor_inc_word ( tb ); return 2; // BackSpace, Ctrl-h case REMOVE_CHAR_BACK: textbox_cursor_bkspc ( tb ); return 1; default: g_return_val_if_reached ( 0 ); } }
// handle a keypress in edit mode // 2 = nav // 0 = unhandled // 1 = handled // -1 = handled and return pressed (finished) int textbox_keypress ( textbox *tb, XEvent *ev, char *pad, KeySym key, Status stat ) { if ( !( tb->flags & TB_EDITABLE ) ) { return 0; } if ( stat == XLookupKeySym || stat == XLookupBoth ) { // Left or Ctrl-b if ( abe_test_action ( MOVE_CHAR_BACK, ev->xkey.state, key ) ) { textbox_cursor_dec ( tb ); return 2; } // Right or Ctrl-F else if ( abe_test_action ( MOVE_CHAR_FORWARD, ev->xkey.state, key ) ) { textbox_cursor_inc ( tb ); return 2; } // Ctrl-U: Kill from the beginning to the end of the line. else if ( abe_test_action ( CLEAR_LINE, ev->xkey.state, key ) ) { textbox_text ( tb, "" ); return 1; } // Ctrl-A else if ( abe_test_action ( MOVE_FRONT, ev->xkey.state, key ) ) { textbox_cursor ( tb, 0 ); return 2; } // Ctrl-E else if ( abe_test_action ( MOVE_END, ev->xkey.state, key ) ) { textbox_cursor_end ( tb ); return 2; } // Ctrl-Alt-h else if ( abe_test_action ( REMOVE_WORD_BACK, ev->xkey.state, key ) ) { textbox_cursor_bkspc_word ( tb ); return 1; } // Ctrl-Alt-d else if ( abe_test_action ( REMOVE_WORD_FORWARD, ev->xkey.state, key ) ) { textbox_cursor_del_word ( tb ); return 1; } // Delete or Ctrl-D else if ( abe_test_action ( REMOVE_CHAR_FORWARD, ev->xkey.state, key ) ) { textbox_cursor_del ( tb ); return 1; } // Alt-B else if ( abe_test_action ( MOVE_WORD_BACK, ev->xkey.state, key ) ) { textbox_cursor_dec_word ( tb ); return 2; } // Alt-F else if ( abe_test_action ( MOVE_WORD_FORWARD, ev->xkey.state, key ) ) { textbox_cursor_inc_word ( tb ); return 2; } // BackSpace, Ctrl-h else if ( abe_test_action ( REMOVE_CHAR_BACK, ev->xkey.state, key ) ) { textbox_cursor_bkspc ( tb ); return 1; } else if ( abe_test_action ( ACCEPT_CUSTOM, ev->xkey.state, key ) ) { return -2; } else if ( abe_test_action ( ACCEPT_ENTRY_CONTINUE, ev->xkey.state, key ) ) { return -3; } else if ( abe_test_action ( ACCEPT_ENTRY, ev->xkey.state, key ) ) { return -1; } } if ( *pad != 0 && ( stat == XLookupBoth || stat == XLookupChars ) ) { // Filter When alt/ctrl is pressed do not accept the character. if ( !g_ascii_iscntrl ( *pad ) ) { textbox_insert ( tb, tb->cursor, pad ); textbox_cursor_inc ( tb ); return 1; } } return 0; }
int main ( int argc, char **argv ) { // Get DISPLAY const char *display_str = getenv ( "DISPLAY" ); if ( !( display = XOpenDisplay ( display_str ) ) ) { fprintf ( stderr, "cannot open display!\n" ); return EXIT_FAILURE; } TASSERT( display != NULL ); Screen *screen = DefaultScreenOfDisplay ( display ); Window root = RootWindow ( display, XScreenNumberOfScreen ( screen ) ); Window mw = XCreateSimpleWindow ( display, root, 0, 0, 200, 100, config.menu_bw, color_get ( display, config.menu_bc ), color_get ( display, config.menu_bg ) ); TASSERT( mw != None ); textbox_setup ( config.menu_bg, config.menu_fg, config.menu_hlbg, config.menu_hlfg ); textbox *box = textbox_create(mw , TB_EDITABLE|TB_AUTOWIDTH|TB_AUTOHEIGHT, 0,0, -1, -1, NORMAL, "test"); TASSERT( box != NULL ); textbox_cursor_end ( box ); TASSERT ( box->cursor == 4); textbox_cursor ( box, -1 ); TASSERT ( box->cursor == 0 ); textbox_cursor ( box, 8 ); TASSERT ( box->cursor == 4 ); textbox_cursor ( box, 2 ); TASSERT ( box->cursor == 2 ); textbox_insert ( box, 3, "bo"); TASSERT ( strcmp(box->text, "tesbot") == 0 ); textbox_cursor_end ( box ); TASSERT ( box->cursor == 6); TASSERT( textbox_get_width( box) > 0 ); TASSERT( textbox_get_height( box) > 0 ); TASSERT( textbox_get_width( box) >= textbox_get_font_width( box) ); TASSERT( textbox_get_height( box) >= textbox_get_font_height( box) ); TASSERT( textbox_get_estimated_char_width ( box) > 0 ); textbox_cursor_bkspc ( box ); TASSERT ( strcmp(box->text, "tesbo") == 0 ); TASSERT ( box->cursor == 5); textbox_cursor_dec ( box ); TASSERT ( box->cursor == 4); textbox_cursor_del ( box ); TASSERT ( strcmp(box->text, "tesb") == 0 ); textbox_cursor_dec ( box ); TASSERT ( box->cursor == 3); textbox_cursor_inc ( box ); TASSERT ( box->cursor == 4); textbox_cursor_inc ( box ); TASSERT ( box->cursor == 4); // Cursor after delete section. textbox_delete ( box, 0, 1 ); TASSERT ( strcmp(box->text, "esb") == 0 ); TASSERT ( box->cursor == 3); // Cursor before delete. textbox_text( box, "aap noot mies"); TASSERT ( strcmp(box->text, "aap noot mies") == 0 ); textbox_cursor( box, 3 ); TASSERT ( box->cursor == 3); textbox_delete ( box, 3, 6 ); TASSERT ( strcmp(box->text, "aapmies") == 0 ); TASSERT ( box->cursor == 3); // Cursor within delete textbox_text( box, "aap noot mies"); TASSERT ( strcmp(box->text, "aap noot mies") == 0 ); textbox_cursor( box, 5 ); TASSERT ( box->cursor == 5); textbox_delete ( box, 3, 6 ); TASSERT ( strcmp(box->text, "aapmies") == 0 ); TASSERT ( box->cursor == 3); // Cursor after delete. textbox_text( box, "aap noot mies"); TASSERT ( strcmp(box->text, "aap noot mies") == 0 ); textbox_cursor( box, 11 ); TASSERT ( box->cursor == 11); textbox_delete ( box, 3, 6 ); TASSERT ( strcmp(box->text, "aapmies") == 0 ); TASSERT ( box->cursor == 5); textbox_font ( box, HIGHLIGHT ); textbox_draw( box ); textbox_show( box ); textbox_move ( box, 12, 13); TASSERT ( box->x == 12 ); TASSERT ( box->y == 13 ); textbox_hide( box ); textbox_free(box); textbox_cleanup(); XDestroyWindow ( display, mw); XCloseDisplay ( display ); }