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.
- checksums.yaml +4 -4
- data/.doc/ext/reflex/application.cpp +19 -1
- data/.doc/ext/reflex/chase_constraint.cpp +84 -0
- data/.doc/ext/reflex/clipboard.cpp +65 -0
- data/.doc/ext/reflex/constraint.cpp +135 -0
- data/.doc/ext/reflex/key_event.cpp +6 -6
- data/.doc/ext/reflex/link_constraint.cpp +178 -0
- data/.doc/ext/reflex/menu.cpp +302 -0
- data/.doc/ext/reflex/native.cpp +22 -4
- data/.doc/ext/reflex/pin.cpp +156 -0
- data/.doc/ext/reflex/pointer.cpp +2 -0
- data/.doc/ext/reflex/pointer_event.cpp +1 -1
- data/.doc/ext/reflex/reflex.cpp +42 -7
- data/.doc/ext/reflex/selector.cpp +4 -4
- data/.doc/ext/reflex/snap_constraint.cpp +125 -0
- data/.doc/ext/reflex/style_length.cpp +3 -2
- data/.doc/ext/reflex/view.cpp +96 -23
- data/.doc/ext/reflex/wheel_constraint.cpp +142 -0
- data/.doc/ext/reflex/window.cpp +59 -17
- data/.github/workflows/release-gem.yml +10 -1
- data/.github/workflows/test.yml +9 -0
- data/ChangeLog.md +30 -0
- data/README.md +1 -0
- data/VERSION +1 -1
- data/ext/reflex/application.cpp +21 -1
- data/ext/reflex/chase_constraint.cpp +89 -0
- data/ext/reflex/clipboard.cpp +69 -0
- data/ext/reflex/constraint.cpp +146 -0
- data/ext/reflex/key_event.cpp +6 -6
- data/ext/reflex/link_constraint.cpp +194 -0
- data/ext/reflex/menu.cpp +330 -0
- data/ext/reflex/native.cpp +22 -4
- data/ext/reflex/pin.cpp +165 -0
- data/ext/reflex/pointer.cpp +2 -0
- data/ext/reflex/pointer_event.cpp +1 -1
- data/ext/reflex/reflex.cpp +42 -7
- data/ext/reflex/selector.cpp +4 -4
- data/ext/reflex/selector.h +1 -1
- data/ext/reflex/snap_constraint.cpp +135 -0
- data/ext/reflex/style_length.cpp +3 -2
- data/ext/reflex/view.cpp +117 -37
- data/ext/reflex/wheel_constraint.cpp +154 -0
- data/ext/reflex/window.cpp +65 -18
- data/include/reflex/application.h +9 -0
- data/include/reflex/clipboard.h +53 -0
- data/include/reflex/constraint.h +275 -0
- data/include/reflex/defs.h +204 -195
- data/include/reflex/event.h +2 -0
- data/include/reflex/menu.h +120 -0
- data/include/reflex/pin.h +68 -0
- data/include/reflex/pointer.h +4 -0
- data/include/reflex/ruby/clipboard.h +23 -0
- data/include/reflex/ruby/constraint.h +94 -0
- data/include/reflex/ruby/menu.h +103 -0
- data/include/reflex/ruby/pin.h +40 -0
- data/include/reflex/ruby/view.h +36 -0
- data/include/reflex/ruby/window.h +36 -18
- data/include/reflex/view.h +39 -12
- data/include/reflex/window.h +17 -4
- data/include/reflex.h +5 -0
- data/lib/reflex/chase_constraint.rb +15 -0
- data/lib/reflex/clipboard.rb +19 -0
- data/lib/reflex/constraint.rb +29 -0
- data/lib/reflex/extension.rb +1 -1
- data/lib/reflex/helper.rb +28 -0
- data/lib/reflex/key_event.rb +7 -12
- data/lib/reflex/link_constraint.rb +31 -0
- data/lib/reflex/menu.rb +76 -0
- data/lib/reflex/pin.rb +39 -0
- data/lib/reflex/pointer.rb +18 -0
- data/lib/reflex/pointer_event.rb +1 -1
- data/lib/reflex/snap_constraint.rb +28 -0
- data/lib/reflex/view.rb +56 -4
- data/lib/reflex/wheel_constraint.rb +28 -0
- data/lib/reflex/wheel_event.rb +9 -0
- data/lib/reflex.rb +15 -6
- data/pod.rake +4 -2
- data/reflex.gemspec +3 -3
- data/samples/constraint.rb +152 -0
- data/samples/menu.rb +29 -0
- data/src/application.cpp +21 -2
- data/src/application.h +5 -0
- data/src/clipboard.cpp +81 -0
- data/src/constraint.cpp +1662 -0
- data/src/constraint.h +64 -0
- data/src/event.cpp +7 -1
- data/src/event.h +1 -2
- data/src/ios/application.mm +5 -0
- data/src/ios/clipboard.mm +44 -0
- data/src/ios/event.h +6 -2
- data/src/ios/event.mm +31 -12
- data/src/ios/menu.mm +36 -0
- data/src/ios/view_controller.mm +45 -12
- data/src/ios/window.mm +6 -0
- data/src/menu.cpp +325 -0
- data/src/menu.h +65 -0
- data/src/osx/app_delegate.mm +74 -125
- data/src/osx/application.mm +16 -0
- data/src/osx/clipboard.mm +45 -0
- data/src/osx/event.mm +40 -10
- data/src/osx/menu.h +25 -0
- data/src/osx/menu.mm +372 -0
- data/src/osx/native_window.mm +27 -0
- data/src/osx/opengl_view.mm +51 -0
- data/src/osx/window.mm +11 -0
- data/src/pin.cpp +137 -0
- data/src/pointer.cpp +27 -16
- data/src/pointer.h +6 -0
- data/src/sdl/application.cpp +5 -0
- data/src/sdl/clipboard.cpp +39 -0
- data/src/sdl/event.cpp +20 -3
- data/src/sdl/event.h +6 -3
- data/src/sdl/menu.cpp +35 -0
- data/src/sdl/window.cpp +26 -8
- data/src/view.cpp +313 -52
- data/src/view.h +18 -2
- data/src/win32/application.cpp +5 -0
- data/src/win32/clipboard.cpp +210 -0
- data/src/win32/event.cpp +11 -1
- data/src/win32/event.h +2 -0
- data/src/win32/menu.cpp +352 -0
- data/src/win32/menu.h +27 -0
- data/src/win32/window.cpp +62 -0
- data/src/win32/window.h +3 -0
- data/src/window.cpp +235 -22
- data/src/window.h +13 -2
- data/src/world.cpp +77 -14
- data/src/world.h +9 -2
- data/test/helper.rb +7 -0
- data/test/test_application.rb +11 -0
- data/test/test_chase_constraint.rb +124 -0
- data/test/test_clipboard.rb +54 -0
- data/test/test_constraint.rb +186 -0
- data/test/test_key_event.rb +6 -0
- data/test/test_link_constraint.rb +239 -0
- data/test/test_menu.rb +207 -0
- data/test/test_pin.rb +65 -0
- data/test/test_pointer.rb +23 -9
- data/test/test_pointer_event.rb +1 -1
- data/test/test_snap_constraint.rb +142 -0
- data/test/test_view.rb +113 -23
- data/test/test_wheel_constraint.rb +127 -0
- data/test/test_wheel_event.rb +15 -9
- data/test/test_window.rb +10 -0
- 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
|
-
|
|
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
|
data/src/win32/menu.cpp
ADDED
|
@@ -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
|
{
|