diff --git a/demo/guihello/form.c b/demo/guihello/form.c index 5e838e10..e73c3fcc 100644 --- a/demo/guihello/form.c +++ b/demo/guihello/form.c @@ -1,6 +1,7 @@ /* Form demo */ #include "form.h" +#include "res_guihello.h" #include /*---------------------------------------------------------------------------*/ @@ -14,8 +15,8 @@ struct _form_data_t Button *validate_check; }; -#define BUTTON_YES 1000 -#define BUTTON_NO 1001 +#define BUTTON_YES 1000 +#define BUTTON_NO 1001 /*---------------------------------------------------------------------------*/ @@ -70,7 +71,7 @@ static Window *i_modal_window(FormData *data, Edit *edit, const GuiControl *next Button *button2 = button_push(); Panel *panel = panel_create(); Window *window = window_create(ekWINDOW_STD | ekWINDOW_ESC); - String *str = str_printf("Do you want to validate the text '%s' of the EditBox '%p'? The focus will be moved to the '%p' control using the '%s' action.", field_text, (void*)edit, (void*)next, action_text); + String *str = str_printf("Do you want to validate the text '%s' of the EditBox '%p'? The focus will be moved to the '%p' control using the '%s' action.", field_text, (void *)edit, (void *)next, action_text); label_text(label, tc(str)); button_text(button1, "Yes"); button_text(button2, "No"); @@ -148,7 +149,7 @@ static bool_t i_validate_field(FormData *data, Edit *edit, const char_t *text) window_origin(data->modal_window, pos); modal_value = window_modal(data->modal_window, data->window); window_destroy(&data->modal_window); - switch(modal_value) + switch (modal_value) { case ekGUI_CLOSE_BUTTON: case ekGUI_CLOSE_ESC: @@ -156,7 +157,7 @@ static bool_t i_validate_field(FormData *data, Edit *edit, const char_t *text) return FALSE; case BUTTON_YES: return TRUE; - cassert_default(); + cassert_default(); } return TRUE; @@ -201,6 +202,7 @@ static Layout *i_numbers(FormData *data, color_t colorbg) label_text(label, "Height (cm):"); edit_text(edit1, "25"); edit_text(edit2, "175"); + edit_autoselect(edit1, TRUE); edit_align(edit1, ekRIGHT); edit_align(edit2, ekRIGHT); edit_OnFilter(edit1, listener(NULL, i_OnFilter, void)); @@ -262,6 +264,7 @@ static Layout *i_edits(FormData *data) edit_OnChange(edit3, listener(data, i_OnEditChange, FormData)); edit_OnChange(edit4, listener(data, i_OnEditChange, FormData)); edit_OnChange(edit5, listener(data, i_OnEditChange, FormData)); + edit_select(edit1, 2, 6); edit_passmode(edit2, TRUE); edit_bgcolor_focus(edit1, colorbg); edit_bgcolor_focus(edit2, colorbg); @@ -292,27 +295,93 @@ static Layout *i_edits(FormData *data) /*---------------------------------------------------------------------------*/ +static void i_OnCopy(FormData *data, Event *e) +{ + GuiControl *control = window_get_focus(data->window); + Edit *edit = guicontrol_edit(control); + unref(e); + if (edit != NULL) + edit_copy(edit); +} + +/*---------------------------------------------------------------------------*/ + +static void i_OnPaste(FormData *data, Event *e) +{ + GuiControl *control = window_get_focus(data->window); + Edit *edit = guicontrol_edit(control); + unref(e); + if (edit != NULL) + edit_paste(edit); +} + +/*---------------------------------------------------------------------------*/ + +static void i_OnCut(FormData *data, Event *e) +{ + GuiControl *control = window_get_focus(data->window); + Edit *edit = guicontrol_edit(control); + unref(e); + if (edit != NULL) + edit_cut(edit); +} + +/*---------------------------------------------------------------------------*/ + +static Layout *i_toolbar(FormData *data) +{ + Layout *layout = layout_create(4, 1); + Button *check = button_check(); + Button *button1 = button_flat(); + Button *button2 = button_flat(); + Button *button3 = button_flat(); + button_text(check, "Field validations"); + button_image(button1, gui_image(COPY_PNG)); + button_image(button2, gui_image(PASTE_PNG)); + button_image(button3, gui_image(CUT_PNG)); + button_OnClick(button1, listener(data, i_OnCopy, FormData)); + button_OnClick(button2, listener(data, i_OnPaste, FormData)); + button_OnClick(button3, listener(data, i_OnCut, FormData)); + button_tooltip(button1, "Copy"); + button_tooltip(button2, "Paste"); + button_tooltip(button3, "Cut"); + layout_button(layout, check, 0, 0); + layout_button(layout, button1, 1, 0); + layout_button(layout, button2, 2, 0); + layout_button(layout, button3, 3, 0); + layout_tabstop(layout, 0, 0, FALSE); + layout_tabstop(layout, 1, 0, FALSE); + layout_tabstop(layout, 2, 0, FALSE); + layout_tabstop(layout, 3, 0, FALSE); + layout_hmargin(layout, 0, 5); + layout_hmargin(layout, 1, 5); + layout_hmargin(layout, 2, 5); + data->validate_check = check; + return layout; +} + +/*---------------------------------------------------------------------------*/ + static Layout *i_form(FormData *data) { Layout *layout1 = layout_create(1, 3); Layout *layout2 = i_edits(data); - Button *check = button_check(); + Layout *layout3 = i_toolbar(data); Label *label = label_multiline(); cassert_no_null(data); - button_text(check, "Field validations"); label_text(label, "Please fill in all the information on the form. We will use this data to send commercial mail at all hours, not caring much if it bothers you or not."); label_color(label, gui_alt_color(color_rgb(255, 0, 0), color_rgb(180, 180, 180))); label_bgcolor(label, gui_alt_color(color_rgb(216, 191, 216), color_rgb(80, 40, 40))); label_bgcolor_over(label, gui_alt_color(color_rgb(255, 250, 205), color_rgb(105, 100, 55))); label_style_over(label, ekFUNDERLINE); layout_layout(layout1, layout2, 0, 0); - layout_button(layout1, check, 0, 1); + layout_layout(layout1, layout3, 0, 1); layout_label(layout1, label, 0, 2); layout_hsize(layout1, 0, 300); + layout_halign(layout1, 0, 1, ekLEFT); layout_vmargin(layout1, 0, 10); layout_vmargin(layout1, 1, 10); layout_margin(layout1, 10); - data->validate_check = check; return layout1; } @@ -336,4 +405,3 @@ Panel *form_basic(Window *window) panel_layout(panel, layout); return panel; } - diff --git a/demo/guihello/popcom.c b/demo/guihello/popcom.c index 0d858806..e0aa7dc7 100644 --- a/demo/guihello/popcom.c +++ b/demo/guihello/popcom.c @@ -14,19 +14,19 @@ static void i_popups(Layout *layout) PopUp *popup2 = popup_create(); label_text(label1, "Language:"); label_text(label2, "Color:"); - popup_add_elem(popup1, "English", (const Image*)UKING_PNG); - popup_add_elem(popup1, "Español", (const Image*)SPAIN_PNG); - popup_add_elem(popup1, "Portugues", (const Image*)PORTUGAL_PNG); - popup_add_elem(popup1, "Italiana", (const Image*)ITALY_PNG); - popup_add_elem(popup1, "Tiếng Việt", (const Image*)VIETNAM_PNG); - popup_add_elem(popup1, "России", (const Image*)RUSSIA_PNG); - popup_add_elem(popup1, "日本語", (const Image*)JAPAN_PNG); - popup_add_elem(popup2, "Red", (const Image*)RED_PNG); - popup_add_elem(popup2, "Blue", (const Image*)BLUE_PNG); - popup_add_elem(popup2, "Green", (const Image*)GREEN_PNG); - popup_add_elem(popup2, "Yellow", (const Image*)YELLOW_PNG); - popup_add_elem(popup2, "Black", (const Image*)BLACK_PNG); - popup_add_elem(popup2, "White", (const Image*)WHITE_PNG); + popup_add_elem(popup1, "English", gui_image(UKING_PNG)); + popup_add_elem(popup1, "Español", gui_image(SPAIN_PNG)); + popup_add_elem(popup1, "Portugues", gui_image(PORTUGAL_PNG)); + popup_add_elem(popup1, "Italiana", gui_image(ITALY_PNG)); + popup_add_elem(popup1, "Tiếng Việt", gui_image(VIETNAM_PNG)); + popup_add_elem(popup1, "России", gui_image(RUSSIA_PNG)); + popup_add_elem(popup1, "日本語", gui_image(JAPAN_PNG)); + popup_add_elem(popup2, "Red", gui_image(RED_PNG)); + popup_add_elem(popup2, "Blue", gui_image(BLUE_PNG)); + popup_add_elem(popup2, "Green", gui_image(GREEN_PNG)); + popup_add_elem(popup2, "Yellow", gui_image(YELLOW_PNG)); + popup_add_elem(popup2, "Black", gui_image(BLACK_PNG)); + popup_add_elem(popup2, "White", gui_image(WHITE_PNG)); popup_list_height(popup1, 10); popup_list_height(popup2, 10); layout_label(layout, label1, 0, 0); diff --git a/demo/guihello/res/res_guihello/copy.png b/demo/guihello/res/res_guihello/copy.png new file mode 100644 index 00000000..0ae91fc5 Binary files /dev/null and b/demo/guihello/res/res_guihello/copy.png differ diff --git a/demo/guihello/res/res_guihello/cut.png b/demo/guihello/res/res_guihello/cut.png new file mode 100644 index 00000000..6b1a43db Binary files /dev/null and b/demo/guihello/res/res_guihello/cut.png differ diff --git a/demo/guihello/res/res_guihello/paste.png b/demo/guihello/res/res_guihello/paste.png new file mode 100644 index 00000000..24153bcf Binary files /dev/null and b/demo/guihello/res/res_guihello/paste.png differ diff --git a/prj/build.txt b/prj/build.txt index 74f1bc45..67891419 100644 --- a/prj/build.txt +++ b/prj/build.txt @@ -1 +1 @@ -5194 +5201 diff --git a/src/gui/listbox.c b/src/gui/listbox.c index c221573b..36892477 100644 --- a/src/gui/listbox.c +++ b/src/gui/listbox.c @@ -141,7 +141,9 @@ static void i_OnDraw(ListBox *listbox, Event *e) uint32_t i; fill_width -= scrollview_scrollbar_width(data->sview); - fill_width -= i_RIGHT_PADDING; +#if defined(__WINDOWS__) + fill_width -= 2; +#endif draw_font(p->ctx, data->font); for (i = strow; i < edrow; ++i) diff --git a/src/gui/scrollview.c b/src/gui/scrollview.c index 8b47bce4..a2e843df 100644 --- a/src/gui/scrollview.c +++ b/src/gui/scrollview.c @@ -139,6 +139,8 @@ void scrollview_content_size(ScrollView *view, const uint32_t content_width, con view_scroll_size(view->view, &bar_width, &bar_height); view->scrollbar_width = (uint32_t)bar_width; view->scrollbar_height = (uint32_t)bar_height; + twidth += view->scrollbar_width; + theight += view->scrollbar_height; if (twidth < view->control_width) twidth = view->control_width; @@ -148,8 +150,6 @@ void scrollview_content_size(ScrollView *view, const uint32_t content_width, con view->content_width = twidth; view->content_height = theight; - twidth += view->scrollbar_width; - theight += view->scrollbar_height; if (twidth != content_width || theight != content_height) view_content_size(view->view, s2df((real32_t)twidth, (real32_t)theight), s2df((real32_t)line_width, (real32_t)line_height)); diff --git a/src/osgui/gtk/oscontrol.c b/src/osgui/gtk/oscontrol.c index 9d19d9a7..0865384a 100644 --- a/src/osgui/gtk/oscontrol.c +++ b/src/osgui/gtk/oscontrol.c @@ -646,6 +646,14 @@ void oscontrol_frame(const OSControl *control, OSFrame *rect) /*---------------------------------------------------------------------------*/ +void oscontrol_set_can_focus(OSControl *control, const bool_t can_focus) +{ + OSWidget *widget = oscontrol_focus_widget(control); + gtk_widget_set_can_focus(cast(widget, GtkWidget), can_focus); +} + +/*---------------------------------------------------------------------------*/ + OSWidget *oscontrol_focus_widget(const OSControl *control) { cassert_no_null(control); diff --git a/src/osgui/oscontrol.inl b/src/osgui/oscontrol.inl index ddcba8fc..c9f17e86 100644 --- a/src/osgui/oscontrol.inl +++ b/src/osgui/oscontrol.inl @@ -22,6 +22,8 @@ OSControl *oscontrol_parent(const OSControl *control); void oscontrol_frame(const OSControl *control, OSFrame *rect); +void oscontrol_set_can_focus(OSControl *control, const bool_t can_focus); + OSWidget *oscontrol_focus_widget(const OSControl *control); bool_t oscontrol_widget_visible(const OSWidget *widget); diff --git a/src/osgui/ostabstop.c b/src/osgui/ostabstop.c index 29be8820..98344557 100644 --- a/src/osgui/ostabstop.c +++ b/src/osgui/ostabstop.c @@ -196,9 +196,11 @@ static void i_set_focus(OSTabStop *tabstop, OSControl *control) cassert_no_null(tabstop); cassert(arrpt_find(tabstop->controls, control, OSControl) != UINT32_MAX); + if (tabstop->transient != NULL) + ostabstop_release_transient(tabstop, tabstop->transient); + oswindow_widget_set_focus(tabstop->window, widget); tabstop->current = control; - cassert(tabstop->transient == NULL); /* We remember the last tablist focused control */ tabindex = arrpt_find(tabstop->tablist, control, OSControl); @@ -302,6 +304,24 @@ static void i_on_focus(OSControl *control, const bool_t focused) /*---------------------------------------------------------------------------*/ +static bool_t i_is_next_transient(const OSTabStop *tabstop, OSControl *focus, OSControl *next) +{ + if (next != NULL && focus != next) + { + /* If button is not in the tablist, can't get the focus */ + gui_type_t type = oscontrol_type(next); + if (type == ekGUI_TYPE_BUTTON && ostabstop_in_tablist(tabstop, next) == FALSE) + { + oscontrol_set_can_focus(next, FALSE); + return TRUE; + } + } + + return FALSE; +} + +/*---------------------------------------------------------------------------*/ + static gui_focus_t i_try_change_focus(OSTabStop *tabstop, OSControl *control, const gui_tab_t motion, const bool_t forward) { gui_focus_t fstate = ENUM_MAX(gui_focus_t); @@ -318,11 +338,14 @@ static gui_focus_t i_try_change_focus(OSTabStop *tabstop, OSControl *control, co next_control = i_effective_focus(tabstop, control, forward); tabstop->next = next_control; + if (i_is_next_transient(tabstop, focus, next_control) == TRUE) + resign = FALSE; + /* * 'focus' and 'next_control' can be the same but, * we force validation events in non-cycle-one-control tablists */ - if (focus != NULL) + if (resign == TRUE && focus != NULL) resign = ostabstop_resign_focus(tabstop, focus); /* The current focused control resign the focus */ @@ -568,6 +591,7 @@ void ostabstop_release_transient(OSTabStop *tabstop, OSControl *control) if (tabstop->transient != NULL) { cassert_unref(tabstop->transient == control, control); + oscontrol_set_can_focus(tabstop->transient, TRUE); tabstop->transient = NULL; if (tabstop->current != NULL) { diff --git a/src/osgui/osx/oscontrol.m b/src/osgui/osx/oscontrol.m index af57083f..90658c7a 100644 --- a/src/osgui/osx/oscontrol.m +++ b/src/osgui/osx/oscontrol.m @@ -655,6 +655,14 @@ void oscontrol_frame(const OSControl *control, OSFrame *rect) /*---------------------------------------------------------------------------*/ +void oscontrol_set_can_focus(OSControl *control, const bool_t can_focus) +{ + unref(control); + unref(can_focus); +} + +/*---------------------------------------------------------------------------*/ + OSWidget *oscontrol_focus_widget(const OSControl *control) { cassert_no_null(control); diff --git a/src/osgui/osx/osedit.m b/src/osgui/osx/osedit.m index d732189f..19294561 100644 --- a/src/osgui/osx/osedit.m +++ b/src/osgui/osx/osedit.m @@ -74,6 +74,7 @@ @interface OSXEdit : NSView uint32_t flags; uint32_t vpadding; real32_t rpadding; + NSRange select; CGFloat wpadding; OSTextAttr attrs; Listener *OnFilter; @@ -211,8 +212,14 @@ static void OSX_textDidChange(OSXEdit *edit, NSTextField *field) static void OSX_textDidEndEditing(OSXEdit *edit, NSNotification *notification) { + OSXEdit *ledit = (OSXEdit *)edit; unsigned int whyEnd = [[[notification userInfo] objectForKey:@"NSTextMovement"] unsignedIntValue]; NSWindow *window = [edit window]; + NSText *text = [window fieldEditor:YES forObject:ledit->field]; + + ledit->select = [text selectedRange]; + [text setSelectedRange:NSMakeRange(0, 0)]; + if (whyEnd == NSReturnTextMovement) { [window keyDown:(NSEvent *)231]; @@ -383,6 +390,7 @@ static void i_update_vpadding(OSXEdit *edit) [field setCell:[[OSXTextFieldCell alloc] init]]; edit->flags = flags; edit->vpadding = UINT32_MAX; + edit->select = NSMakeRange(0, 0); edit->OnFilter = NULL; edit->OnChange = NULL; edit->OnFocus = NULL; @@ -567,9 +575,38 @@ void osedit_autoselect(OSEdit *edit, const bool_t autoselect) void osedit_select(OSEdit *edit, const int32_t start, const int32_t end) { - unref(edit); - unref(start); - unref(end); + OSXEdit *ledit = (OSXEdit *)edit; + cassert_no_null(ledit); + /* Deselect all text */ + if (start == -1 && end == 0) + { + ledit->select = NSMakeRange(0, 0); + } + /* Deselect all text and caret to the end */ + else if (start == -1 && end == -1) + { + ledit->select = NSMakeRange(NSUIntegerMax, 0); + } + /* Select all text and caret to the end */ + else if (start == 0 && end == -1) + { + ledit->select = NSMakeRange(0, NSUIntegerMax); + } + /* Select from position to the end */ + else if (start > 0 && end == -1) + { + ledit->select = NSMakeRange(start, NSIntegerMax); + } + /* Deselect all and move the caret */ + else if (start == end) + { + ledit->select = NSMakeRange(start, 0); + } + /* Select from start to end */ + else + { + ledit->select = NSMakeRange(start, end - start); + } } /*---------------------------------------------------------------------------*/ @@ -762,8 +799,7 @@ void osedit_focus(OSEdit *edit, const bool_t focus) } else { - NSRange range = [text selectedRange]; - [text setSelectedRange:NSMakeRange(range.length, 0)]; + [text setSelectedRange:ledit->select]; } } } diff --git a/src/osgui/osx/osweb.m b/src/osgui/osx/osweb.m index 1002463b..eff541af 100644 --- a/src/osgui/osx/osweb.m +++ b/src/osgui/osx/osweb.m @@ -15,6 +15,7 @@ #include "osweb_osx.inl" #include "oscontrol_osx.inl" #include "ospanel_osx.inl" +#include #include #include diff --git a/src/osgui/win/osbutton.c b/src/osgui/win/osbutton.c index 10a23ad9..8773d3d7 100644 --- a/src/osgui/win/osbutton.c +++ b/src/osgui/win/osbutton.c @@ -40,6 +40,7 @@ struct _osbutton_t OSControl control; uint32_t flags; bool_t is_default; + bool_t can_focus; uint16_t id; vkey_t key; Font *font; @@ -227,18 +228,22 @@ static LRESULT CALLBACK i_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP return 0; case WM_SETFOCUS: - if (button_get_type(button->flags) == ekBUTTON_RADIO) - { - uint64_t microseconds; - microseconds = btime_now(); - i_LAST_FOCUS = button->control.hwnd; - i_LAST_FOCUS_TIME = i_TIME_SEC(microseconds); - } - else + if (button->can_focus == FALSE) + return 0; + { - i_LAST_FOCUS = NULL; + if (button_get_type(button->flags) == ekBUTTON_RADIO) + { + uint64_t microseconds; + microseconds = btime_now(); + i_LAST_FOCUS = button->control.hwnd; + i_LAST_FOCUS_TIME = i_TIME_SEC(microseconds); + } + else + { + i_LAST_FOCUS = NULL; + } } - break; case WM_KILLFOCUS: @@ -322,6 +327,7 @@ OSButton *osbutton_create(const uint32_t flags) button->control.type = ekGUI_TYPE_BUTTON; button->flags = flags; button->is_default = FALSE; + button->can_focus = TRUE; button->vpadding = UINT32_MAX; button->key = ENUM_MAX(vkey_t); button->id = _osgui_unique_child_id(); @@ -729,6 +735,14 @@ void _osbutton_toggle(OSButton *button) /*---------------------------------------------------------------------------*/ +void _osbutton_set_can_focus(OSButton *button, const bool_t can_focus) +{ + cassert_no_null(button); + button->can_focus = can_focus; +} + +/*---------------------------------------------------------------------------*/ + void osbutton_set_default(OSButton *button, const bool_t is_default) { cassert_no_null(button); diff --git a/src/osgui/win/osbutton_win.inl b/src/osgui/win/osbutton_win.inl index d4c0ac78..abd2eb26 100644 --- a/src/osgui/win/osbutton_win.inl +++ b/src/osgui/win/osbutton_win.inl @@ -18,4 +18,6 @@ void _osbutton_command(OSButton *button, WPARAM wParam, const bool_t restore_foc void _osbutton_toggle(OSButton *button); +void _osbutton_set_can_focus(OSButton *button, const bool_t can_focus); + __END_C diff --git a/src/osgui/win/oscontrol.cpp b/src/osgui/win/oscontrol.cpp index 60a1de56..558f1cd1 100644 --- a/src/osgui/win/oscontrol.cpp +++ b/src/osgui/win/oscontrol.cpp @@ -14,6 +14,7 @@ #include "oscontrol_win.inl" #include "osgui.inl" #include "osgui_win.inl" +#include "osbutton_win.inl" #include "oscombo_win.inl" #include "ospanel_win.inl" #include "ospopup_win.inl" @@ -500,6 +501,15 @@ void oscontrol_frame(const OSControl *control, OSFrame *rect) /*---------------------------------------------------------------------------*/ +void oscontrol_set_can_focus(OSControl *control, const bool_t can_focus) +{ + cassert_no_null(control); + if (control->type == ekGUI_TYPE_BUTTON) + _osbutton_set_can_focus(cast(control, OSButton), can_focus); +} + +/*---------------------------------------------------------------------------*/ + OSWidget *oscontrol_focus_widget(const OSControl *control) { cassert_no_null(control);