reflexion 0.5.2 → 0.6.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 (145) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/reflex/application.cpp +19 -1
  3. data/.doc/ext/reflex/chase_constraint.cpp +84 -0
  4. data/.doc/ext/reflex/clipboard.cpp +65 -0
  5. data/.doc/ext/reflex/constraint.cpp +135 -0
  6. data/.doc/ext/reflex/key_event.cpp +6 -6
  7. data/.doc/ext/reflex/link_constraint.cpp +178 -0
  8. data/.doc/ext/reflex/menu.cpp +302 -0
  9. data/.doc/ext/reflex/native.cpp +22 -4
  10. data/.doc/ext/reflex/pin.cpp +156 -0
  11. data/.doc/ext/reflex/pointer.cpp +2 -0
  12. data/.doc/ext/reflex/pointer_event.cpp +1 -1
  13. data/.doc/ext/reflex/reflex.cpp +42 -7
  14. data/.doc/ext/reflex/selector.cpp +4 -4
  15. data/.doc/ext/reflex/snap_constraint.cpp +125 -0
  16. data/.doc/ext/reflex/style_length.cpp +3 -2
  17. data/.doc/ext/reflex/view.cpp +96 -23
  18. data/.doc/ext/reflex/wheel_constraint.cpp +142 -0
  19. data/.doc/ext/reflex/window.cpp +59 -17
  20. data/.github/workflows/release-gem.yml +10 -1
  21. data/.github/workflows/test.yml +9 -0
  22. data/ChangeLog.md +30 -0
  23. data/README.md +1 -0
  24. data/VERSION +1 -1
  25. data/ext/reflex/application.cpp +21 -1
  26. data/ext/reflex/chase_constraint.cpp +89 -0
  27. data/ext/reflex/clipboard.cpp +69 -0
  28. data/ext/reflex/constraint.cpp +146 -0
  29. data/ext/reflex/key_event.cpp +6 -6
  30. data/ext/reflex/link_constraint.cpp +194 -0
  31. data/ext/reflex/menu.cpp +330 -0
  32. data/ext/reflex/native.cpp +22 -4
  33. data/ext/reflex/pin.cpp +165 -0
  34. data/ext/reflex/pointer.cpp +2 -0
  35. data/ext/reflex/pointer_event.cpp +1 -1
  36. data/ext/reflex/reflex.cpp +42 -7
  37. data/ext/reflex/selector.cpp +4 -4
  38. data/ext/reflex/selector.h +1 -1
  39. data/ext/reflex/snap_constraint.cpp +135 -0
  40. data/ext/reflex/style_length.cpp +3 -2
  41. data/ext/reflex/view.cpp +117 -37
  42. data/ext/reflex/wheel_constraint.cpp +154 -0
  43. data/ext/reflex/window.cpp +65 -18
  44. data/include/reflex/application.h +9 -0
  45. data/include/reflex/clipboard.h +53 -0
  46. data/include/reflex/constraint.h +275 -0
  47. data/include/reflex/defs.h +204 -195
  48. data/include/reflex/event.h +2 -0
  49. data/include/reflex/menu.h +120 -0
  50. data/include/reflex/pin.h +68 -0
  51. data/include/reflex/pointer.h +4 -0
  52. data/include/reflex/ruby/clipboard.h +23 -0
  53. data/include/reflex/ruby/constraint.h +94 -0
  54. data/include/reflex/ruby/menu.h +103 -0
  55. data/include/reflex/ruby/pin.h +40 -0
  56. data/include/reflex/ruby/view.h +36 -0
  57. data/include/reflex/ruby/window.h +36 -18
  58. data/include/reflex/view.h +39 -12
  59. data/include/reflex/window.h +17 -4
  60. data/include/reflex.h +5 -0
  61. data/lib/reflex/chase_constraint.rb +15 -0
  62. data/lib/reflex/clipboard.rb +19 -0
  63. data/lib/reflex/constraint.rb +29 -0
  64. data/lib/reflex/extension.rb +1 -1
  65. data/lib/reflex/helper.rb +28 -0
  66. data/lib/reflex/key_event.rb +7 -12
  67. data/lib/reflex/link_constraint.rb +31 -0
  68. data/lib/reflex/menu.rb +76 -0
  69. data/lib/reflex/pin.rb +39 -0
  70. data/lib/reflex/pointer.rb +18 -0
  71. data/lib/reflex/pointer_event.rb +1 -1
  72. data/lib/reflex/snap_constraint.rb +28 -0
  73. data/lib/reflex/view.rb +56 -4
  74. data/lib/reflex/wheel_constraint.rb +28 -0
  75. data/lib/reflex/wheel_event.rb +9 -0
  76. data/lib/reflex.rb +15 -6
  77. data/pod.rake +4 -2
  78. data/reflex.gemspec +3 -3
  79. data/samples/constraint.rb +152 -0
  80. data/samples/menu.rb +29 -0
  81. data/src/application.cpp +21 -2
  82. data/src/application.h +5 -0
  83. data/src/clipboard.cpp +81 -0
  84. data/src/constraint.cpp +1662 -0
  85. data/src/constraint.h +64 -0
  86. data/src/event.cpp +7 -1
  87. data/src/event.h +1 -2
  88. data/src/ios/application.mm +5 -0
  89. data/src/ios/clipboard.mm +44 -0
  90. data/src/ios/event.h +6 -2
  91. data/src/ios/event.mm +31 -12
  92. data/src/ios/menu.mm +36 -0
  93. data/src/ios/view_controller.mm +45 -12
  94. data/src/ios/window.mm +6 -0
  95. data/src/menu.cpp +325 -0
  96. data/src/menu.h +65 -0
  97. data/src/osx/app_delegate.mm +74 -125
  98. data/src/osx/application.mm +16 -0
  99. data/src/osx/clipboard.mm +45 -0
  100. data/src/osx/event.mm +40 -10
  101. data/src/osx/menu.h +25 -0
  102. data/src/osx/menu.mm +372 -0
  103. data/src/osx/native_window.mm +27 -0
  104. data/src/osx/opengl_view.mm +51 -0
  105. data/src/osx/window.mm +11 -0
  106. data/src/pin.cpp +137 -0
  107. data/src/pointer.cpp +27 -16
  108. data/src/pointer.h +6 -0
  109. data/src/sdl/application.cpp +5 -0
  110. data/src/sdl/clipboard.cpp +39 -0
  111. data/src/sdl/event.cpp +20 -3
  112. data/src/sdl/event.h +6 -3
  113. data/src/sdl/menu.cpp +35 -0
  114. data/src/sdl/window.cpp +26 -8
  115. data/src/view.cpp +313 -52
  116. data/src/view.h +18 -2
  117. data/src/win32/application.cpp +5 -0
  118. data/src/win32/clipboard.cpp +210 -0
  119. data/src/win32/event.cpp +11 -1
  120. data/src/win32/event.h +2 -0
  121. data/src/win32/menu.cpp +352 -0
  122. data/src/win32/menu.h +27 -0
  123. data/src/win32/window.cpp +62 -0
  124. data/src/win32/window.h +3 -0
  125. data/src/window.cpp +235 -22
  126. data/src/window.h +13 -2
  127. data/src/world.cpp +77 -14
  128. data/src/world.h +9 -2
  129. data/test/helper.rb +7 -0
  130. data/test/test_application.rb +11 -0
  131. data/test/test_chase_constraint.rb +124 -0
  132. data/test/test_clipboard.rb +54 -0
  133. data/test/test_constraint.rb +186 -0
  134. data/test/test_key_event.rb +6 -0
  135. data/test/test_link_constraint.rb +239 -0
  136. data/test/test_menu.rb +207 -0
  137. data/test/test_pin.rb +65 -0
  138. data/test/test_pointer.rb +23 -9
  139. data/test/test_pointer_event.rb +1 -1
  140. data/test/test_snap_constraint.rb +142 -0
  141. data/test/test_view.rb +113 -23
  142. data/test/test_wheel_constraint.rb +127 -0
  143. data/test/test_wheel_event.rb +15 -9
  144. data/test/test_window.rb +10 -0
  145. metadata +82 -8
@@ -0,0 +1,210 @@
1
+ #include "reflex/clipboard.h"
2
+
3
+
4
+ #include <string.h>
5
+ #include <wchar.h>
6
+ #include <xot/noncopyable.h>
7
+ #include <xot/windows.h>
8
+ #include "reflex/exception.h"
9
+
10
+
11
+ namespace Reflex
12
+ {
13
+
14
+
15
+ class ClipboardLock : public Xot::NonCopyable
16
+ {
17
+
18
+ enum
19
+ {
20
+
21
+ RETRY_COUNT = 3,
22
+
23
+ RETRY_INTERVAL = 30// milliseconds
24
+
25
+ };
26
+
27
+ public:
28
+
29
+ ClipboardLock ()
30
+ : opened(false)
31
+ {
32
+ // OpenClipboard fails while another process has the clipboard open
33
+ for (int i = 0; i < RETRY_COUNT; ++i)
34
+ {
35
+ if (i > 0) Sleep(RETRY_INTERVAL);
36
+
37
+ opened = OpenClipboard(NULL) != FALSE;
38
+ if (opened) break;
39
+ }
40
+ }
41
+
42
+ ~ClipboardLock ()
43
+ {
44
+ if (opened) CloseClipboard();
45
+ }
46
+
47
+ operator bool () const
48
+ {
49
+ return opened;
50
+ }
51
+
52
+ private:
53
+
54
+ bool opened;
55
+
56
+ };// ClipboardLock
57
+
58
+
59
+ class GlobalMemory : public Xot::NonCopyable
60
+ {
61
+
62
+ public:
63
+
64
+ GlobalMemory (HGLOBAL handle, bool owner = false)
65
+ : handle(handle), owner(owner), pointer(NULL)
66
+ {
67
+ }
68
+
69
+ ~GlobalMemory ()
70
+ {
71
+ unlock();
72
+ if (handle && owner) GlobalFree(handle);
73
+ }
74
+
75
+ void* lock ()
76
+ {
77
+ if (!pointer && handle) pointer = GlobalLock(handle);
78
+ return pointer;
79
+ }
80
+
81
+ void unlock ()
82
+ {
83
+ if (!pointer) return;
84
+ GlobalUnlock(handle);
85
+ pointer = NULL;
86
+ }
87
+
88
+ HGLOBAL release ()
89
+ {
90
+ owner = false;
91
+ return handle;
92
+ }
93
+
94
+ HGLOBAL get () const
95
+ {
96
+ return handle;
97
+ }
98
+
99
+ operator bool () const
100
+ {
101
+ return handle != NULL;
102
+ }
103
+
104
+ private:
105
+
106
+ HGLOBAL handle;
107
+
108
+ bool owner;
109
+
110
+ void* pointer;
111
+
112
+ };// GlobalMemory
113
+
114
+
115
+ static String
116
+ to_crlf (const char* text)
117
+ {
118
+ String result;
119
+ for (const char* p = text; *p; ++p)
120
+ {
121
+ if (*p == '\r' || *p == '\n')
122
+ {
123
+ result += "\r\n";
124
+ if (*p == '\r' && *(p + 1) == '\n') ++p;
125
+ continue;
126
+ }
127
+ result += *p;
128
+ }
129
+ return result;
130
+ }
131
+
132
+ static String
133
+ to_lf (const String& text)
134
+ {
135
+ size_t size = text.size();
136
+ String result;
137
+ result.reserve(size);
138
+ for (size_t i = 0; i < size; ++i)
139
+ {
140
+ char c = text[i];
141
+ if (c == '\r')
142
+ {
143
+ if ((i + 1) < size && text[i + 1] == '\n') continue;
144
+ c = '\n';
145
+ }
146
+ result += c;
147
+ }
148
+ return result;
149
+ }
150
+
151
+ static HGLOBAL
152
+ create_text_handle (const char* text)
153
+ {
154
+ std::wstring wtext = to_crlf(text).to_wstr();
155
+ size_t size = (wtext.size() + 1) * sizeof(wchar_t);
156
+
157
+ GlobalMemory mem(GlobalAlloc(GMEM_MOVEABLE, size), true);
158
+ if (!mem)
159
+ system_error(__FILE__, __LINE__);
160
+
161
+ void* buffer = mem.lock();
162
+ if (!buffer)
163
+ system_error(__FILE__, __LINE__);
164
+
165
+ memcpy(buffer, wtext.c_str(), size);
166
+ mem.unlock();
167
+
168
+ return mem.release();
169
+ }
170
+
171
+ void
172
+ set_clipboard (const Clipboard& clipboard)
173
+ {
174
+ const char* text = clipboard.text();
175
+ GlobalMemory textmem(text ? create_text_handle(text) : NULL, true);
176
+
177
+ ClipboardLock lock;
178
+ if (!lock)
179
+ system_error(__FILE__, __LINE__);
180
+
181
+ if (!EmptyClipboard())
182
+ system_error(__FILE__, __LINE__);
183
+
184
+ if (textmem)
185
+ {
186
+ if (!SetClipboardData(CF_UNICODETEXT, textmem.get()))
187
+ system_error(__FILE__, __LINE__);
188
+ textmem.release();
189
+ }
190
+ }
191
+
192
+ Clipboard
193
+ get_clipboard ()
194
+ {
195
+ ClipboardLock lock;
196
+ if (!lock)
197
+ system_error(__FILE__, __LINE__);
198
+
199
+ Clipboard clipboard;
200
+
201
+ GlobalMemory textmem(GetClipboardData(CF_UNICODETEXT));
202
+ const wchar_t* text = (const wchar_t*) textmem.lock();
203
+ if (text)
204
+ clipboard.set_text(to_lf(String(text, wcslen(text))).c_str());
205
+
206
+ return clipboard;
207
+ }
208
+
209
+
210
+ }// Reflex
data/src/win32/event.cpp CHANGED
@@ -68,6 +68,7 @@ namespace Reflex
68
68
  break;
69
69
 
70
70
  case WM_MOUSEMOVE:
71
+ case WM_MOUSELEAVE:
71
72
  type |= Reflex::Pointer::MOUSE;
72
73
  break;
73
74
  }
@@ -96,6 +97,9 @@ namespace Reflex
96
97
  case WM_MOUSEMOVE:
97
98
  return Reflex::Pointer::MOVE;
98
99
 
100
+ case WM_MOUSELEAVE:
101
+ return Reflex::Pointer::LEAVE;
102
+
99
103
  default:
100
104
  return Reflex::Pointer::ACTION_NONE;
101
105
  }
@@ -128,11 +132,17 @@ namespace Reflex
128
132
  }
129
133
 
130
134
  NativePointerEvent::NativePointerEvent (UINT msg, WPARAM wp, LPARAM lp)
135
+ : NativePointerEvent(msg, wp, lp, get_mouse_action(msg))
136
+ {
137
+ }
138
+
139
+ NativePointerEvent::NativePointerEvent (
140
+ UINT msg, WPARAM wp, LPARAM lp, Pointer::Action action)
131
141
  {
132
142
  PointerEvent_add_pointer(this, Pointer(
133
143
  0,
134
144
  get_mouse_type(msg, wp),
135
- get_mouse_action(msg),
145
+ action,
136
146
  Point(GET_X_LPARAM(lp), GET_Y_LPARAM(lp)),
137
147
  KeyEvent_get_modifiers(),
138
148
  get_mouse_click_count(msg),
data/src/win32/event.h CHANGED
@@ -29,6 +29,8 @@ namespace Reflex
29
29
 
30
30
  NativePointerEvent (UINT msg, WPARAM wp, LPARAM lp);
31
31
 
32
+ NativePointerEvent (UINT msg, WPARAM wp, LPARAM lp, Pointer::Action action);
33
+
32
34
  NativePointerEvent (HWND hwnd, const TOUCHINPUT* touches, size_t size);
33
35
 
34
36
  };// NativePointerEvent
@@ -0,0 +1,352 @@
1
+ #include "menu.h"
2
+
3
+
4
+ #include "reflex/exception.h"
5
+ #include "reflex/event.h"
6
+ #include "reflex/view.h"
7
+ #include "window.h"
8
+
9
+
10
+ namespace Rays
11
+ {
12
+ HBITMAP Bitmap_get_hbitmap (const Bitmap& bmp);
13
+ }
14
+
15
+
16
+ namespace Reflex
17
+ {
18
+
19
+
20
+ static UINT
21
+ next_menu_id ()
22
+ {
23
+ static UINT id = 100;
24
+ return id++;
25
+ }
26
+
27
+ static HMENU
28
+ create_hmenu (Menu* menu, bool menubar)
29
+ {
30
+ HMENU hmenu = menubar ? CreateMenu() : CreatePopupMenu();
31
+ if (!hmenu)
32
+ system_error(__FILE__, __LINE__);
33
+
34
+ MENUINFO mi = {sizeof(mi)};
35
+ mi.fMask = MIM_MENUDATA | MIM_STYLE;
36
+ mi.dwMenuData = (ULONG_PTR) menu;
37
+ mi.dwStyle = MNS_NOTIFYBYPOS;
38
+ SetMenuInfo(hmenu, &mi);
39
+
40
+ return hmenu;
41
+ }
42
+
43
+ static void
44
+ destroy_hmenu (HMENU hmenu)
45
+ {
46
+ if (!hmenu || !IsMenu(hmenu)) return;
47
+
48
+ while (GetMenuItemCount(hmenu) > 0)
49
+ RemoveMenu(hmenu, 0, MF_BYPOSITION);
50
+
51
+ DestroyMenu(hmenu);
52
+ }
53
+
54
+
55
+ struct MenuData : public Menu::Data
56
+ {
57
+
58
+ UINT id = next_menu_id();
59
+
60
+ HMENU hparent = NULL;
61
+
62
+ HMENU hsubmenu = NULL;
63
+
64
+ bool menubar = false;
65
+
66
+ Image image;
67
+
68
+ std::shared_ptr<HBITMAP__> hbitmap;
69
+
70
+ virtual ~MenuData ()
71
+ {
72
+ destroy_hmenu(hsubmenu);
73
+ }
74
+
75
+ HMENU get_hsubmenu (Menu* menu, bool menubar = false);
76
+
77
+ HBITMAP get_hbitmap (const Image& image)
78
+ {
79
+ if (image != this->image)
80
+ {
81
+ this->image = image;
82
+ if (image)
83
+ hbitmap.reset(Rays::Bitmap_get_hbitmap(image.bitmap()), DeleteObject);
84
+ else
85
+ hbitmap.reset();
86
+ }
87
+ return hbitmap.get();
88
+ }
89
+
90
+ };// MenuData
91
+
92
+
93
+ static MenuData&
94
+ get_data (Menu* menu)
95
+ {
96
+ if (!menu)
97
+ argument_error(__FILE__, __LINE__);
98
+
99
+ return (MenuData&) *menu->self;
100
+ }
101
+
102
+ static Menu*
103
+ get_item_owner (HMENU hparent, uint index)
104
+ {
105
+ if (!hparent) return NULL;
106
+
107
+ MENUITEMINFO mii = {sizeof(mii)};
108
+ mii.fMask = MIIM_DATA;
109
+ if (!GetMenuItemInfo(hparent, index, TRUE, &mii))
110
+ return NULL;
111
+
112
+ return (Menu*) mii.dwItemData;
113
+ }
114
+
115
+ static Menu*
116
+ get_submenu_owner (HMENU hsubmenu)
117
+ {
118
+ if (!hsubmenu) return NULL;
119
+
120
+ MENUINFO mi = {sizeof(mi)};
121
+ mi.fMask = MIM_MENUDATA;
122
+ if (!GetMenuInfo(hsubmenu, &mi))
123
+ return NULL;
124
+
125
+ return (Menu*) mi.dwMenuData;
126
+ }
127
+
128
+ static void
129
+ insert_item (HMENU hparent, Menu* item, int index)
130
+ {
131
+ MenuData& self = get_data(item);
132
+
133
+ MENUITEMINFO mii = {sizeof(mii)};
134
+ mii.fMask = MIIM_ID | MIIM_DATA | MIIM_FTYPE | MIIM_STRING;
135
+ mii.fType = MFT_STRING;
136
+ mii.wID = self.id;
137
+ mii.dwItemData = (ULONG_PTR) item;
138
+ mii.dwTypeData = (LPSTR) "";
139
+
140
+ if (!InsertMenuItem(hparent, (UINT) index, TRUE, &mii))
141
+ system_error(__FILE__, __LINE__);
142
+
143
+ self.hparent = hparent;
144
+
145
+ Menu_update(item);
146
+ }
147
+
148
+ Menu::Data*
149
+ Menu_create_data ()
150
+ {
151
+ return new MenuData();
152
+ }
153
+
154
+ static String
155
+ make_item_string (const Menu* menu)
156
+ {
157
+ String s = menu->label();
158
+ const char* key = menu->shortcut_key();
159
+ if (key && *key)
160
+ {
161
+ s += '\t';
162
+ uint mods = menu->shortcut_modifiers();
163
+ if (mods & MOD_CONTROL) s += "Ctrl+";
164
+ if (mods & MOD_SHIFT) s += "Shift+";
165
+ if (mods & (MOD_ALT | MOD_OPTION)) s += "Alt+";
166
+ s += key;
167
+ }
168
+ return s;
169
+ }
170
+
171
+ void
172
+ Menu_update (Menu* menu)
173
+ {
174
+ MenuData& self = get_data(menu);
175
+
176
+ if (!self.hparent) return;
177
+
178
+ MENUITEMINFO mii = {sizeof(mii)};
179
+ mii.fMask =
180
+ MIIM_ID | MIIM_DATA | MIIM_FTYPE | MIIM_STATE | MIIM_BITMAP | MIIM_SUBMENU;
181
+ mii.wID = self.id;
182
+ mii.dwItemData = (ULONG_PTR) menu;
183
+
184
+ String label;
185
+ if (menu->is_separator())
186
+ mii.fType = MFT_SEPARATOR;
187
+ else
188
+ {
189
+ label = make_item_string(menu);
190
+
191
+ mii.fMask |= MIIM_STRING;
192
+ mii.fType = MFT_STRING;
193
+ mii.dwTypeData = (LPSTR) label.c_str();
194
+ mii.fState =
195
+ (menu->is_enabled() ? MFS_ENABLED : MFS_GRAYED) |
196
+ (menu->is_checked() ? MFS_CHECKED : MFS_UNCHECKED);
197
+ mii.hbmpItem = self.get_hbitmap(menu->image());
198
+ mii.hSubMenu = menu->empty() ? NULL : self.hsubmenu;
199
+ }
200
+
201
+ SetMenuItemInfo(self.hparent, self.id, FALSE, &mii);
202
+ }
203
+
204
+ void
205
+ Menu_popup (Menu* menu, View* view, coord x, coord y)
206
+ {
207
+ MenuData& self = get_data(menu);
208
+
209
+ HMENU hmenu = self.get_hsubmenu(menu, false);
210
+ if (!hmenu)
211
+ invalid_state_error(__FILE__, __LINE__);
212
+
213
+ HWND hwnd = NULL;
214
+ POINT pos = {(int) x, (int) y};
215
+
216
+ if (view)
217
+ {
218
+ Window* win = view->window();
219
+ if (!win)
220
+ invalid_state_error(__FILE__, __LINE__);
221
+
222
+ hwnd = Window_get_hwnd(win);
223
+ if (!hwnd)
224
+ invalid_state_error(__FILE__, __LINE__);
225
+
226
+ Point p = view->to_window(Point(x, y));
227
+ pos.x = (int) p.x;
228
+ pos.y = (int) p.y;
229
+ ClientToScreen(hwnd, &pos);
230
+ }
231
+ else
232
+ hwnd = GetActiveWindow();
233
+
234
+ if (!hwnd) return;
235
+
236
+ // TrackPopupMenu needs the owner window in the foreground, and the
237
+ // trailing WM_NULL is the documented workaround for the menu not closing
238
+ // on the first outside click.
239
+ SetForegroundWindow(hwnd);
240
+ TrackPopupMenu(
241
+ hmenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON,
242
+ pos.x, pos.y, 0, hwnd, NULL);
243
+ PostMessage(hwnd, WM_NULL, 0, 0);
244
+ }
245
+
246
+ void
247
+ Menu_child_added (Menu* parent, Menu* child, int index)
248
+ {
249
+ MenuData& c = get_data(child);
250
+
251
+ if (c.hparent)
252
+ invalid_state_error(__FILE__, __LINE__);
253
+
254
+ insert_item(get_data(parent).get_hsubmenu(parent), child, index);
255
+ }
256
+
257
+ void
258
+ Menu_child_removed (Menu* parent, Menu* child)
259
+ {
260
+ MenuData& p = get_data(parent);
261
+ MenuData& c = get_data(child);
262
+
263
+ if (!p.hsubmenu)
264
+ invalid_state_error(__FILE__, __LINE__);
265
+ if (c.hparent != p.hsubmenu)
266
+ invalid_state_error(__FILE__, __LINE__);
267
+
268
+ RemoveMenu(p.hsubmenu, c.id, MF_BYCOMMAND);
269
+ c.hparent = NULL;
270
+ }
271
+
272
+ HMENU
273
+ Menu_get_hmenu (Menu* menu)
274
+ {
275
+ return menu ? get_data(menu).get_hsubmenu(menu, true) : NULL;
276
+ }
277
+
278
+ void
279
+ Menu_call_command_event (HMENU hmenu, uint index)
280
+ {
281
+ Menu* menu = get_item_owner(hmenu, index);
282
+ if (!menu) return;
283
+
284
+ Event e;
285
+ menu->on_click(&e);
286
+ }
287
+
288
+ void
289
+ Menu_call_open_event (HMENU hmenu)
290
+ {
291
+ Menu* menu = get_submenu_owner(hmenu);
292
+ if (!menu) return;
293
+
294
+ Event e;
295
+ menu->on_open_submenu(&e);
296
+
297
+ int count = GetMenuItemCount(hmenu);
298
+ for (int i = 0; i < count; ++i)
299
+ {
300
+ Menu* child = get_item_owner(hmenu, i);
301
+ if (!child) continue;
302
+
303
+ Event ce;
304
+ child->on_show(&ce);
305
+ }
306
+ }
307
+
308
+ void
309
+ Menu_call_close_event (HMENU hmenu)
310
+ {
311
+ Menu* menu = get_submenu_owner(hmenu);
312
+ if (!menu) return;
313
+
314
+ int count = GetMenuItemCount(hmenu);
315
+ for (int i = 0; i < count; ++i)
316
+ {
317
+ Menu* child = get_item_owner(hmenu, i);
318
+ if (!child) continue;
319
+
320
+ Event ce;
321
+ child->on_hide(&ce);
322
+ }
323
+
324
+ Event e;
325
+ menu->on_close_submenu(&e);
326
+ }
327
+
328
+
329
+ HMENU
330
+ MenuData::get_hsubmenu (Menu* menu, bool menubar)
331
+ {
332
+ if (!hsubmenu)
333
+ {
334
+ hsubmenu = create_hmenu(menu, menubar);
335
+ this->menubar = menubar;
336
+ }
337
+ else if (menubar != this->menubar)
338
+ {
339
+ HMENU old = hsubmenu;
340
+ hsubmenu = create_hmenu(menu, menubar);
341
+ this->menubar = menubar;
342
+
343
+ int index = 0;
344
+ for (auto it = menu->begin(); it != menu->end(); ++it, ++index)
345
+ insert_item(hsubmenu, it->get(), index);
346
+ destroy_hmenu(old);
347
+ }
348
+ return hsubmenu;
349
+ }
350
+
351
+
352
+ }// Reflex
data/src/win32/menu.h ADDED
@@ -0,0 +1,27 @@
1
+ // -*- c++ -*-
2
+ #pragma once
3
+ #ifndef __REFLEX_SRC_WIN32_MENU_H__
4
+ #define __REFLEX_SRC_WIN32_MENU_H__
5
+
6
+
7
+ #include <xot/windows.h>
8
+ #include "../menu.h"
9
+
10
+
11
+ namespace Reflex
12
+ {
13
+
14
+
15
+ HMENU Menu_get_hmenu (Menu* menu);
16
+
17
+ void Menu_call_command_event (HMENU hmenu, uint index);
18
+
19
+ void Menu_call_open_event (HMENU hmenu);
20
+
21
+ void Menu_call_close_event (HMENU hmenu);
22
+
23
+
24
+ }// Reflex
25
+
26
+
27
+ #endif//EOH
data/src/win32/window.cpp CHANGED
@@ -15,6 +15,7 @@
15
15
  #include "gamepad.h"
16
16
  #include "screen.h"
17
17
  #include "opengl.h"
18
+ #include "menu.h"
18
19
 
19
20
 
20
21
  namespace Reflex
@@ -36,6 +37,8 @@ namespace Reflex
36
37
 
37
38
  bool need_rebind = false;
38
39
 
40
+ bool tracking_mouse = false;
41
+
39
42
  OpenGLContext context;
40
43
 
41
44
  PressingKeyMap pressing_keys;
@@ -305,6 +308,28 @@ namespace Reflex
305
308
  {
306
309
  if (is_from_touch_event()) return;
307
310
 
311
+ WindowData* self = get_data(win);
312
+
313
+ if (msg == WM_MOUSEMOVE && !self->tracking_mouse)
314
+ {
315
+ TRACKMOUSEEVENT tme = {sizeof(tme), TME_LEAVE, self->hwnd, 0};
316
+ TrackMouseEvent(&tme);
317
+ self->tracking_mouse = true;
318
+
319
+ // Win32 has no mouse-enter message; the first move after (re)arming
320
+ // the leave tracking is when the mouse entered the window.
321
+ NativePointerEvent e(msg, wp, lp, Pointer::ENTER);
322
+ Window_call_pointer_event(win, &e);
323
+ }
324
+ else if (msg == WM_MOUSELEAVE)
325
+ {
326
+ self->tracking_mouse = false;
327
+
328
+ POINT pt;
329
+ if (GetCursorPos(&pt) && ScreenToClient(self->hwnd, &pt))
330
+ lp = MAKELPARAM(pt.x, pt.y);
331
+ }
332
+
308
333
  NativePointerEvent e(msg, wp, lp);
309
334
  Window_call_pointer_event(win, &e);
310
335
  }
@@ -384,6 +409,24 @@ namespace Reflex
384
409
  return 0;
385
410
  }
386
411
 
412
+ case WM_MENUCOMMAND:
413
+ {
414
+ Menu_call_command_event((HMENU) lp, (uint) wp);
415
+ return 0;
416
+ }
417
+
418
+ case WM_INITMENUPOPUP:
419
+ {
420
+ Menu_call_open_event((HMENU) wp);
421
+ break;
422
+ }
423
+
424
+ case WM_UNINITMENUPOPUP:
425
+ {
426
+ Menu_call_close_event((HMENU) wp);
427
+ break;
428
+ }
429
+
387
430
  case WM_PAINT:
388
431
  {
389
432
  self->context.make_current();
@@ -440,6 +483,7 @@ namespace Reflex
440
483
  case WM_RBUTTONUP:
441
484
  case WM_MBUTTONUP:
442
485
  case WM_MOUSEMOVE:
486
+ case WM_MOUSELEAVE:
443
487
  {
444
488
  mouse(win, msg, wp, lp);
445
489
  break;
@@ -707,6 +751,24 @@ namespace Reflex
707
751
  return Bounds(x, y, w, h);
708
752
  }
709
753
 
754
+ HWND
755
+ Window_get_hwnd (const Window* window)
756
+ {
757
+ if (!window) return NULL;
758
+
759
+ return get_data(window)->hwnd;
760
+ }
761
+
762
+ void
763
+ Window_set_menu (Window* window, Menu* menu)
764
+ {
765
+ HWND hwnd = get_data(window)->hwnd;
766
+ if (!hwnd) return;
767
+
768
+ SetMenu(hwnd, menu ? Menu_get_hmenu(menu) : NULL);
769
+ DrawMenuBar(hwnd);
770
+ }
771
+
710
772
  Screen
711
773
  Window_get_screen (const Window& window)
712
774
  {