diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/nigui.nim | 203 | ||||
| -rwxr-xr-x | src/nigui/private/gtk3/gtk3.nim | 16 | ||||
| -rwxr-xr-x | src/nigui/private/gtk3/platform_impl.nim | 173 | ||||
| -rwxr-xr-x | src/nigui/private/gtk3/platform_types2.nim | 4 | ||||
| -rwxr-xr-x | src/nigui/private/gtk3/platform_types3.nim | 8 | ||||
| -rwxr-xr-x | src/nigui/private/windows/platform_impl.nim | 173 | ||||
| -rwxr-xr-x | src/nigui/private/windows/platform_types2.nim | 2 | ||||
| -rwxr-xr-x | src/nigui/private/windows/platform_types3.nim | 6 | ||||
| -rwxr-xr-x | src/nigui/private/windows/windows.nim | 5 |
9 files changed, 342 insertions, 248 deletions
diff --git a/src/nigui.nim b/src/nigui.nim index 6065cba..a6b3b0a 100755 --- a/src/nigui.nim +++ b/src/nigui.nim @@ -67,50 +67,61 @@ type Timer* = distinct int Key* = enum - Key_None - Key_Number0 - Key_Number1 - Key_Number2 - Key_Number3 - Key_Number4 - Key_Number5 - Key_Number6 - Key_Number7 - Key_Number8 - Key_Number9 - Key_A - Key_B - Key_C - Key_D - Key_E - Key_F - Key_G - Key_H - Key_I - Key_J - Key_K - Key_L - Key_M - Key_N - Key_O - Key_P - Key_Q - Key_R - Key_S - Key_T - Key_U - Key_V - Key_W - Key_X - Key_Y - Key_Z - Key_Space - Key_Tab - Key_Return - Key_Escape - Key_Insert + # Keys with same value than Unicode: + Key_None = 0 + Key_Backspace = 8 + Key_Tab = 9 + Key_Return = 13 + Key_Escape = 27 + Key_Space = 32 + Key_Asterisk = 42 + Key_Plus = 43 + Key_Comma = 44 + Key_Minus = 45 + Key_Point = 46 + Key_Number0 = 48 + Key_Number1 = 49 + Key_Number2 = 50 + Key_Number3 = 51 + Key_Number4 = 52 + Key_Number5 = 53 + Key_Number6 = 54 + Key_Number7 = 55 + Key_Number8 = 56 + Key_Number9 = 57 + Key_A = 65 + Key_B = 66 + Key_C = 67 + Key_D = 68 + Key_E = 69 + Key_F = 70 + Key_G = 71 + Key_H = 72 + Key_I = 73 + Key_J = 74 + Key_K = 75 + Key_L = 76 + Key_M = 77 + Key_N = 78 + Key_O = 79 + Key_P = 80 + Key_Q = 81 + Key_R = 82 + Key_S = 83 + Key_T = 84 + Key_U = 85 + Key_V = 86 + Key_W = 87 + Key_X = 88 + Key_Y = 89 + Key_Z = 90 + Key_AE = 196 + Key_OE = 214 + Key_UE = 220 + Key_SharpS = 223 + # Not part of Unicode: + Key_Insert = 1000 Key_Delete - Key_Backspace Key_Left Key_Right Key_Up @@ -120,7 +131,8 @@ type Key_PageUp Key_PageDown -const inactiveTimer* = 0 +const + inactiveTimer* = 0 # ---------------------------------------------------------------------------------------- @@ -281,17 +293,15 @@ type Button* = ref object of ControlImpl fText: string + fEnabled: bool Label* = ref object of ControlImpl fText: string TextBox* = ref object of ControlImpl + fEditable: bool - TextArea* = ref object of ControlImpl - fWrap: bool - - -# Platform-specific extension of basic controls: +# Platform-specific extension: when useWindows(): include "nigui/private/windows/platform_types2" when useGtk(): include "nigui/private/gtk3/platform_types2" @@ -308,6 +318,13 @@ type fPadding: int fSpacing: int + TextArea* = ref object of NativeTextBox + fWrap: bool + +# Platform-specific extension: +when useWindows(): include "nigui/private/windows/platform_types3" +when useGtk(): include "nigui/private/gtk3/platform_types3" + # ---------------------------------------------------------------------------------------- # Global Variables @@ -766,6 +783,9 @@ proc init*(button: NativeButton) method text*(button: Button): string method `text=`*(button: Button, text: string) +method enabled*(button: Button): bool +method `enabled=`*(button: Button, enabled: bool) + # ---------------------------------------------------------------------------------------- # Label @@ -792,6 +812,21 @@ proc init*(textBox: NativeTextBox) method text*(textBox: TextBox): string method `text=`*(textBox: TextBox, text: string) +method editable*(textBox: TextBox): bool +method `editable=`*(textBox: TextBox, editable: bool) + +method cursorPos*(textBox: TextBox): int +method `cursorPos=`*(textBox: TextBox, cursorPos: int) + +method selectionStart*(textBox: TextBox): int +method `selectionStart=`*(textBox: TextBox, selectionStart: int) + +method selectionEnd*(textBox: TextBox): int +method `selectionEnd=`*(textBox: TextBox, selectionEnd: int) + +method selectedText*(textBox: TextBox): string +method `selectedText=`*(textBox: TextBox, text: string) + # ---------------------------------------------------------------------------------------- # TextArea @@ -802,8 +837,6 @@ proc newTextArea*(text = ""): TextArea proc init*(textArea: TextArea) proc init*(textArea: NativeTextArea) -method text*(textArea: TextArea): string -method `text=`*(textArea: TextArea, text: string) method addText*(textArea: TextArea, text: string) method addLine*(textArea: TextArea, text = "") @@ -892,7 +925,27 @@ proc rgb(red, green, blue: byte, alpha: byte = 255): Color = result.blue = blue result.alpha = alpha -proc countLines(s: string): int = strutils.countLines(s) + 1 +# Should removed here, when version in strutils is fixed +proc countLines(s: string): int = + result = 1 + var i = 0 + while i < s.len: + case s[i] + of '\c': + if s[i+1] == '\l': inc i + inc result + of '\l': inc result + else: discard + inc i + +proc unicodeToUpper(unicode: int): int = + if unicode < 128: + return cast[int](cast[char](unicode).toUpper) + result = case unicode: + of 228: 196 # Ä + of 246: 214 # Ö + of 252: 220 # Ü + else: unicode proc sleep(app: App, milliSeconds: float) = let t = epochTime() + milliSeconds / 1000 @@ -2136,6 +2189,7 @@ proc init(button: Button) = button.fHeightMode = HeightMode_Auto button.minWidth = 15 button.minHeight = 15 + button.enabled = true method text(button: Button): string = button.fText @@ -2149,6 +2203,11 @@ method naturalWidth(button: Button): int = button.getTextWidth(button.text) + 20 method naturalHeight(button: Button): int = button.getTextLineHeight() * button.text.countLines + 12 +method enabled(button: Button): bool = button.fEnabled + +method `enabled=`(button: Button, enabled: bool) = discard + # has to be implemented by NativeTextBox + method `onDraw=`(container: NativeButton, callback: DrawProc) = raiseError("NativeButton does not allow onDraw.") @@ -2198,6 +2257,7 @@ proc init(textBox: TextBox) = textBox.fHeightMode = HeightMode_Auto textBox.minWidth = 20 textBox.minHeight = 20 + textBox.editable = true method naturalHeight(textBox: TextBox): int = textBox.getTextLineHeight() @@ -2209,6 +2269,38 @@ method `text=`(textBox: TextBox, text: string) = discard method `onDraw=`(container: NativeTextBox, callback: DrawProc) = raiseError("NativeTextBox does not allow onDraw.") +method editable(textBox: TextBox): bool = textBox.fEditable + +method `editable=`(textBox: TextBox, editable: bool) = discard + # has to be implemented by NativeTextBox + +method cursorPos(textBox: TextBox): int = discard + # has to be implemented by NativeTextBox + +method `cursorPos=`(textBox: TextBox, cursorPos: int) = discard + # has to be implemented by NativeTextBox + +method selectionStart(textBox: TextBox): int = discard + # has to be implemented by NativeTextBox + +method `selectionStart=`(textBox: TextBox, selectionStart: int) = discard + # has to be implemented by NativeTextBox + +method selectionEnd(textBox: TextBox): int = discard + # has to be implemented by NativeTextBox + +method `selectionEnd=`(textBox: TextBox, selectionEnd: int) = discard + # has to be implemented by NativeTextBox + +method selectedText(textBox: TextBox): string = + result = textBox.text.substr(textBox.selectionStart, textBox.selectionEnd - 1) + +method `selectedText=`(textBox: TextBox, text: string) = + let oldCursorPos = textBox.cursorPos + let oldText = textBox.text + textBox.text = oldText.substr(0, textBox.selectionStart - 1) & text & oldText.substr(textBox.selectionEnd) + textBox.cursorPos = oldCursorPos + # ---------------------------------------------------------------------------------------- # TextArea @@ -2226,12 +2318,7 @@ proc init(textArea: TextArea) = textArea.minWidth = 20 textArea.minHeight = 20 textArea.wrap = true - -method text(textArea: TextArea): string = discard - # has to be implemented by NativeTextBox - -method `text=`(textArea: TextArea, text: string) = discard - # has to be implemented by NativeTextBox + textArea.editable = true method addText(textArea: TextArea, text: string) = textArea.text = textArea.text & text diff --git a/src/nigui/private/gtk3/gtk3.nim b/src/nigui/private/gtk3/gtk3.nim index eff2a94..3e83f62 100755 --- a/src/nigui/private/gtk3/gtk3.nim +++ b/src/nigui/private/gtk3/gtk3.nim @@ -245,6 +245,7 @@ proc gtk_widget_grab_focus*(widget: pointer) {.importc: "gtk_widget_grab_focus", proc gtk_widget_is_focus*(widget: pointer): bool {.importc: "gtk_widget_is_focus", libgtk3.} proc gtk_widget_realize*(widget: pointer) {.importc: "gtk_widget_realize", libgtk3.} proc gtk_widget_draw*(widget, cr: pointer) {.importc: "gtk_widget_draw", libgtk3.} +proc gtk_widget_set_sensitive*(widget: pointer, sensitive: bool) {.importc: "gtk_widget_set_sensitive", libgtk3.} proc gtk_container_add*(container, widget: pointer) {.importc: "gtk_container_add", libgtk3.} proc gtk_container_remove*(container, widget: pointer) {.importc: "gtk_container_remove", libgtk3.} @@ -303,6 +304,10 @@ proc gtk_entry_get_text*(entry: pointer): cstring {.importc: "gtk_entry_get_text proc gtk_entry_set_width_chars*(entry: pointer, n_chars: cint) {.importc: "gtk_entry_set_width_chars", libgtk3.} proc gtk_editable_get_selection_bounds*(editable: pointer, start_pos, end_pos: var cint): bool {.importc: "gtk_editable_get_selection_bounds", libgtk3.} proc gtk_editable_get_chars*(editable: pointer, start_pos, end_pos: cint): cstring {.importc: "gtk_editable_get_chars", libgtk3.} +proc gtk_editable_select_region*(editable: pointer, start_pos, end_pos: cint) {.importc: "gtk_editable_select_region", libgtk3.} +proc gtk_editable_get_position*(editable: pointer): cint {.importc: "gtk_editable_get_position", libgtk3.} +proc gtk_editable_set_position*(editable: pointer, position: cint) {.importc: "gtk_editable_set_position", libgtk3.} +proc gtk_editable_set_editable*(editable: pointer, is_editable: bool) {.importc: "gtk_editable_set_editable", libgtk3.} proc gtk_text_view_new*(): pointer {.importc: "gtk_text_view_new", libgtk3.} proc gtk_text_view_set_buffer*(text_view, buffer: pointer) {.importc: "gtk_text_view_set_buffer", libgtk3.} @@ -315,8 +320,7 @@ proc gtk_text_view_set_bottom_margin*(text_view: pointer, margin: cint) {.import proc gtk_text_view_scroll_to_iter*(text_view: pointer, iter: var GtkTextIter, within_margin: cfloat, use_align: bool, xalign, yalign: cfloat) {.importc: "gtk_text_view_scroll_to_iter", libgtk3.} # proc gtk_text_view_scroll_to_mark*(text_view, mark: pointer, within_margin: cfloat, use_align: bool, xalign, yalign: cfloat) {.importc: "gtk_text_view_scroll_to_mark", libgtk3.} # proc gtk_text_view_place_cursor_onscreen*(text_view: pointer): bool {.importc: "gtk_text_view_place_cursor_onscreen", libgtk3.} - -# proc gtk_text_mark_new*(name: cstring, left_gravity: bool): pointer {.importc: "gtk_text_mark_new", libgtk3.} +proc gtk_text_view_set_editable*(text_view: pointer, setting: bool) {.importc: "gtk_text_view_set_editable", libgtk3.} # proc gtk_text_buffer_new*(table: pointer): pointer {.importc: "gtk_text_buffer_new", libgtk3.} proc gtk_text_buffer_set_text*(text_buffer: pointer, text: cstring, len: cint) {.importc: "gtk_text_buffer_set_text", libgtk3.} @@ -324,10 +328,16 @@ proc gtk_text_buffer_get_text*(text_buffer: pointer, start, `end`: var GtkTextIt proc gtk_text_buffer_get_start_iter*(text_buffer: pointer, iter: var GtkTextIter) {.importc: "gtk_text_buffer_get_start_iter", libgtk3.} proc gtk_text_buffer_get_end_iter*(text_buffer: pointer, iter: var GtkTextIter) {.importc: "gtk_text_buffer_get_end_iter", libgtk3.} # proc gtk_text_buffer_add_mark*(buffer, mark: pointer, where: var GtkTextIter) {.importc: "gtk_text_buffer_add_mark", libgtk3.} -# proc gtk_text_buffer_get_insert*(buffer: pointer): pointer {.importc: "gtk_text_buffer_get_insert", libgtk3.} +proc gtk_text_buffer_get_insert*(buffer: pointer): pointer {.importc: "gtk_text_buffer_get_insert", libgtk3.} # proc gtk_text_buffer_get_iter_at_line*(buffer: pointer, iter: var GtkTextIter, line_number: cint) {.importc: "gtk_text_buffer_get_iter_at_line", libgtk3.} proc gtk_text_buffer_insert*(buffer: pointer, iter: var GtkTextIter, text: cstring, len: cint) {.importc: "gtk_text_buffer_insert", libgtk3.} proc gtk_text_buffer_get_selection_bounds*(buffer: pointer, start, `end`: var GtkTextIter): bool {.importc: "gtk_text_buffer_get_selection_bounds", libgtk3.} +proc gtk_text_buffer_select_range*(buffer: pointer, ins, bound: var GtkTextIter) {.importc: "gtk_text_buffer_select_range", libgtk3.} +proc gtk_text_buffer_get_iter_at_offset*(buffer: pointer, iter: var GtkTextIter, char_offset: cint) {.importc: "gtk_text_buffer_get_iter_at_offset", libgtk3.} +proc gtk_text_buffer_get_iter_at_mark*(buffer: pointer, iter: var GtkTextIter, mark: pointer) {.importc: "gtk_text_buffer_get_iter_at_mark", libgtk3.} + +proc gtk_text_iter_get_offset*(iter: var GtkTextIter): cint {.importc: "gtk_text_iter_get_offset", libgtk3.} +# proc gtk_text_mark_new*(name: cstring, left_gravity: bool): pointer {.importc: "gtk_text_mark_new", libgtk3.} proc gtk_scrolled_window_new*(hadjustment, vadjustment: pointer): pointer {.importc: "gtk_scrolled_window_new", libgtk3.} proc gtk_scrolled_window_set_policy*(scrolled_window: pointer, hscrollbar_policy, vscrollbar_policy: cint) {.importc: "gtk_scrolled_window_set_policy", libgtk3.} diff --git a/src/nigui/private/gtk3/platform_impl.nim b/src/nigui/private/gtk3/platform_impl.nim index 405a3a3..508373c 100755 --- a/src/nigui/private/gtk3/platform_impl.nim +++ b/src/nigui/private/gtk3/platform_impl.nim @@ -61,70 +61,7 @@ proc pWindowConfigureSignal(windowHandle, event, data: pointer): bool {.cdecl.} window.triggerRelayout() proc pKeyvalToKey(keyval: cint): Key = - case keyval - of 48: Key_Number0 - of 49: Key_Number1 - of 50: Key_Number2 - of 51: Key_Number3 - of 52: Key_Number4 - of 53: Key_Number5 - of 54: Key_Number6 - of 55: Key_Number7 - of 56: Key_Number8 - of 57: Key_Number9 - of 65: Key_A - of 66: Key_B - of 67: Key_C - of 68: Key_D - of 69: Key_E - of 70: Key_F - of 71: Key_G - of 72: Key_H - of 73: Key_I - of 74: Key_J - of 75: Key_K - of 76: Key_L - of 77: Key_M - of 78: Key_N - of 79: Key_O - of 80: Key_P - of 81: Key_Q - of 82: Key_R - of 83: Key_S - of 84: Key_T - of 85: Key_U - of 86: Key_V - of 87: Key_W - of 88: Key_X - of 89: Key_Y - of 90: Key_Z - of 97: Key_A - of 98: Key_B - of 99: Key_C - of 100: Key_D - of 101: Key_E - of 102: Key_F - of 103: Key_G - of 104: Key_H - of 105: Key_I - of 106: Key_J - of 107: Key_K - of 108: Key_L - of 109: Key_M - of 110: Key_N - of 111: Key_O - of 112: Key_P - of 113: Key_Q - of 114: Key_R - of 115: Key_S - of 116: Key_T - of 117: Key_U - of 118: Key_V - of 119: Key_W - of 120: Key_X - of 121: Key_Y - of 122: Key_Z - of 32: Key_Space + result = case keyval of 65289: Key_Tab of 65293: Key_Return of 65307: Key_Escape @@ -139,7 +76,7 @@ proc pKeyvalToKey(keyval: cint): Key = of 65367: Key_End of 65365: Key_PageUp of 65366: Key_PageDown - else: Key_None + else: cast[Key](keyval.unicodeToUpper) proc pWindowKeyPressSignal(widget: pointer, event: var GdkEventKey, data: pointer): bool {.cdecl.} = # echo "window keyPressCallback" @@ -1092,6 +1029,10 @@ method pAddButtonPressEvent(control: NativeButton) = gtk_widget_add_events(control.fHandle, GDK_BUTTON_PRESS_MASK) discard g_signal_connect_data(control.fHandle, "button-press-event", pDefaultControlButtonPressSignal, cast[pointer](control)) +method `enabled=`(button: NativeButton, enabled: bool) = + button.fEnabled = enabled + gtk_widget_set_sensitive(button.fHandle, enabled) + # ---------------------------------------------------------------------------------------- # Label @@ -1129,12 +1070,8 @@ proc pTextBoxKeyPressSignal(widget: pointer, event: var GdkEventKey, data: point let modifiers = gtk_accelerator_get_default_mod_mask() if event.keyval == 'c'.ord and (event.state and modifiers) == GDK_CONTROL_MASK: let textBox = cast[NativeTextBox](data) - var startPos: cint - var endPos: cint - discard gtk_editable_get_selection_bounds(textBox.fHandle, startPos, endPos) - if startPos != endPos: - app.clipboardText = $gtk_editable_get_chars(textBox.fHandle, startPos, endPos) - return true # prevent default "copy to clipboard" + app.clipboardText = textBox.selectedText + return true # prevent default "copy to clipboard" proc init(textBox: NativeTextBox) = textBox.fHandle = gtk_entry_new() @@ -1158,25 +1095,42 @@ method pAddButtonPressEvent(control: NativeTextBox) = gtk_widget_add_events(control.fHandle, GDK_BUTTON_PRESS_MASK) discard g_signal_connect_data(control.fHandle, "button-press-event", pDefaultControlButtonPressSignal, cast[pointer](control)) +method `editable=`(textBox: NativeTextBox, editable: bool) = + textBox.fEditable = editable + gtk_editable_set_editable(textBox.fHandle, editable) + +method cursorPos(textBox: NativeTextBox): int = + result = gtk_editable_get_position(textBox.fHandle) + +method `cursorPos=`(textBox: NativeTextBox, cursorPos: int) = + # side effect: clears selection + gtk_editable_set_position(textBox.fHandle, cursorPos.cint) + +method selectionStart(textBox: NativeTextBox): int = + var startPos: cint + var endPos: cint + discard gtk_editable_get_selection_bounds(textBox.fHandle, startPos, endPos) + result = startPos + +method selectionEnd(textBox: NativeTextBox): int = + var startPos: cint + var endPos: cint + discard gtk_editable_get_selection_bounds(textBox.fHandle, startPos, endPos) + result = endPos + +method `selectionStart=`(textBox: NativeTextBox, selectionStart: int) = + gtk_editable_select_region(textBox.fHandle, selectionStart.cint, textBox.selectionEnd.cint) + # side effect: sets cursor to end of selection + +method `selectionEnd=`(textBox: NativeTextBox, selectionEnd: int) = + gtk_editable_select_region(textBox.fHandle, textBox.selectionStart.cint, selectionEnd.cint) + # side effect: sets cursor to end of selection + # ---------------------------------------------------------------------------------------- # TextArea # ---------------------------------------------------------------------------------------- -proc pTextAreaKeyPressSignal(widget: pointer, event: var GdkEventKey, data: pointer): bool {.cdecl.} = - result = pControlKeyPressSignal(widget, event, data) - - # Implement own "copy to clipboard", because by default the clipboard is non-persistent - if not result: - let modifiers = gtk_accelerator_get_default_mod_mask() - if event.keyval == 'c'.ord and (event.state and modifiers) == GDK_CONTROL_MASK: - let textArea = cast[NativeTextArea](data) - var startIter: GtkTextIter - var endIter: GtkTextIter - discard gtk_text_buffer_get_selection_bounds(textArea.fBufferHandle, startIter, endIter) - app.clipboardText = $gtk_text_buffer_get_text(textArea.fBufferHandle, startIter, endIter, true) - return true # prevent default "copy to clipboard" - proc init(textArea: NativeTextArea) = textArea.fHandle = gtk_scrolled_window_new(nil, nil) # gtk_scrolled_window_set_policy(textArea.fHandle, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC) @@ -1188,11 +1142,15 @@ proc init(textArea: NativeTextArea) = gtk_text_view_set_bottom_margin(textArea.fTextViewHandle, 5) gtk_container_add(textArea.fHandle, textArea.fTextViewHandle) gtk_widget_show(textArea.fTextViewHandle) - discard g_signal_connect_data(textArea.fTextViewHandle, "key-press-event", pTextAreaKeyPressSignal, cast[pointer](textArea)) + discard g_signal_connect_data(textArea.fTextViewHandle, "key-press-event", pTextBoxKeyPressSignal, cast[pointer](textArea)) textArea.fBufferHandle = gtk_text_view_get_buffer(textArea.fTextViewHandle) discard g_signal_connect_data(textArea.fBufferHandle, "changed", pControlChangedSignal, cast[pointer](textArea)) textArea.TextArea.init() +method setSize(textBox: NativeTextArea, width, height: int) = + # Need to override method of NativeTextBox + procCall textBox.ControlImpl.setSize(width, height) + method text(textArea: NativeTextArea): string = var startIter, endIter: GtkTextIter gtk_text_buffer_get_start_iter(textArea.fBufferHandle, startIter) @@ -1227,3 +1185,46 @@ method `wrap=`(textArea: NativeTextArea, wrap: bool) = else: gtk_text_view_set_wrap_mode(textArea.fTextViewHandle, GTK_WRAP_NONE) +method `editable=`(textArea: NativeTextArea, editable: bool) = + textArea.fEditable = editable + gtk_text_view_set_editable(textArea.fTextViewHandle, editable) + +method cursorPos(textArea: NativeTextArea): int = + let mark = gtk_text_buffer_get_insert(textArea.fBufferHandle) + var iter: GtkTextIter + gtk_text_buffer_get_iter_at_mark(textArea.fBufferHandle, iter, mark) + result = gtk_text_iter_get_offset(iter) + +method `cursorPos=`(textArea: NativeTextArea, cursorPos: int) = + # side effect: clears selection + var iter: GtkTextIter + gtk_text_buffer_get_iter_at_offset(textArea.fBufferHandle, iter, cursorPos.cint) + gtk_text_buffer_select_range(textArea.fBufferHandle, iter, iter) + +method selectionStart(textArea: NativeTextArea): int = + var startIter: GtkTextIter + var endIter: GtkTextIter + discard gtk_text_buffer_get_selection_bounds(textArea.fBufferHandle, startIter, endIter) + result = gtk_text_iter_get_offset(startIter) + +method selectionEnd(textArea: NativeTextArea): int = + var startIter: GtkTextIter + var endIter: GtkTextIter + discard gtk_text_buffer_get_selection_bounds(textArea.fBufferHandle, startIter, endIter) + result = gtk_text_iter_get_offset(endIter) + +method `selectionStart=`(textArea: NativeTextArea, selectionStart: int) = + var startIter: GtkTextIter + var endIter: GtkTextIter + gtk_text_buffer_get_iter_at_offset(textArea.fBufferHandle, startIter, selectionStart.cint) + gtk_text_buffer_get_iter_at_offset(textArea.fBufferHandle, endIter, textArea.selectionEnd.cint) + gtk_text_buffer_select_range(textArea.fBufferHandle, startIter, endIter) + # side effect: sets cursor to start of selection + +method `selectionEnd=`(textArea: NativeTextArea, selectionEnd: int) = + var startIter: GtkTextIter + var endIter: GtkTextIter + gtk_text_buffer_get_iter_at_offset(textArea.fBufferHandle, startIter, textArea.selectionStart.cint) + gtk_text_buffer_get_iter_at_offset(textArea.fBufferHandle, endIter, selectionEnd.cint) + gtk_text_buffer_select_range(textArea.fBufferHandle, startIter, endIter) + # side effect: sets cursor to start of selection diff --git a/src/nigui/private/gtk3/platform_types2.nim b/src/nigui/private/gtk3/platform_types2.nim index c176ffc..5faa8b6 100755 --- a/src/nigui/private/gtk3/platform_types2.nim +++ b/src/nigui/private/gtk3/platform_types2.nim @@ -14,7 +14,3 @@ type NativeLabel* = ref object of Label NativeTextBox* = ref object of TextBox - - NativeTextArea* = ref object of TextArea - fTextViewHandle: pointer - fBufferHandle: pointer diff --git a/src/nigui/private/gtk3/platform_types3.nim b/src/nigui/private/gtk3/platform_types3.nim new file mode 100755 index 0000000..d424f3b --- /dev/null +++ b/src/nigui/private/gtk3/platform_types3.nim @@ -0,0 +1,8 @@ +# NiGui - GTK+ 3 platform-specific code - part 3 + +# This file will be included in "nigui.nim". + +type + NativeTextArea* = ref object of TextArea + fTextViewHandle: pointer + fBufferHandle: pointer diff --git a/src/nigui/private/windows/platform_impl.nim b/src/nigui/private/windows/platform_impl.nim index 8013706..2466e00 100755 --- a/src/nigui/private/windows/platform_impl.nim +++ b/src/nigui/private/windows/platform_impl.nim @@ -207,51 +207,8 @@ proc pCommonWndProc(hWnd: pointer, uMsg: int32, wParam, lParam: pointer): pointe discard result = DefWindowProcA(hWnd, uMsg, wParam, lParam) -proc pKeyvalToKey(keyval: int): Key = +proc pVirtualKeyToKey(keyval: int): Key = case keyval - of 48: Key_Number0 - of 49: Key_Number1 - of 50: Key_Number2 - of 51: Key_Number3 - of 52: Key_Number4 - of 53: Key_Number5 - of 54: Key_Number6 - of 55: Key_Number7 - of 56: Key_Number8 - of 57: Key_Number9 - of 65: Key_A - of 66: Key_B - of 67: Key_C - of 68: Key_D - of 69: Key_E - of 70: Key_F - of 71: Key_G - of 72: Key_H - of 73: Key_I - of 74: Key_J - of 75: Key_K - of 76: Key_L - of 77: Key_M - of 78: Key_N - of 79: Key_O - of 80: Key_P - of 81: Key_Q - of 82: Key_R - of 83: Key_S - of 84: Key_T - of 85: Key_U - of 86: Key_V - of 87: Key_W - of 88: Key_X - of 89: Key_Y - of 90: Key_Z - of 32: Key_Space - of 9: Key_Tab - of 13: Key_Return - of 27: Key_Escape - of 45: Key_Insert - of 46: Key_Delete - of 8: Key_Backspace of 37: Key_Left of 38: Key_Up of 39: Key_Right @@ -260,32 +217,20 @@ proc pKeyvalToKey(keyval: int): Key = of 36: Key_Home of 33: Key_PageUp of 34: Key_PageDown - else: Key_None + else: cast[Key](keyval.unicodeToUpper) -proc pHandleWMKEYDOWN(window: Window, control: Control, wParam, lParam: pointer) = +proc pHandleWMKEYDOWNOrWMCHAR(window: Window, control: Control, unicode: int, key: Key): bool = var windowEvent = new WindowKeyEvent windowEvent.window = window - windowEvent.key = pKeyvalToKey(cast[int](wParam)) + windowEvent.key = key if windowEvent.key == Key_None: - echo "Unkown key value: ", cast[int](wParam) + echo "WM_CHAR: Unkown key value: ", unicode return - if not GetKeyboardState(pKeyState): pRaiseLastOSError() - var widestring = newString(2) - let scancode = int32((cast[int](lParam) shr 8) and 0xFFFFFF00) - let ret = ToUnicode(cast[int](wParam).int32, scancode, pKeyState, widestring, 1, 0) - if ret == 1: - windowEvent.unicode = widestring.pUtf16ToUnicode - windowEvent.character = windowEvent.unicode.pUnicodeCharToUtf8 - else: - windowEvent.character = "" - window.handleKeyDownEvent(windowEvent) + windowEvent.unicode = unicode + windowEvent.character = unicode.pUnicodeCharToUtf8 - # var windowEvent = new WindowKeyEvent - # windowEvent.window = window - # windowEvent.character = $chr(cast[int](wParam)) - # windowEvent.key = pKeyvalToKey(cast[int](wParam)) - # window.handleKeyDownEvent(windowEvent) + window.handleKeyDownEvent(windowEvent) if control != nil: var controlEvent = new ControlKeyEvent @@ -294,9 +239,20 @@ proc pHandleWMKEYDOWN(window: Window, control: Control, wParam, lParam: pointer) controlEvent.unicode = windowEvent.unicode controlEvent.character = windowEvent.character control.handleKeyDownEvent(controlEvent) - # if controlEvent.cancel: - # return nil # key is still inserted in text area + result = controlEvent.cancel + +proc pHandleWMKEYDOWN(window: Window, control: Control, wParam, lParam: pointer): bool = + if not GetKeyboardState(pKeyState): pRaiseLastOSError() + var widestring = newString(2) + let scancode = int32((cast[int](lParam) shr 8) and 0xFFFFFF00) + let ret = ToUnicode(cast[int](wParam).int32, scancode, pKeyState, widestring, 1, 0) + if ret == 1: + return # Unicode characters are handled by WM_CHAR + result = pHandleWMKEYDOWNOrWMCHAR(window, control, 0, pVirtualKeyToKey(cast[int](wParam))) +proc pHandleWMCHAR(window: Window, control: Control, wParam, lParam: pointer): bool = + let unicode = cast[int](wParam) + result = pHandleWMKEYDOWNOrWMCHAR(window, control, unicode, cast[Key](unicode.unicodeToUpper)) proc pWindowWndProc(hWnd: pointer, uMsg: int32, wParam, lParam: pointer): pointer {.cdecl.} = case uMsg @@ -339,31 +295,14 @@ proc pWindowWndProc(hWnd: pointer, uMsg: int32, wParam, lParam: pointer): pointe event.window = window event.files = files window.handleDropFilesEvent(event) - # of WM_CHAR: - # not triggered for all key - # echo "window WM_CHAR: " - # let window = cast[Window](pGetWindowLongPtr(hWnd, GWLP_USERDATA)) - # if window != nil: - # var unicode = cast[int](wParam) - # var event = new WindowKeyEvent - # event.window = window - # event.unicode = unicode - # event.character = unicode.pUnicodeCharToUtf8 - # echo event.character[0].ord - # window.handleKeyDownEvent(event) of WM_KEYDOWN: - # echo "window WM_KEYDOWN" - - # if (cast[int](lParam) and 0x40000000) != 0x40000000: - # echo "window WM_KEYDOWN first" - # else: - # echo "window WM_KEYDOWN" - - # echo int((cast[int](lParam) shr 8) and 0xFFFFFF00) - let window = cast[Window](pGetWindowLongPtr(hWnd, GWLP_USERDATA)) - if window != nil: - pHandleWMKEYDOWN(window, nil, wParam, lParam) + if window != nil and pHandleWMKEYDOWN(window, nil, wParam, lParam): + return + of WM_CHAR: + let window = cast[Window](pGetWindowLongPtr(hWnd, GWLP_USERDATA)) + if window != nil and pHandleWMCHAR(window, nil, wParam, lParam): + return else: discard result = pCommonWndProc(hWnd, uMsg, wParam, lParam) @@ -427,7 +366,7 @@ proc clipboardText(app: App): string = result = $text discard GlobalUnlock(data) discard CloseClipboard() - + proc `clipboardText=`(app: App, text: string) = if not OpenClipboard(nil): return @@ -1032,11 +971,21 @@ proc pCommonControlWndProc_Scroll(origWndProc, hWnd: pointer, uMsg: int32, wPara proc pCommonControlWndProc(origWndProc, hWnd: pointer, uMsg: int32, wParam, lParam: pointer): pointer = case uMsg + + # Note: A WM_KEYDOWN is sent for every key, for some (mostly visual) keys WM_CHAR is sent in addition. + # To discard a character in text input, WM_CHAR must return without calling the default window proc. + # Because we should not to trigger two events for one key press, WM_KEYDOWN must ignore all keys, + # which are handled by WM_CHAR. + of WM_KEYDOWN: let control = cast[Control](pGetWindowLongPtr(hWnd, GWLP_USERDATA)) - if control != nil: - # echo "control WM_KEYDOWN" - pHandleWMKEYDOWN(control.parentWindow, control, wParam, lParam) + if control != nil and pHandleWMKEYDOWN(control.parentWindow, control, wParam, lParam): + return nil + + of WM_CHAR: + let control = cast[Control](pGetWindowLongPtr(hWnd, GWLP_USERDATA)) + if control != nil and pHandleWMCHAR(control.parentWindow, control, wParam, lParam): + return nil # of WM_KEYUP: # return nil # key is still inserted in text area @@ -1245,6 +1194,10 @@ method `text=`(button: NativeButton, text: string) = procCall button.Button.`text=`(text) pSetWindowText(button.fHandle, text) +method `enabled=`(button: NativeButton, enabled: bool) = + button.fEnabled = enabled + discard EnableWindow(button.fHandle, enabled) + # ---------------------------------------------------------------------------------------- # Label @@ -1279,6 +1232,36 @@ method `text=`(textBox: NativeTextBox, text: string) = pSetWindowText(textBox.fH method naturalHeight(textBox: NativeTextBox): int = textBox.getTextLineHeight() + 9 # add padding +method `editable=`(textBox: NativeTextBox, editable: bool) = + textBox.fEditable = editable + discard SendMessageA(textBox.fHandle, EM_SETREADONLY, cast[pointer](not editable), nil) + +method cursorPos(textBox: NativeTextBox): int = + var startPos: int32 + discard SendMessageA(textBox.fHandle, EM_GETSEL, startPos.addr, nil) + result = startPos + # Not really the cursor position, but the start of selection + +method `cursorPos=`(textBox: NativeTextBox, cursorPos: int) = + discard SendMessageA(textBox.fHandle, EM_SETSEL, cast[pointer](cursorPos), cast[pointer](cursorPos)) + # Side effect: clears selection + +method selectionStart(textBox: NativeTextBox): int = + var startPos: int32 + discard SendMessageA(textBox.fHandle, EM_GETSEL, startPos.addr, nil) + result = startPos + +method selectionEnd(textBox: NativeTextBox): int = + var endPos: int32 + discard SendMessageA(textBox.fHandle, EM_GETSEL, nil, endPos.addr) + result = endPos + +method `selectionStart=`(textBox: NativeTextBox, selectionStart: int) = + discard SendMessageA(textBox.fHandle, EM_SETSEL, cast[pointer](selectionStart), cast[pointer](textBox.selectionEnd)) + +method `selectionEnd=`(textBox: NativeTextBox, selectionEnd: int) = + discard SendMessageA(textBox.fHandle, EM_SETSEL, cast[pointer](textBox.selectionStart), cast[pointer](selectionEnd)) + # ---------------------------------------------------------------------------------------- # TextArea @@ -1302,9 +1285,11 @@ proc init(textArea: NativeTextArea) = pTextAreaOrigWndProc = pSetWindowLongPtr(textArea.fHandle, GWLP_WNDPROC, pTextAreaWndProc) textArea.TextArea.init() -method text(textArea: NativeTextArea): string = pGetWindowText(textArea.fHandle) +# method text(textArea: NativeTextArea): string = pGetWindowText(textArea.fHandle) +# not needed any more -method `text=`(textArea: NativeTextArea, text: string) = pSetWindowText(textArea.fHandle, text) +# method `text=`(textArea: NativeTextArea, text: string) = pSetWindowText(textArea.fHandle, text) +# not needed any more method scrollToBottom(textArea: NativeTextArea) = # select all diff --git a/src/nigui/private/windows/platform_types2.nim b/src/nigui/private/windows/platform_types2.nim index bbe7caf..120f15f 100755 --- a/src/nigui/private/windows/platform_types2.nim +++ b/src/nigui/private/windows/platform_types2.nim @@ -14,5 +14,3 @@ type NativeLabel* = ref object of Label
NativeTextBox* = ref object of TextBox
-
- NativeTextArea* = ref object of TextArea
diff --git a/src/nigui/private/windows/platform_types3.nim b/src/nigui/private/windows/platform_types3.nim new file mode 100755 index 0000000..7219027 --- /dev/null +++ b/src/nigui/private/windows/platform_types3.nim @@ -0,0 +1,6 @@ +# NiGui - Win32 platform-specific code - part 3
+
+# This file will be included in "nigui.nim".
+
+type
+ NativeTextArea* = ref object of TextArea
diff --git a/src/nigui/private/windows/windows.nim b/src/nigui/private/windows/windows.nim index 7e3f959..536d345 100755 --- a/src/nigui/private/windows/windows.nim +++ b/src/nigui/private/windows/windows.nim @@ -46,7 +46,9 @@ const CW_USEDEFAULT* = 0x80000000.int DEFAULT_GUI_FONT* = 17 EM_SCROLLCARET* = 183 + EM_GETSEL* = 176 EM_SETSEL* = 177 + EM_SETREADONLY* = 207 EN_CHANGE* = 768 ES_MULTILINE* = 4 GCLP_HBRBACKGROUND* = -10 @@ -155,7 +157,7 @@ const # UnitDocument* = 5 # UnitMillimeter* = 6 GMEM_MOVEABLE* = 2 - + # ---------------------------------------------------------------------------------------- # Types @@ -383,6 +385,7 @@ proc CloseClipboard*(): bool {.importc: "CloseClipboard", libUser32.} proc GetClipboardData*(uFormat: int32): pointer {.importc: "GetClipboardData", libUser32.} proc SetClipboardData*(uFormat: int32, hMem: pointer): pointer {.importc: "SetClipboardData", libUser32.} proc EmptyClipboard*(): bool {.importc: "EmptyClipboard", libUser32.} +# proc MapVirtualKeyW*(uCode, uMapType: int32): int32 {.importc: "MapVirtualKeyW", libUser32.} when defined(cpu64): # Only available on 64-bit Windows: |
