reflexion 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/reflex/application.cpp +37 -6
  3. data/.doc/ext/reflex/capture_event.cpp +1 -1
  4. data/.doc/ext/reflex/chase_constraint.cpp +1 -1
  5. data/.doc/ext/reflex/clipboard.cpp +1 -1
  6. data/.doc/ext/reflex/color_event.cpp +76 -0
  7. data/.doc/ext/reflex/color_picker.cpp +113 -0
  8. data/.doc/ext/reflex/constraint.cpp +1 -1
  9. data/.doc/ext/reflex/contact_event.cpp +1 -1
  10. data/.doc/ext/reflex/control_change_event.cpp +1 -1
  11. data/.doc/ext/reflex/device.cpp +1 -1
  12. data/.doc/ext/reflex/device_event.cpp +1 -1
  13. data/.doc/ext/reflex/draw_event.cpp +1 -1
  14. data/.doc/ext/reflex/ellipse_shape.cpp +1 -1
  15. data/.doc/ext/reflex/event.cpp +1 -1
  16. data/.doc/ext/reflex/file_dialog.cpp +181 -0
  17. data/.doc/ext/reflex/file_event.cpp +103 -0
  18. data/.doc/ext/reflex/filter.cpp +1 -1
  19. data/.doc/ext/reflex/focus_event.cpp +1 -1
  20. data/.doc/ext/reflex/frame_event.cpp +1 -1
  21. data/.doc/ext/reflex/gamepad.cpp +48 -0
  22. data/.doc/ext/reflex/image_view.cpp +1 -1
  23. data/.doc/ext/reflex/key_event.cpp +1 -274
  24. data/.doc/ext/reflex/line_shape.cpp +1 -1
  25. data/.doc/ext/reflex/link_constraint.cpp +1 -1
  26. data/.doc/ext/reflex/menu.cpp +6 -5
  27. data/.doc/ext/reflex/midi.cpp +9 -2
  28. data/.doc/ext/reflex/midi_event.cpp +1 -1
  29. data/.doc/ext/reflex/motion_event.cpp +1 -1
  30. data/.doc/ext/reflex/native.cpp +18 -6
  31. data/.doc/ext/reflex/note_event.cpp +1 -1
  32. data/.doc/ext/reflex/pin.cpp +1 -1
  33. data/.doc/ext/reflex/pointer.cpp +1 -1
  34. data/.doc/ext/reflex/pointer_event.cpp +2 -2
  35. data/.doc/ext/reflex/polygon_shape.cpp +1 -1
  36. data/.doc/ext/reflex/rect_shape.cpp +1 -1
  37. data/.doc/ext/reflex/reflex.cpp +566 -232
  38. data/.doc/ext/reflex/screen.cpp +27 -1
  39. data/.doc/ext/reflex/scroll_event.cpp +1 -1
  40. data/.doc/ext/reflex/selector.cpp +1 -1
  41. data/.doc/ext/reflex/shape.cpp +1 -1
  42. data/.doc/ext/reflex/snap_constraint.cpp +1 -1
  43. data/.doc/ext/reflex/style.cpp +1 -1
  44. data/.doc/ext/reflex/style_length.cpp +1 -1
  45. data/.doc/ext/reflex/text_event.cpp +104 -0
  46. data/.doc/ext/reflex/timer.cpp +1 -1
  47. data/.doc/ext/reflex/timer_event.cpp +1 -1
  48. data/.doc/ext/reflex/update_event.cpp +1 -1
  49. data/.doc/ext/reflex/view.cpp +110 -56
  50. data/.doc/ext/reflex/wheel_constraint.cpp +1 -1
  51. data/.doc/ext/reflex/wheel_event.cpp +1 -1
  52. data/.doc/ext/reflex/window.cpp +226 -17
  53. data/.github/workflows/release-gem.yml +2 -49
  54. data/.github/workflows/tag.yml +5 -28
  55. data/.github/workflows/test.yml +1 -37
  56. data/ChangeLog.md +54 -0
  57. data/Gemfile.lock +13 -8
  58. data/Rakefile +13 -2
  59. data/Reflex.podspec +2 -2
  60. data/VERSION +1 -1
  61. data/ext/reflex/application.cpp +41 -6
  62. data/ext/reflex/capture_event.cpp +1 -1
  63. data/ext/reflex/chase_constraint.cpp +1 -1
  64. data/ext/reflex/clipboard.cpp +1 -1
  65. data/ext/reflex/color_event.cpp +80 -0
  66. data/ext/reflex/color_picker.cpp +121 -0
  67. data/ext/reflex/constraint.cpp +1 -1
  68. data/ext/reflex/contact_event.cpp +1 -1
  69. data/ext/reflex/control_change_event.cpp +1 -1
  70. data/ext/reflex/device.cpp +1 -1
  71. data/ext/reflex/device_event.cpp +1 -1
  72. data/ext/reflex/draw_event.cpp +1 -1
  73. data/ext/reflex/ellipse_shape.cpp +1 -1
  74. data/ext/reflex/event.cpp +1 -1
  75. data/ext/reflex/extconf.rb +4 -2
  76. data/ext/reflex/file_dialog.cpp +194 -0
  77. data/ext/reflex/file_event.cpp +108 -0
  78. data/ext/reflex/filter.cpp +1 -1
  79. data/ext/reflex/focus_event.cpp +1 -1
  80. data/ext/reflex/frame_event.cpp +1 -1
  81. data/ext/reflex/gamepad.cpp +50 -0
  82. data/ext/reflex/image_view.cpp +1 -1
  83. data/ext/reflex/key_event.cpp +1 -275
  84. data/ext/reflex/line_shape.cpp +1 -1
  85. data/ext/reflex/link_constraint.cpp +1 -1
  86. data/ext/reflex/menu.cpp +8 -7
  87. data/ext/reflex/midi.cpp +11 -3
  88. data/ext/reflex/midi_event.cpp +1 -1
  89. data/ext/reflex/motion_event.cpp +1 -1
  90. data/ext/reflex/native.cpp +18 -6
  91. data/ext/reflex/note_event.cpp +1 -1
  92. data/ext/reflex/pin.cpp +1 -1
  93. data/ext/reflex/pointer.cpp +1 -1
  94. data/ext/reflex/pointer_event.cpp +2 -2
  95. data/ext/reflex/polygon_shape.cpp +1 -1
  96. data/ext/reflex/rect_shape.cpp +1 -1
  97. data/ext/reflex/reflex.cpp +568 -232
  98. data/ext/reflex/screen.cpp +31 -2
  99. data/ext/reflex/scroll_event.cpp +1 -1
  100. data/ext/reflex/selector.cpp +1 -1
  101. data/ext/reflex/selector.h +9 -9
  102. data/ext/reflex/shape.cpp +1 -1
  103. data/ext/reflex/snap_constraint.cpp +1 -1
  104. data/ext/reflex/style.cpp +1 -1
  105. data/ext/reflex/style_length.cpp +1 -1
  106. data/ext/reflex/text_event.cpp +111 -0
  107. data/ext/reflex/timer.cpp +1 -1
  108. data/ext/reflex/timer_event.cpp +1 -1
  109. data/ext/reflex/update_event.cpp +1 -1
  110. data/ext/reflex/view.cpp +121 -61
  111. data/ext/reflex/wheel_constraint.cpp +1 -1
  112. data/ext/reflex/wheel_event.cpp +1 -1
  113. data/ext/reflex/window.cpp +256 -25
  114. data/include/reflex/application.h +10 -0
  115. data/include/reflex/color_picker.h +65 -0
  116. data/include/reflex/event.h +178 -88
  117. data/include/reflex/file_dialog.h +73 -0
  118. data/include/reflex/gamepad.h +3 -0
  119. data/include/reflex/menu.h +3 -3
  120. data/include/reflex/midi.h +3 -0
  121. data/include/reflex/reflex.h +2 -0
  122. data/include/reflex/ruby/application.h +6 -1
  123. data/include/reflex/ruby/color_picker.h +89 -0
  124. data/include/reflex/ruby/event.h +62 -29
  125. data/include/reflex/ruby/file_dialog.h +89 -0
  126. data/include/reflex/ruby/gamepad.h +46 -0
  127. data/include/reflex/ruby/reflex.h +3 -0
  128. data/include/reflex/ruby/view.h +92 -44
  129. data/include/reflex/ruby/window.h +60 -1
  130. data/include/reflex/ruby.h +3 -0
  131. data/include/reflex/screen.h +11 -2
  132. data/include/reflex/view.h +28 -16
  133. data/include/reflex/window.h +40 -8
  134. data/include/reflex.h +3 -0
  135. data/lib/reflex/application.rb +5 -5
  136. data/lib/reflex/autoinit.rb +3 -1
  137. data/lib/reflex/button.rb +3 -3
  138. data/lib/reflex/color_event.rb +16 -0
  139. data/lib/reflex/color_picker.rb +45 -0
  140. data/lib/reflex/control_change_event.rb +17 -0
  141. data/lib/reflex/file_dialog.rb +70 -0
  142. data/lib/reflex/file_event.rb +37 -0
  143. data/lib/reflex/helper.rb +58 -7
  144. data/lib/reflex/key_event.rb +9 -4
  145. data/lib/reflex/menu.rb +17 -1
  146. data/lib/reflex/model.rb +19 -19
  147. data/lib/reflex/note_event.rb +1 -1
  148. data/lib/reflex/pointer.rb +14 -3
  149. data/lib/reflex/pointer_event.rb +12 -1
  150. data/lib/reflex/reflex.rb +5 -0
  151. data/lib/reflex/shape.rb +14 -14
  152. data/lib/reflex/style.rb +16 -16
  153. data/lib/reflex/text_event.rb +40 -0
  154. data/lib/reflex/timer.rb +3 -3
  155. data/lib/reflex/view.rb +29 -14
  156. data/lib/reflex/wheel_event.rb +12 -3
  157. data/lib/reflex/window.rb +25 -13
  158. data/lib/reflex.rb +8 -2
  159. data/reflex.gemspec +4 -4
  160. data/samples/ime.rb +100 -0
  161. data/samples/ios/hello/hello.xcodeproj/project.pbxproj +236 -224
  162. data/samples/menu.rb +4 -1
  163. data/samples/model.rb +3 -3
  164. data/samples/test/alert.rb +93 -0
  165. data/samples/test/always_on.rb +76 -0
  166. data/samples/test/app_background.rb +51 -0
  167. data/samples/test/boundary.rb +75 -0
  168. data/samples/test/callback_exception.rb +101 -0
  169. data/samples/test/cancel.rb +53 -0
  170. data/samples/test/color_picker.rb +63 -0
  171. data/samples/test/file_dialog.rb +102 -0
  172. data/samples/window_style.rb +156 -0
  173. data/src/application.cpp +159 -18
  174. data/src/application.h +92 -7
  175. data/src/color_picker.cpp +113 -0
  176. data/src/color_picker.h +36 -0
  177. data/src/event.cpp +410 -252
  178. data/src/event.h +12 -0
  179. data/src/file_dialog.cpp +163 -0
  180. data/src/file_dialog.h +52 -0
  181. data/src/gamepad.cpp +42 -5
  182. data/src/gamepad.h +4 -0
  183. data/src/ios/app_delegate.mm +5 -3
  184. data/src/ios/application.mm +24 -0
  185. data/src/ios/color_picker.mm +19 -0
  186. data/src/ios/file_dialog.mm +21 -0
  187. data/src/ios/gamepad.mm +4 -4
  188. data/src/ios/menu.mm +5 -0
  189. data/src/ios/reflex.mm +8 -0
  190. data/src/ios/screen.mm +26 -0
  191. data/src/ios/view_controller.mm +2 -30
  192. data/src/ios/window.mm +38 -9
  193. data/src/menu.cpp +66 -4
  194. data/src/menu.h +17 -1
  195. data/src/midi.cpp +61 -31
  196. data/src/osx/app_delegate.h +4 -0
  197. data/src/osx/app_delegate.mm +102 -22
  198. data/src/osx/application.mm +88 -6
  199. data/src/osx/color_picker.mm +112 -0
  200. data/src/osx/event.h +10 -0
  201. data/src/osx/event.mm +84 -30
  202. data/src/osx/file_dialog.mm +168 -0
  203. data/src/osx/gamepad.mm +2 -2
  204. data/src/osx/gamepad_hid.mm +1 -1
  205. data/src/osx/menu.mm +177 -33
  206. data/src/osx/native_window.h +16 -2
  207. data/src/osx/native_window.mm +114 -57
  208. data/src/osx/opengl_view.h +2 -1
  209. data/src/osx/opengl_view.mm +184 -43
  210. data/src/osx/reflex.mm +38 -0
  211. data/src/osx/screen.mm +36 -0
  212. data/src/osx/window.mm +106 -24
  213. data/src/pointer.cpp +13 -4
  214. data/src/pointer.h +4 -0
  215. data/src/rays.h +46 -0
  216. data/src/sdl/application.cpp +68 -8
  217. data/src/sdl/color_picker.cpp +18 -0
  218. data/src/sdl/event.cpp +24 -3
  219. data/src/sdl/event.h +12 -0
  220. data/src/sdl/file_dialog.cpp +20 -0
  221. data/src/sdl/gamepad.cpp +3 -7
  222. data/src/sdl/menu.cpp +5 -0
  223. data/src/sdl/reflex.cpp +20 -0
  224. data/src/sdl/screen.cpp +36 -0
  225. data/src/sdl/window.cpp +142 -29
  226. data/src/shape.cpp +15 -10
  227. data/src/view.cpp +287 -198
  228. data/src/view.h +4 -2
  229. data/src/vk.h +416 -0
  230. data/src/win32/application.cpp +162 -12
  231. data/src/win32/application.h +20 -0
  232. data/src/win32/color_picker.cpp +82 -0
  233. data/src/win32/event.cpp +114 -12
  234. data/src/win32/event.h +21 -4
  235. data/src/win32/file_dialog.cpp +226 -0
  236. data/src/win32/gamepad.cpp +9 -2
  237. data/src/win32/menu.cpp +191 -53
  238. data/src/win32/menu.h +9 -1
  239. data/src/win32/opengl.cpp +2 -9
  240. data/src/win32/reflex.cpp +44 -3
  241. data/src/win32/screen.cpp +164 -3
  242. data/src/win32/screen.h +8 -0
  243. data/src/win32/tray.cpp +191 -0
  244. data/src/win32/tray.h +22 -0
  245. data/src/win32/vk.cpp +11 -0
  246. data/src/win32/window.cpp +809 -148
  247. data/src/win32/window.h +6 -0
  248. data/src/window.cpp +718 -185
  249. data/src/window.h +66 -33
  250. data/src/world.cpp +9 -1
  251. data/test/helper.rb +17 -0
  252. data/test/test_application.rb +90 -1
  253. data/test/test_chase_constraint.rb +1 -3
  254. data/test/test_color_event.rb +36 -0
  255. data/test/test_color_picker.rb +62 -0
  256. data/test/test_constraint.rb +2 -4
  257. data/test/test_event.rb +1 -1
  258. data/test/test_file_dialog.rb +48 -0
  259. data/test/test_file_event.rb +43 -0
  260. data/test/test_has_text_preedit.rb +54 -0
  261. data/test/test_key_event.rb +20 -5
  262. data/test/test_link_constraint.rb +1 -3
  263. data/test/test_menu.rb +40 -10
  264. data/test/test_pointer.rb +33 -23
  265. data/test/test_pointer_event.rb +24 -9
  266. data/test/test_reflex.rb +36 -0
  267. data/test/test_screen.rb +24 -2
  268. data/test/test_snap_constraint.rb +1 -3
  269. data/test/test_text_event.rb +54 -0
  270. data/test/test_view.rb +41 -4
  271. data/test/test_wheel_constraint.rb +1 -3
  272. data/test/test_wheel_event.rb +13 -5
  273. data/test/test_window.rb +196 -44
  274. metadata +80 -10
  275. data/.github/workflows/utils.rb +0 -127
@@ -0,0 +1,82 @@
1
+ #include "../color_picker.h"
2
+
3
+
4
+ #include <xot/windows.h>
5
+ #include <commdlg.h>
6
+ #include "reflex/exception.h"
7
+ #include "window.h"
8
+
9
+
10
+ namespace Reflex
11
+ {
12
+
13
+
14
+ // the custom color slots of the dialog live as long as the process
15
+ static COLORREF custom_colors[16] =
16
+ {
17
+ RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255),
18
+ RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255),
19
+ RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255),
20
+ RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255), RGB(255, 255, 255)
21
+ };
22
+
23
+
24
+ static BYTE
25
+ to_byte (float value)
26
+ {
27
+ if (value < 0) value = 0;
28
+ if (value > 1) value = 1;
29
+ return (BYTE) (value * 255 + 0.5f);
30
+ }
31
+
32
+ static COLORREF
33
+ to_colorref (const Color& color)
34
+ {
35
+ return RGB(to_byte(color.red), to_byte(color.green), to_byte(color.blue));
36
+ }
37
+
38
+ static Color
39
+ to_color (COLORREF colorref)
40
+ {
41
+ return Color(
42
+ GetRValue(colorref) / 255.f,
43
+ GetGValue(colorref) / 255.f,
44
+ GetBValue(colorref) / 255.f);
45
+ }
46
+
47
+ void
48
+ ColorPicker_show (ColorPicker* ppicker, const Color* initial)
49
+ {
50
+ if (!ppicker)
51
+ argument_error(__FILE__, __LINE__);
52
+
53
+ ColorPicker::Ref picker = ppicker;
54
+
55
+ Window* owner = picker->owner();
56
+ CHOOSECOLORW cc = {0};
57
+ cc.lStructSize = sizeof(cc);
58
+ cc.hwndOwner = owner ? Window_get_hwnd(owner) : NULL;
59
+ cc.lpCustColors = custom_colors;
60
+ cc.Flags = CC_FULLOPEN | CC_ANYCOLOR;
61
+ if (initial)
62
+ {
63
+ cc.rgbResult = to_colorref(*initial);
64
+ cc.Flags |= CC_RGBINIT;
65
+ }
66
+
67
+ // the dialog has no alpha, so the picked color always has alpha 1
68
+ BOOL picked = ChooseColorW(&cc);// runs a modal loop
69
+ if (picked)
70
+ {
71
+ ColorEvent e(to_color(cc.rgbResult));
72
+ ColorPicker_call_color_event(picker, &e);
73
+ }
74
+ else if (CommDlgExtendedError() != 0)
75
+ system_error(__FILE__, __LINE__);
76
+
77
+ Event e;
78
+ ColorPicker_call_close_event(picker, &e);
79
+ }
80
+
81
+
82
+ }// Reflex
data/src/win32/event.cpp CHANGED
@@ -1,6 +1,8 @@
1
1
  #include "event.h"
2
2
 
3
3
 
4
+ #include <string>
5
+ #include <vector>
4
6
  #include <xot/time.h>
5
7
  #include "reflex/exception.h"
6
8
  #include "reflex/debug.h"
@@ -42,6 +44,90 @@ namespace Reflex
42
44
  }
43
45
 
44
46
 
47
+ static std::wstring
48
+ get_composition_string (HIMC himc, DWORD index)
49
+ {
50
+ LONG size = ImmGetCompositionStringW(himc, index, NULL, 0);
51
+ if (size <= 0) return {};
52
+
53
+ std::wstring text(size / sizeof(wchar_t), L'\0');
54
+ ImmGetCompositionStringW(himc, index, text.data(), size);
55
+ return text;
56
+ }
57
+
58
+ static int
59
+ to_char_index (const std::wstring& str, size_t utf16_index)
60
+ {
61
+ size_t length = str.size();
62
+ if (utf16_index > length) utf16_index = length;
63
+
64
+ int index = 0;
65
+ for (size_t i = 0; i < utf16_index; ++i, ++index)
66
+ {
67
+ if (!IS_HIGH_SURROGATE(str[i]) || i + 1 >= length)
68
+ continue;
69
+
70
+ if (IS_LOW_SURROGATE(str[i + 1])) ++i;
71
+ }
72
+ return index;
73
+ }
74
+
75
+ static void
76
+ get_selection (
77
+ HIMC himc, const std::wstring& text, int* offset, int* size)
78
+ {
79
+ *offset = *size = 0;
80
+
81
+ LONG attr_size = ImmGetCompositionStringW(himc, GCS_COMPATTR, NULL, 0);
82
+ if (attr_size > 0)
83
+ {
84
+ std::vector<char> attrs(attr_size);
85
+ ImmGetCompositionStringW(himc, GCS_COMPATTR, attrs.data(), attr_size);
86
+
87
+ int begin = -1, end = 0;
88
+ for (LONG i = 0; i < attr_size; ++i)
89
+ {
90
+ if (
91
+ attrs[i] != ATTR_TARGET_CONVERTED &&
92
+ attrs[i] != ATTR_TARGET_NOTCONVERTED)
93
+ {
94
+ continue;
95
+ }
96
+
97
+ if (begin < 0) begin = (int) i;
98
+ end = (int) i + 1;
99
+ }
100
+
101
+ if (begin >= 0)
102
+ {
103
+ *offset = to_char_index(text, begin);
104
+ *size = to_char_index(text, end) - *offset;
105
+ return;
106
+ }
107
+ }
108
+
109
+ LONG pos = ImmGetCompositionStringW(himc, GCS_CURSORPOS, NULL, 0);
110
+ *offset = to_char_index(text, pos >= 0 ? (size_t) pos : text.size());
111
+ }
112
+
113
+ static TextEvent
114
+ to_text_event (TextEvent::Action action, HIMC himc, DWORD index)
115
+ {
116
+ std::wstring text = get_composition_string(himc, index);
117
+
118
+ int offset = -1, size = 0;
119
+ if (action == TextEvent::PREEDIT)
120
+ get_selection(himc, text, &offset, &size);
121
+
122
+ return TextEvent(action, String(text.c_str(), text.size()), offset, size);
123
+ }
124
+
125
+ NativeTextEvent::NativeTextEvent (Action action, HIMC himc, DWORD index)
126
+ : TextEvent(to_text_event(action, himc, index))
127
+ {
128
+ }
129
+
130
+
45
131
  static uint
46
132
  get_mouse_type (UINT msg, WPARAM wp)
47
133
  {
@@ -131,19 +217,20 @@ namespace Reflex
131
217
  }
132
218
  }
133
219
 
134
- NativePointerEvent::NativePointerEvent (UINT msg, WPARAM wp, LPARAM lp)
135
- : NativePointerEvent(msg, wp, lp, get_mouse_action(msg))
220
+ NativePointerEvent::NativePointerEvent (
221
+ const Window& window, UINT msg, WPARAM wp, LPARAM lp)
222
+ : NativePointerEvent(window, msg, wp, lp, get_mouse_action(msg))
136
223
  {
137
224
  }
138
225
 
139
226
  NativePointerEvent::NativePointerEvent (
140
- UINT msg, WPARAM wp, LPARAM lp, Pointer::Action action)
227
+ const Window& window, UINT msg, WPARAM wp, LPARAM lp, Pointer::Action action)
141
228
  {
142
229
  PointerEvent_add_pointer(this, Pointer(
143
230
  0,
144
231
  get_mouse_type(msg, wp),
145
232
  action,
146
- Point(GET_X_LPARAM(lp), GET_Y_LPARAM(lp)),
233
+ Window_from_native_coord(window, GET_X_LPARAM(lp), GET_Y_LPARAM(lp)),
147
234
  KeyEvent_get_modifiers(),
148
235
  get_mouse_click_count(msg),
149
236
  is_mouse_dragging(msg, wp),
@@ -168,19 +255,19 @@ namespace Reflex
168
255
  }
169
256
 
170
257
  static Point
171
- get_touch_position (HWND hwnd, const TOUCHINPUT& touch)
258
+ get_touch_position (const Window& window, const TOUCHINPUT& touch)
172
259
  {
173
260
  coord x = (coord) touch.x / 100;
174
261
  coord y = (coord) touch.y / 100;
175
262
 
176
263
  POINT point = {0, 0};
177
- if (ClientToScreen(hwnd, &point))
264
+ if (ClientToScreen(Window_get_hwnd(&window), &point))
178
265
  {
179
266
  x -= point.x;
180
267
  y -= point.y;
181
268
  }
182
269
 
183
- return Point(x, y);
270
+ return Window_from_native_coord(window, x, y);
184
271
  }
185
272
 
186
273
  static double
@@ -193,7 +280,7 @@ namespace Reflex
193
280
  }
194
281
 
195
282
  NativePointerEvent::NativePointerEvent (
196
- HWND hwnd, const TOUCHINPUT* touches, size_t size)
283
+ const Window& window, const TOUCHINPUT* touches, size_t size)
197
284
  {
198
285
  for (size_t i = 0; i < size; ++i)
199
286
  {
@@ -204,7 +291,7 @@ namespace Reflex
204
291
  0,
205
292
  get_touch_type(touch),
206
293
  action,
207
- get_touch_position(hwnd, touch),
294
+ get_touch_position(window, touch),
208
295
  KeyEvent_get_modifiers(),
209
296
  action == Pointer::DOWN ? 1 : 0,
210
297
  action == Pointer::MOVE,
@@ -217,10 +304,25 @@ namespace Reflex
217
304
  }
218
305
 
219
306
 
220
- NativeWheelEvent::NativeWheelEvent (WPARAM wp_x, WPARAM wp_y, LPARAM lp)
307
+ static Point
308
+ get_pointer_position (const Window& window, LPARAM lp)
309
+ {
310
+ POINT pos = {GET_X_LPARAM(lp), GET_Y_LPARAM(lp)};
311
+ ScreenToClient(Window_get_hwnd(&window), &pos);
312
+ return Window_from_native_coord(window, pos.x, pos.y);
313
+ }
314
+
315
+ static coord
316
+ to_wheel_pixels (WPARAM wp)
317
+ {
318
+ return (coord) GET_WHEEL_DELTA_WPARAM(wp) / WHEEL_DELTA * WHEEL_PIXELS_PER_NOTCH;
319
+ }
320
+
321
+ NativeWheelEvent::NativeWheelEvent (
322
+ const Window& window, WPARAM wp_x, WPARAM wp_y, LPARAM lp)
221
323
  : WheelEvent(
222
- GET_X_LPARAM(lp), GET_Y_LPARAM(lp), 0,
223
- GET_WHEEL_DELTA_WPARAM(wp_x), -GET_WHEEL_DELTA_WPARAM(wp_y), 0,
324
+ get_pointer_position(window, lp),
325
+ Point(to_wheel_pixels(wp_x), -to_wheel_pixels(wp_y), 0),
224
326
  KeyEvent_get_modifiers())
225
327
  {
226
328
  }
data/src/win32/event.h CHANGED
@@ -5,6 +5,8 @@
5
5
 
6
6
 
7
7
  #include <xot/windows.h>
8
+ #include <imm.h>
9
+
8
10
  #include "../event.h"
9
11
 
10
12
 
@@ -22,16 +24,31 @@ namespace Reflex
22
24
  };// NativeKeyEvent
23
25
 
24
26
 
27
+ class NativeTextEvent : public TextEvent
28
+ {
29
+
30
+ public:
31
+
32
+ NativeTextEvent (Action action, HIMC himc, DWORD index);
33
+
34
+ };// NativeTextEvent
35
+
36
+
37
+ class Window;
38
+
39
+
25
40
  class NativePointerEvent : public PointerEvent
26
41
  {
27
42
 
28
43
  public:
29
44
 
30
- NativePointerEvent (UINT msg, WPARAM wp, LPARAM lp);
45
+ NativePointerEvent (const Window& window, UINT msg, WPARAM wp, LPARAM lp);
31
46
 
32
- NativePointerEvent (UINT msg, WPARAM wp, LPARAM lp, Pointer::Action action);
47
+ NativePointerEvent (
48
+ const Window& window, UINT msg, WPARAM wp, LPARAM lp, Pointer::Action action);
33
49
 
34
- NativePointerEvent (HWND hwnd, const TOUCHINPUT* touches, size_t size);
50
+ NativePointerEvent (
51
+ const Window& window, const TOUCHINPUT* touches, size_t size);
35
52
 
36
53
  };// NativePointerEvent
37
54
 
@@ -41,7 +58,7 @@ namespace Reflex
41
58
 
42
59
  public:
43
60
 
44
- NativeWheelEvent (WPARAM wp_x, WPARAM wp_y, LPARAM lp);
61
+ NativeWheelEvent (const Window& window, WPARAM wp_x, WPARAM wp_y, LPARAM lp);
45
62
 
46
63
  };// NativeWheelEvent
47
64
 
@@ -0,0 +1,226 @@
1
+ #include "../file_dialog.h"
2
+
3
+
4
+ #include <wchar.h>
5
+ #include <string>
6
+ #include <xot/windows.h>
7
+ #include <shobjidl.h>
8
+ #include <xot/noncopyable.h>
9
+ #include "reflex/exception.h"
10
+ #include "window.h"
11
+
12
+
13
+ namespace Reflex
14
+ {
15
+
16
+
17
+ template <typename T>
18
+ struct ComPtr : public Xot::NonCopyable
19
+ {
20
+
21
+ T* ptr = NULL;
22
+
23
+ ~ComPtr () {if (ptr) ptr->Release();}
24
+
25
+ T* operator -> () {return ptr;}
26
+
27
+ operator bool () const {return ptr != NULL;}
28
+
29
+ };// ComPtr
30
+
31
+
32
+ static std::wstring
33
+ to_native_path (const char* path)
34
+ {
35
+ std::wstring result = String(path).to_wstr();
36
+ for (auto& c : result)
37
+ {
38
+ if (c == L'/') c = L'\\';
39
+ }
40
+ return result;
41
+ }
42
+
43
+ static String
44
+ from_native_path (PCWSTR path, size_t size)
45
+ {
46
+ String result(path, size);
47
+ for (auto& c : result)
48
+ {
49
+ if (c == '\\') c = '/';
50
+ }
51
+ return result;
52
+ }
53
+
54
+ static void
55
+ setup_options (IFileDialog* nativedialog, FileDialog::Data::Mode mode)
56
+ {
57
+ FILEOPENDIALOGOPTIONS options = 0;
58
+ if (FAILED(nativedialog->GetOptions(&options)))
59
+ system_error(__FILE__, __LINE__);
60
+
61
+ options |= FOS_FORCEFILESYSTEM;
62
+ if (mode == FileDialog::Data::OPEN_DIRECTORY) options |= FOS_PICKFOLDERS;
63
+ if (mode == FileDialog::Data::OPEN_FILES) options |= FOS_ALLOWMULTISELECT;
64
+
65
+ if (FAILED(nativedialog->SetOptions(options)))
66
+ system_error(__FILE__, __LINE__);
67
+ }
68
+
69
+ static void
70
+ setup_file_types (
71
+ std::wstring* joined,
72
+ IFileDialog* nativedialog, const FileDialog* dialog, FileDialog::Data::Mode mode)
73
+ {
74
+ if (mode == FileDialog::Data::OPEN_DIRECTORY)
75
+ return;
76
+
77
+ const StringList& extensions = dialog->extensions();
78
+ if (extensions.empty())
79
+ return;
80
+
81
+ for (const auto& extension : extensions)
82
+ {
83
+ if (!joined->empty()) *joined += L';';
84
+ *joined += ("*." + extension).to_wstr();
85
+ }
86
+
87
+ COMDLG_FILTERSPEC spec = {L"Files", joined->c_str()};
88
+ nativedialog->SetFileTypes(1, &spec);
89
+ }
90
+
91
+ static void
92
+ add_path (StringList* paths, IShellItem* item)
93
+ {
94
+ PWSTR wpath = NULL;
95
+ if (FAILED(item->GetDisplayName(SIGDN_FILESYSPATH, &wpath)) || !wpath)
96
+ return;
97
+
98
+ paths->emplace_back(from_native_path(wpath, wcslen(wpath)));
99
+ CoTaskMemFree(wpath);
100
+ }
101
+
102
+ static bool
103
+ is_missing_result (HRESULT hresult)
104
+ {
105
+ // closing the last window ends the modal loop of Show() with a WM_QUIT,
106
+ // and it answers S_OK though nothing was ever chosen. asking for the
107
+ // result then gives E_FAIL, which is this dialog being over, not an error
108
+ return hresult == E_FAIL;
109
+ }
110
+
111
+ static void
112
+ get_open_paths (StringList* paths, IFileOpenDialog* nativedialog)
113
+ {
114
+ ComPtr<IShellItemArray> items;
115
+ HRESULT result = nativedialog->GetResults(&items.ptr);
116
+ if (is_missing_result(result))
117
+ return;
118
+ if (FAILED(result) || !items)
119
+ system_error(__FILE__, __LINE__);
120
+
121
+ DWORD count = 0;
122
+ if (FAILED(items->GetCount(&count)))
123
+ system_error(__FILE__, __LINE__);
124
+
125
+ for (DWORD i = 0; i < count; ++i)
126
+ {
127
+ ComPtr<IShellItem> item;
128
+ if (FAILED(items->GetItemAt(i, &item.ptr)) || !item)
129
+ continue;
130
+
131
+ add_path(paths, item.ptr);
132
+ }
133
+ }
134
+
135
+ static void
136
+ get_save_path (StringList* paths, IFileDialog* nativedialog)
137
+ {
138
+ ComPtr<IShellItem> item;
139
+ HRESULT result = nativedialog->GetResult(&item.ptr);
140
+ if (is_missing_result(result))
141
+ return;
142
+ if (FAILED(result) || !item)
143
+ system_error(__FILE__, __LINE__);
144
+
145
+ add_path(paths, item.ptr);
146
+ }
147
+
148
+ static void
149
+ set_folder (IFileDialog* nativedialog, const char* dir)
150
+ {
151
+ // SetFolder overrides the folder the user last visited, so it is only
152
+ // called when a directory was explicitly given
153
+ ComPtr<IShellItem> item;
154
+ HRESULT result = SHCreateItemFromParsingName(
155
+ to_native_path(dir).c_str(), NULL, IID_IShellItem, (void**) &item.ptr);
156
+ if (SUCCEEDED(result) && item)
157
+ nativedialog->SetFolder(item.ptr);
158
+ }
159
+
160
+ void
161
+ FileDialog_show (
162
+ FileDialog* pdialog, FileDialog::Data::Mode mode,
163
+ const char* dir, const char* name)
164
+ {
165
+ if (!pdialog)
166
+ argument_error(__FILE__, __LINE__);
167
+
168
+ FileDialog::Ref dialog = pdialog;
169
+ bool save = mode == FileDialog::Data::SAVE_FILE;
170
+
171
+ ComPtr<IFileOpenDialog> opendialog;
172
+ ComPtr<IFileDialog> savedialog;
173
+ HRESULT result = CoCreateInstance(
174
+ save ? CLSID_FileSaveDialog : CLSID_FileOpenDialog,
175
+ NULL,
176
+ CLSCTX_INPROC_SERVER,
177
+ save ? IID_IFileDialog : IID_IFileOpenDialog,
178
+ save ? (void**) &savedialog.ptr : (void**) &opendialog.ptr);
179
+ if (FAILED(result))
180
+ system_error(__FILE__, __LINE__);
181
+
182
+ IFileDialog* nativedialog = save ? savedialog.ptr : (IFileDialog*) opendialog.ptr;
183
+ setup_options(nativedialog, mode);
184
+
185
+ std::wstring joined;// keeps the filter string alive until Show()
186
+ setup_file_types(&joined, nativedialog, dialog, mode);
187
+
188
+ const char* title = dialog->title();
189
+ if (*title)
190
+ nativedialog->SetTitle(String(title).to_wstr().c_str());
191
+
192
+ if (dir && *dir)
193
+ set_folder(nativedialog, dir);
194
+
195
+ if (save && name && *name)
196
+ nativedialog->SetFileName(String(name).to_wstr().c_str());
197
+
198
+ Window* owner = dialog->owner();
199
+ HWND hwnd = owner ? Window_get_hwnd(owner) : NULL;
200
+ result = nativedialog->Show(hwnd);// runs a modal loop
201
+
202
+ StringList paths;
203
+ if (SUCCEEDED(result))
204
+ {
205
+ if (save)
206
+ get_save_path(&paths, savedialog.ptr);
207
+ else
208
+ get_open_paths(&paths, opendialog.ptr);
209
+ }
210
+
211
+ if (!paths.empty())
212
+ {
213
+ FileEvent e(save ? FileEvent::SAVE : FileEvent::OPEN, paths);
214
+ FileDialog_call_file_event(dialog, &e);
215
+ }
216
+ else if (SUCCEEDED(result) || result == HRESULT_FROM_WIN32(ERROR_CANCELLED))
217
+ {
218
+ Event e;
219
+ FileDialog_call_cancel_event(dialog, &e);
220
+ }
221
+ else
222
+ system_error(__FILE__, __LINE__);
223
+ }
224
+
225
+
226
+ }// Reflex
@@ -72,20 +72,27 @@ namespace Reflex
72
72
  handle_gamepad_trigger_event(win, state.Gamepad.bRightTrigger, prev_state.Gamepad.bRightTrigger, KEY_GAMEPAD_RTRIGGER);
73
73
  }
74
74
 
75
+ static bool polling = false;
76
+
75
77
  void
76
- Gamepad_init (Application* app)
78
+ Gamepad_init_native (Application* app)
77
79
  {
80
+ polling = true;
78
81
  }
79
82
 
80
83
  void
81
- Gamepad_fin (Application* app)
84
+ Gamepad_fin_native (Application* app)
82
85
  {
86
+ polling = false;
87
+
83
88
  Gamepad_remove_all(app);
84
89
  }
85
90
 
86
91
  void
87
92
  Gamepad_poll ()
88
93
  {
94
+ if (!polling) return;
95
+
89
96
  static XINPUT_STATE prev_state;
90
97
  static bool prev_detected = false;
91
98