summaryrefslogtreecommitdiff
path: root/src/nigui
diff options
context:
space:
mode:
authortrustable-code <krauter.simon@arcor.de>2017-09-12 21:25:30 +0200
committertrustable-code <krauter.simon@arcor.de>2017-09-12 21:25:30 +0200
commitbc342d98102bea5ff6e2d2f41684c87d75a164bb (patch)
tree2981c613b2f121c32bcc70d03f38e3b49b734bca /src/nigui
parent360f88fd25d197c2956c1fccc635646646fbf751 (diff)
downloadNiGui-bc342d98102bea5ff6e2d2f41684c87d75a164bb.tar.gz
NiGui-bc342d98102bea5ff6e2d2f41684c87d75a164bb.zip
Improvements for Button/TextBox/TextArea
* TextArea is now inherited from TextBox (A TextArea can do anything that a TextBox can do.) * Better handling of keyboard events * New properties for TextBox/TextArea: "editable", "cursorPos", "selectionStart" and "selectionEnd" * New properties for Button: "enabled"
Diffstat (limited to 'src/nigui')
-rwxr-xr-xsrc/nigui/private/gtk3/gtk3.nim16
-rwxr-xr-xsrc/nigui/private/gtk3/platform_impl.nim173
-rwxr-xr-xsrc/nigui/private/gtk3/platform_types2.nim4
-rwxr-xr-xsrc/nigui/private/gtk3/platform_types3.nim8
-rwxr-xr-xsrc/nigui/private/windows/platform_impl.nim173
-rwxr-xr-xsrc/nigui/private/windows/platform_types2.nim2
-rwxr-xr-xsrc/nigui/private/windows/platform_types3.nim6
-rwxr-xr-xsrc/nigui/private/windows/windows.nim5
8 files changed, 197 insertions, 190 deletions
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: