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