1 // Written by Christopher E. Miller
2 // See the included license.txt for copyright and license details.
3 
4 
5 ///
6 module dfl.groupbox;
7 
8 private import dfl.control, dfl.base, dfl.button, dfl.drawing;
9 private import dfl.internal.winapi, dfl.application, dfl.event;
10 
11 
12 private extern(Windows) void _initButton();
13 
14 
15 version(NO_DRAG_DROP)
16 	version = DFL_NO_DRAG_DROP;
17 
18 
19 ///
20 class GroupBox: ControlSuperClass // docmain
21 {
22 	override @property Rect displayRectangle() // getter
23 	{
24 		// Should only calculate this upon setting the text ?
25 		
26 		int xw = GetSystemMetrics(SM_CXFRAME);
27 		int yw = GetSystemMetrics(SM_CYFRAME);
28 		//const int _textHeight = 13; // Hack.
29 		return Rect(xw, yw + _textHeight, clientSize.width - xw * 2, clientSize.height - yw - _textHeight - yw);
30 	}
31 	
32 	
33 	override @property Size defaultSize() // getter
34 	{
35 		return Size(200, 100);
36 	}
37 	
38 	
39 	version(DFL_NO_DRAG_DROP) {} else
40 	{
41 		override @property void allowDrop(bool dyes) // setter
42 		{
43 			//if(dyes)
44 			//	throw new DflException("Cannot drop on a group box");
45 			assert(!dyes, "Cannot drop on a group box");
46 		}
47 		
48 		alias Control.allowDrop allowDrop; // Overload.
49 	}
50 	
51 	
52 	this()
53 	{
54 		_initButton();
55 		
56 		if(DEFTEXTHEIGHT_INIT == _defTextHeight)
57 		{
58 			//_recalcTextHeight(defaultFont);
59 			_recalcTextHeight(font);
60 			_defTextHeight = _textHeight;
61 		}
62 		_textHeight = _defTextHeight;
63 		
64 		wstyle |= BS_GROUPBOX /+ | WS_TABSTOP +/; // Should WS_TABSTOP be set?
65 		//wstyle |= BS_GROUPBOX | WS_TABSTOP;
66 		//wexstyle |= WS_EX_CONTROLPARENT; // ?
67 		wclassStyle = buttonClassStyle;
68 		ctrlStyle |= ControlStyles.CONTAINER_CONTROL;
69 	}
70 	
71 	
72 	protected override void onFontChanged(EventArgs ea)
73 	{
74 		_dispChanged();
75 		
76 		super.onFontChanged(ea);
77 	}
78 	
79 	
80 	protected override void onHandleCreated(EventArgs ea)
81 	{
82 		super.onHandleCreated(ea);
83 		
84 		_dispChanged();
85 	}
86 	
87 	
88 	protected override void createParams(ref CreateParams cp)
89 	{
90 		super.createParams(cp);
91 		
92 		cp.className = BUTTON_CLASSNAME;
93 	}
94 	
95 	
96 	protected override void wndProc(ref Message msg)
97 	{
98 		switch(msg.msg)
99 		{
100 			case WM_NCHITTEST:
101 				Control._defWndProc(msg);
102 				break;
103 			
104 			default:
105 				super.wndProc(msg);
106 		}
107 	}
108 	
109 	
110 	protected override void onPaintBackground(PaintEventArgs ea)
111 	{
112 		//Control.onPaintBackground(ea); // DMD 0.106: not accessible.
113 		
114 		RECT rect;
115 		ea.clipRectangle.getRect(&rect);
116 		FillRect(ea.graphics.handle, &rect, hbrBg);
117 	}
118 	
119 	
120 	protected override void prevWndProc(ref Message msg)
121 	{
122 		//msg.result = CallWindowProcA(buttonPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam);
123 		msg.result = dfl.internal.utf.callWindowProc(buttonPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam);
124 		
125 		// Work around a Windows issue...
126 		if(WM_PAINT == msg.msg)
127 		{
128 			auto hmuxt = GetModuleHandleA("uxtheme.dll");
129 			if(hmuxt)
130 			{
131 				auto isAppThemed = cast(typeof(&IsAppThemed))GetProcAddress(hmuxt, "IsAppThemed");
132 				if(isAppThemed && isAppThemed())
133 				{
134 					auto txt = text;
135 					if(txt.length)
136 					{
137 						auto openThemeData = cast(typeof(&OpenThemeData))GetProcAddress(hmuxt, "OpenThemeData");
138 						HTHEME htd;
139 						if(openThemeData
140 							&& HTHEME.init != (htd = openThemeData(msg.hWnd, "Button")))
141 						{
142 							HDC hdc = cast(HDC)msg.wParam;
143 							//PAINTSTRUCT ps;
144 							bool gotdc = false;
145 							if(!hdc)
146 							{
147 								//hdc = BeginPaint(msg.hWnd, &ps);
148 								gotdc = true;
149 								hdc = GetDC(msg.hWnd);
150 							}
151 							try
152 							{
153 								scope g = new Graphics(hdc, false); // Not owned.
154 								auto f = font;
155 								scope tfmt = new TextFormat(TextFormatFlags.SINGLE_LINE);
156 								
157 								Color c;
158 								COLORREF cr;
159 								auto getThemeColor = cast(typeof(&GetThemeColor))GetProcAddress(hmuxt, "GetThemeColor");
160 								auto gtcState = enabled ? (1 /*PBS_NORMAL*/) : (2 /*GBS_DISABLED*/);
161 								if(getThemeColor
162 									&& 0 == getThemeColor(htd, 4 /*BP_GROUPBOX*/, gtcState, 3803 /*TMT_TEXTCOLOR*/, &cr))
163 									c = Color.fromRgb(cr);
164 								else
165 									c = enabled ? foreColor : SystemColors.grayText; // ?
166 								
167 								Size tsz = g.measureText(txt, f, tfmt);
168 								
169 								g.fillRectangle(backColor, 8, 0, 2 + tsz.width + 2, tsz.height + 2);
170 								g.drawText(txt, f, c, Rect(8 + 2, 0, tsz.width, tsz.height), tfmt);
171 							}
172 							finally
173 							{
174 								//if(ps.hdc)
175 								//	EndPaint(msg.hWnd, &ps);
176 								if(gotdc)
177 									ReleaseDC(msg.hWnd, hdc);
178 								
179 								auto closeThemeData = cast(typeof(&CloseThemeData))GetProcAddress(hmuxt, "CloseThemeData");
180 								assert(closeThemeData !is null);
181 								closeThemeData(htd);
182 							}
183 						}
184 					}
185 				}
186 			}
187 		}
188 	}
189 	
190 	
191 	private:
192 	
193 	enum int DEFTEXTHEIGHT_INIT = -1;
194 	static int _defTextHeight = DEFTEXTHEIGHT_INIT;
195 	int _textHeight = -1;
196 	
197 	
198 	void _recalcTextHeight(Font f)
199 	{
200 		_textHeight = cast(int)f.getSize(GraphicsUnit.PIXEL);
201 	}
202 	
203 	
204 	void _dispChanged()
205 	{
206 		int old = _textHeight;
207 		_recalcTextHeight(font);
208 		if(old != _textHeight)
209 		{
210 			//if(isHandleCreated)
211 			{
212 				// Display area changed...
213 				// ?
214 				suspendLayout();
215 				resumeLayout(true);
216 			}
217 		}
218 	}
219 }
220