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