1 module ws.wm.win32.window;
2 
3 version(Windows):
4 
5 import
6 	std.conv,
7 	std.string,
8 	std.utf,
9 
10 	ws.string,
11 	ws.list,
12 	ws.gui.base,
13 	ws.draw,
14 	ws.wm.win32.api,
15 	ws.wm.win32.wm,
16 	ws.wm;
17 
18 __gshared:
19 
20 
21 class Win32Window: Base {
22 
23 	Mouse.cursor cursor = Mouse.cursor.inherit;
24 	string title;
25 	WindowHandle windowHandle;
26 	List!Event eventQueue;
27 
28 	int antiAliasing = 1;
29 	HDC deviceContext;
30 
31 	bool hasMouse;
32 	bool _hasFocus;
33 	Base _dragging;
34 	bool draggingUnfocus;
35 	int[2] _cursorPos;
36 
37 	bool isActive = true;
38 	DrawEmpty _draw;
39 
40 	this(WindowHandle handle){
41 		windowHandle = handle;
42 	}
43 
44 	this(int w, int h, string t){
45 		title = t;
46 		size = [w, h];
47 		RECT targetSize = {0, 0, size.w, size.h};
48 		AdjustWindowRect(&targetSize, WS_OVERLAPPEDWINDOW, false);
49 		windowHandle = CreateWindowExW(
50 			0, wm.windowClass.lpszClassName, title.toUTF16z(),
51 			WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
52 			targetSize.right-targetSize.left, targetSize.bottom-targetSize.top,
53 			null, null, wm.getInstance, null
54 		);
55 		if(!windowHandle)
56 			throw new Exception("CreateWindowW failed");
57 		RECT r;
58 		GetWindowRect(windowHandle, &r);
59 		pos = [r.left, r.right];
60 
61 		drawInit;
62 
63 		RAWINPUTDEVICE rawMouseDevice;
64 		rawMouseDevice.usUsagePage = 0x01; 
65 		rawMouseDevice.usUsage = 0x02;
66 		rawMouseDevice.hwndTarget = windowHandle;
67 		if(!RegisterRawInputDevices(&rawMouseDevice, 1, RAWINPUTDEVICE.sizeof))
68 			throw new Exception("Failed to register RID");
69 		
70 		if(GetFocus == windowHandle)
71 			onKeyboardFocus(true);
72 		
73 		hidden = true;
74 		show;
75 	}
76 
77 	override DrawEmpty draw(){
78 		return _draw;
79 	}
80 
81 	void draw(DrawEmpty draw){
82 		_draw = draw;
83 	}
84 
85 	@property
86 	WindowHandle handle(){
87 		return windowHandle;
88 	}
89 
90 	override void show(){
91 		if(!hidden)
92 			return;
93 		ShowWindow(windowHandle, SW_SHOWNORMAL);
94 		UpdateWindow(windowHandle);
95 		onKeyboardFocus(true);
96 		resized(size);
97 		super.show;
98 	}
99 
100 	override void hide(){
101 		if(hidden)
102 			return;
103 		DestroyWindow(windowHandle);
104 		super.hide;
105 	}
106 
107 	override void resize(int[2] size){
108 		SetWindowPos(windowHandle, null, 0, 0, size.w, size.h, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
109 	}
110 
111 	void onDestroy(){
112 		isActive = false;
113 		draw.destroy;
114 	}
115 
116 	override void onShow(){
117 		hidden = false;
118 		resized(size);
119 	}
120 
121 	void resized(int[2] size){
122 		this.size = size;
123 		if(draw)
124 			draw.resize(size);
125 	}
126 
127 	void setTitle(string title){
128 		this.title = title;
129 		SetWindowTextW(windowHandle, title.toUTF16z());
130 	}
131 
132 	string getTitle(){
133 		wchar[512] str;
134 		int r = GetWindowTextW(windowHandle, str.ptr, str.length);
135 		return to!string(str[0..r]);
136 	}
137 
138 	long getPid(){
139 		DWORD pid;
140 		DWORD threadId = GetWindowThreadProcessId(windowHandle, &pid);
141 		return pid;
142 	}
143 	
144 	@property
145 	override bool hasFocus(){
146 		return _hasFocus;
147 	}
148 	
149 	override void onKeyboardFocus(bool focus){
150 		_hasFocus = focus;
151 	}
152 
153 	void swapBuffers(){
154 		SwapBuffers(deviceContext);
155 	}
156 
157 	override void onDraw(){
158 		super.onDraw;
159 		draw.finishFrame;
160 	}
161 
162 	void onRawMouse(int x, int y){}
163 
164 	void setActive(){
165 		wm.activeWindow = this;
166 	}
167 
168 	override void setCursor(Mouse.cursor cursor){
169 		HCURSOR hcur = null;
170 		if(cursor != Mouse.cursor.none)
171 			hcur = LoadCursorW(null, cast(const(wchar)*)MOUSE_CURSOR_TO_HCUR[cast(int)cursor]);
172 		this.cursor = cursor;
173 		SetCursor(hcur);
174 		SetClassLongW(windowHandle, -12, cast(LONG)cast(LONG_PTR)hcur);
175 	}
176 
177 	void setCursorPos(int x, int y){
178 		POINT p = {cast(long)x, cast(long)y};
179 		ClientToScreen(windowHandle, &p);
180 		SetCursorPos(p.x, p.y);
181 	}
182 
183 
184 	void sendMessage(uint message, WPARAM wpar, LPARAM lpar){
185 		SendMessageA(windowHandle, message, wpar, lpar);
186 	}
187 
188 	/+
189 	void setTop(){
190 		SetForegroundWindow(windowHandle);
191 	}
192 	+/
193 
194 	void drawInit(){
195 		//_draw = new GlDraw;
196 	}
197 
198 	override int[2] cursorPos(){
199 		return _cursorPos;
200 	}
201 
202 	override Base draggingChild(){
203 		return _dragging;
204 	}
205 
206 	override void onMouseMove(int x, int y){
207 		_cursorPos = [x, y];
208 		super.onMouseMove(x, y);
209 	}
210 
211 	override void onMouseButton(Mouse.button button, bool pressed, int x, int y){
212 		if(button == Mouse.buttonLeft){
213 			if(pressed){
214 				auto child = mouseChild;
215 				while(child && child.mouseChild){
216 					child = child.mouseChild;
217 				}
218 				_dragging = child;
219 			}else{
220 				_dragging = null;
221 				if(draggingUnfocus){
222 					onMouseFocus(false);
223 				}
224 			}
225 		}
226 		super.onMouseButton(button, pressed, x, y);
227 	}
228 
229 }
230 
231 
232 string getLastError(){
233 	DWORD errcode = GetLastError();
234 	if(!errcode)
235 		return "No error";
236 	LPCSTR msgBuf;
237 	DWORD i = FormatMessageA(
238 		cast(uint)(
239 		FORMAT_MESSAGE_ALLOCATE_BUFFER |
240 		FORMAT_MESSAGE_FROM_SYSTEM |
241 		FORMAT_MESSAGE_IGNORE_INSERTS),
242 		null,
243 		errcode,
244 		cast(uint)MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
245 		cast(LPSTR)&msgBuf,
246 		0,
247 		null
248 	);
249 	string text = to!string(msgBuf);
250 	LocalFree(cast(HLOCAL)msgBuf);
251 	return text;
252 }