1 module iota.etc.window;
2 
3 version (Windows) {
4 	import core.sys.windows.windows;
5 	import core.sys.windows.wtypes;
6 }
7 import std.utf : toUTF16z;
8 import std.algorithm.searching;
9 public import iota.etc.vers;
10 
11 public enum MessageWindowType {
12 	init,
13 }
14 /** 
15  * Implements Window handles for GUI apps.
16  */
17 version (Windows) {
18 	alias WindowH = HWND;
19 } else {
20 	alias WindowH = void*;
21 }
22 /** 
23  * Used for automatic reference counting for window handles.
24  */
25 public WindowH[] allAppWindows;
26 
27 shared static ~this() {
28 	foreach (WindowH w ; allAppWindows) {
29 		version (Windows)
30 			DestroyWindow(w);
31 	}
32 }
33 /** 
34  * Returns the handle of the currently active Window.
35  */
36 public WindowH getActiveWindowH() @nogc nothrow {
37 	version (Windows) {
38 		return GetActiveWindow();
39 	} else {
40 		return null;
41 	}
42 }
43 /** 
44  * Window style identifiers.
45  * These can be supplied to the createWindow function in an array, then the desired window will be created.
46  */
47 public enum WindowStyleIDs {
48 	Border,
49 	Caption,
50 	Child,
51 	Parent,
52 	Disabled,
53 	Resizable,
54 	Minimized,
55 	Maximized,
56 	MinimizeBtn,
57 	MaximizeBtn,
58 	PopUp,
59 	Visible,
60 	Default,
61 }
62 /** 
63  * Creates a window and returns its handle, while also saving its reference for later and to safe and automatic 
64  * deallocation.
65  * Params:
66  *   title = The title of the window.
67  *   x = X position of the window, or -1 for OS default.
68  *   y = Y position of the window, or -1 for OS default.
69  *   width = Width of the window, or -1 for OS default.
70  *   height = Height of the window, or -1 for OS default.
71  *   parent = Parent if there's any
72  *   styleIDs = Style identifiers, see enum `WindowStyleIDs` for details.
73  * Returns: The Window handle, or null if an error have happened.
74  * Note: Only some basic functionality can be accessed from here. More advanced functionality is out of scope of this
75  * library to minimize its complexity, and it's not supposed to be a GUI library. However, function `addWindow` will 
76  * add any window handle to the reference counting if needed.
77  */
78 public WindowH createWindow(io_str_t title, int x, int y, int width, int height, WindowH parent = null, 
79 		uint[] styleIDs = [WindowStyleIDs.Default]) {
80 	version (Windows) {
81 		LPCTSTR name = toUTF16z(title);
82 		WNDCLASSEXW clsReg;
83 		clsReg.cbSize = cast(UINT)WNDCLASSEXW.sizeof;
84 		clsReg.lpfnWndProc = &wndprocCallback;
85 		clsReg.lpszClassName = name;
86 		uint clsRegResult = RegisterClassExW(&clsReg);
87 		if (!clsRegResult) return null;
88 
89 
90 		DWORD flags;
91 		foreach (uint i ; styleIDs) {
92 			switch(i) {
93 				case WindowStyleIDs.Border:
94 					flags |= WS_BORDER;
95 					break;
96 				case WindowStyleIDs.Caption:
97 					flags |= WS_CAPTION;
98 					break;
99 				case WindowStyleIDs.Child:
100 					flags |= WS_CHILD;
101 					break;
102 				case WindowStyleIDs.Disabled:
103 					flags |= WS_DISABLED;
104 					break;
105 				case WindowStyleIDs.Resizable:
106 					flags |= WS_THICKFRAME;
107 					break;
108 				case WindowStyleIDs.Maximized:
109 					flags |= WS_MAXIMIZE;
110 					break;
111 				case WindowStyleIDs.Minimized:
112 					flags |= WS_MINIMIZE;
113 					break;
114 				case WindowStyleIDs.MaximizeBtn:
115 					flags |= WS_MAXIMIZEBOX | WS_SYSMENU;
116 					break;
117 				case WindowStyleIDs.MinimizeBtn:
118 					flags |= WS_MINIMIZEBOX | WS_SYSMENU;
119 					break;
120 				case WindowStyleIDs.PopUp:
121 					flags |= WS_POPUPWINDOW;
122 					break;
123 				case WindowStyleIDs.Visible:
124 					flags |= WS_VISIBLE;
125 					break;
126 				case WindowStyleIDs.Default:
127 					flags |= WS_TILEDWINDOW | WS_VISIBLE;
128 					break;
129 				default:
130 					break;
131 			}
132 		}
133 		if (x == -1) x = CW_USEDEFAULT;
134 		if (y == -1) y = CW_USEDEFAULT;
135 		if (width == -1) width = CW_USEDEFAULT;
136 		if (height == -1) height = CW_USEDEFAULT;
137 		WindowH handle; 
138 		
139 		handle = CreateWindowW(name, name, flags, x, y, width, height, parent, 
140 				null, null, null);
141 		if (handle)
142 			allAppWindows ~= handle;
143 		return handle;
144 	} else {
145 		return null;
146 	}
147 }
148 /** 
149  * Adds a non-library created window handle to its references to cooperation with the library.
150  * Params:
151  *   ext = The window handle that needs to be added.
152  * Returns: The reference, or null if either already added or an error happened.
153  */
154 public WindowH addWindowRef(WindowH ext) nothrow {
155 	try {
156 		if (!count(allAppWindows, ext)) {
157 			allAppWindows ~= ext;
158 			return ext;
159 		} else {
160 			return null;
161 		}
162 	} catch (Exception e) {		//The count function should not throw, but still let know the user that some error have happened
163 		return null;
164 	}
165 }
166 version (Windows) {
167 	///As of now, this works as a dummy function. If more functionality needed in the future, then it might become part
168 	///of a class.
169 	extern (Windows) LRESULT wndprocCallback(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) nothrow @system {
170 		return LRESULT.init;
171 	}
172 }