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