1 // Written by Christopher E. Miller
2 // See the included license.txt for copyright and license details.
3 
4 
5 
6 module dfl.statusbar;
7 
8 
9 private import dfl.control, dfl.base, dfl.internal.winapi, dfl.event,
10         dfl.collections, dfl.internal.utf, dfl.internal.dlib, dfl.application;
11 
12 private import dfl.internal.dlib;
13 
14 
15 private extern(Windows) void _initStatusbar();
16 
17 
18 /+
19 enum StatusBarPanelAutoSize: ubyte {
20    NONE,
21    CONTENTS,
22    SPRING,
23 }
24 +/
25 
26 
27 
28 enum StatusBarPanelBorderStyle: ubyte {
29    NONE, ///
30    SUNKEN, /// ditto
31    RAISED /// ditto
32 }
33 
34 
35 
36 class StatusBarPanel: DObject {
37 
38    this(Dstring text) {
39       this._txt = text;
40    }
41 
42    /// ditto
43    this(Dstring text, int width) {
44       this._txt = text;
45       this._width = width;
46    }
47 
48    /// ditto
49    this() {
50    }
51 
52 
53    override Dstring toString() {
54       return _txt;
55    }
56 
57 
58    override Dequ opEquals(Object o) {
59       return _txt == getObjectString(o); // ?
60    }
61 
62    Dequ opEquals(StatusBarPanel pnl) {
63       return _txt == pnl._txt;
64    }
65 
66    Dequ opEquals(Dstring val) {
67       return _txt == val;
68    }
69 
70 
71    override int opCmp(Object o) {
72       return stringICmp(_txt, getObjectString(o)); // ?
73    }
74 
75    int opCmp(StatusBarPanel pnl) {
76       return stringICmp(_txt, pnl._txt);
77    }
78 
79    int opCmp(Dstring val) {
80       return stringICmp(_txt, val);
81    }
82 
83 
84    /+
85 
86    final @property void alignment(HorizontalAlignment ha) { // setter
87 
88    }
89 
90    /// ditto
91    final @property HorizontalAlignment alignment() { // getter
92       //LEFT
93    }
94    +/
95 
96 
97    /+
98 
99    final @property void autoSize(StatusBarPanelAutoSize asize) { // setter
100 
101    }
102 
103    /// ditto
104    final @property StatusBarPanelAutoSize autoSize() { // getter
105       //NONE
106    }
107    +/
108 
109 
110 
111    final @property void borderStyle(StatusBarPanelBorderStyle bs) { // setter
112       switch(bs) {
113          case StatusBarPanelBorderStyle.NONE:
114             _utype = (_utype & ~SBT_POPOUT) | SBT_NOBORDERS;
115             break;
116 
117          case StatusBarPanelBorderStyle.RAISED:
118             _utype = (_utype & ~SBT_NOBORDERS) | SBT_POPOUT;
119             break;
120 
121          case StatusBarPanelBorderStyle.SUNKEN:
122             _utype &= ~(SBT_NOBORDERS | SBT_POPOUT);
123             break;
124 
125          default:
126             assert(0);
127       }
128 
129       if(_parent && _parent.isHandleCreated) {
130          _parent.panels._fixtexts(); // Also fixes styles.
131       }
132    }
133 
134    /// ditto
135    final @property StatusBarPanelBorderStyle borderStyle() { // getter
136       if(_utype & SBT_POPOUT) {
137          return StatusBarPanelBorderStyle.RAISED;
138       }
139       if(_utype & SBT_NOBORDERS) {
140          return StatusBarPanelBorderStyle.NONE;
141       }
142       return StatusBarPanelBorderStyle.RAISED;
143    }
144 
145 
146    // icon
147 
148 
149    /+
150 
151    final @property void minWidth(int mw) // setter
152    in {
153       assert(mw >= 0);
154    }
155    body {
156 
157    }
158 
159    /// ditto
160    final @property int minWidth() { // getter
161       //10
162    }
163    +/
164 
165 
166 
167    final @property StatusBar parent() { // getter
168       return _parent;
169    }
170 
171 
172    // style
173 
174 
175 
176    final @property void text(Dstring txt) { // setter
177       if(_parent && _parent.isHandleCreated) {
178          int idx = _parent.panels.indexOf(this);
179          assert(-1 != idx);
180          _parent._sendidxtext(idx, _utype, txt);
181       }
182 
183       this._txt = txt;
184    }
185 
186    /// ditto
187    final @property Dstring text() { // getter
188       return _txt;
189    }
190 
191 
192    /+
193 
194    final @property void toolTipText(Dstring txt) { // setter
195 
196    }
197 
198    /// ditto
199    final @property Dstring toolTipText() { // getter
200       //null
201    }
202    +/
203 
204 
205 
206    final @property void width(int w) { // setter
207       _width = w;
208 
209       if(_parent && _parent.isHandleCreated) {
210          _parent.panels._fixwidths();
211       }
212    }
213 
214    /// ditto
215    final @property int width() { // getter
216       return _width;
217    }
218 
219 
220  private:
221 
222    Dstring _txt = null;
223    int _width = 100;
224    StatusBar _parent = null;
225    WPARAM _utype = 0; // StatusBarPanelBorderStyle.SUNKEN.
226 }
227 
228 
229 /+
230 
231 class StatusBarPanelClickEventArgs: MouseEventArgs {
232 
233    this(StatusBarPanel sbpanel, MouseButtons btn, int clicks, int x, int y) {
234       this._sbpanel = sbpanel;
235       super(btn, clicks, x, y, 0);
236    }
237 
238 
239  private:
240    StatusBarPanel _sbpanel;
241 }
242 +/
243 
244 
245 
246 class StatusBar: ControlSuperClass { // docmain
247 
248    class StatusBarPanelCollection {
249       protected this(StatusBar sb)
250       in {
251          assert(sb.lpanels is null);
252       }
253       body {
254          this.sb = sb;
255       }
256 
257 
258     private:
259 
260       StatusBar sb;
261       package StatusBarPanel[] _panels;
262 
263 
264       package void _fixwidths() {
265          assert(isHandleCreated);
266 
267          UINT[20] _pws = void;
268          UINT[] pws = _pws;
269          if(_panels.length > _pws.length) {
270             pws = new UINT[_panels.length];
271          }
272          UINT right = 0;
273          foreach(idx, pnl; _panels) {
274             if(-1 == pnl.width) {
275                pws[idx] = -1;
276             } else {
277                right += pnl.width;
278                pws[idx] = right;
279             }
280          }
281          sb.prevwproc(SB_SETPARTS, cast(WPARAM)_panels.length, cast(LPARAM)pws.ptr);
282       }
283 
284 
285       void _fixtexts() {
286          assert(isHandleCreated);
287 
288          if(dfl.internal.utf.useUnicode) {
289             foreach(idx, pnl; _panels) {
290                sb.prevwproc(SB_SETTEXTW, cast(WPARAM)idx | pnl._utype, cast(LPARAM)dfl.internal.utf.toUnicodez(pnl._txt));
291             }
292          } else {
293             foreach(idx, pnl; _panels) {
294                sb.prevwproc(SB_SETTEXTA, cast(WPARAM)idx | pnl._utype, cast(LPARAM)dfl.internal.utf.toAnsiz(pnl._txt));
295             }
296          }
297       }
298 
299 
300       void _setcurparts() {
301          assert(isHandleCreated);
302 
303          _fixwidths();
304 
305          _fixtexts();
306       }
307 
308 
309       void _removed(size_t idx, Object val) {
310          if(size_t.max == idx) { // Clear all.
311             if(sb.isHandleCreated) {
312                sb.prevwproc(SB_SETPARTS, 0, 0); // 0 parts.
313             }
314          } else {
315             if(sb.isHandleCreated) {
316                _setcurparts();
317             }
318          }
319       }
320 
321 
322       void _added(size_t idx, StatusBarPanel val) {
323          if(val._parent) {
324             throw new DflException("StatusBarPanel already belongs to a StatusBar");
325          }
326 
327          val._parent = sb;
328 
329          if(sb.isHandleCreated) {
330             _setcurparts();
331          }
332       }
333 
334 
335       void _adding(size_t idx, StatusBarPanel val) {
336          if(_panels.length >= 254) { // Since SB_SETTEXT with 255 has special meaning.
337             throw new DflException("Too many status bar panels");
338          }
339       }
340 
341 
342     public:
343 
344       mixin ListWrapArray!(StatusBarPanel, _panels,
345                            _adding, _added,
346                            _blankListCallback!(StatusBarPanel), _removed,
347                            true, /+true+/ false, false) _wraparray;
348    }
349 
350 
351 
352    this() {
353       _initStatusbar();
354 
355       _issimple = true;
356       wstyle |= SBARS_SIZEGRIP;
357       wclassStyle = statusbarClassStyle;
358       //height = ?;
359       dock = DockStyle.BOTTOM;
360 
361       lpanels = new StatusBarPanelCollection(this);
362    }
363 
364 
365    // backColor / font / foreColor ...
366 
367 
368    override @property void dock(DockStyle ds) { // setter
369       switch(ds) {
370          case DockStyle.BOTTOM:
371          case DockStyle.TOP:
372             super.dock = ds;
373             break;
374 
375          default:
376             throw new DflException("Invalid status bar dock");
377       }
378    }
379 
380    alias Control.dock dock; // Overload.
381 
382 
383 
384    final @property StatusBarPanelCollection panels() { // getter
385       return lpanels;
386    }
387 
388 
389 
390    final @property void showPanels(bool byes) { // setter
391       if(!byes == _issimple) {
392          return;
393       }
394 
395       if(isHandleCreated) {
396          prevwproc(SB_SIMPLE, cast(WPARAM)!byes, 0);
397 
398          /+ // It's kept in sync even if simple.
399          if(byes) {
400             panels._setcurparts();
401          }
402          +/
403 
404          if(!byes) {
405             _sendidxtext(255, 0, _simpletext);
406          }
407       }
408 
409       _issimple = !byes;
410    }
411 
412    /// ditto
413    final @property bool showPanels() { // getter
414       return !_issimple;
415    }
416 
417 
418 
419    final @property void sizingGrip(bool byes) { // setter
420       if(byes == sizingGrip) {
421          return;
422       }
423 
424       if(byes) {
425          _style(_style() | SBARS_SIZEGRIP);
426       } else {
427          _style(_style() & ~SBARS_SIZEGRIP);
428       }
429    }
430 
431    /// ditto
432    final @property bool sizingGrip() { // getter
433       if(wstyle & SBARS_SIZEGRIP) {
434          return true;
435       }
436       return false;
437    }
438 
439 
440    override @property void text(Dstring txt) { // setter
441       if(isHandleCreated && !showPanels) {
442          _sendidxtext(255, 0, txt);
443       }
444 
445       this._simpletext = txt;
446 
447       onTextChanged(EventArgs.empty);
448    }
449 
450    /// ditto
451    override @property Dstring text() { // getter
452       return this._simpletext;
453    }
454 
455 
456    protected override void onHandleCreated(EventArgs ea) {
457       super.onHandleCreated(ea);
458 
459       if(_issimple) {
460          prevwproc(SB_SIMPLE, cast(WPARAM)true, 0);
461          panels._setcurparts();
462          if(_simpletext.length) {
463             _sendidxtext(255, 0, _simpletext);
464          }
465       } else {
466          panels._setcurparts();
467          prevwproc(SB_SIMPLE, cast(WPARAM)false, 0);
468       }
469    }
470 
471 
472    protected override void createParams(ref CreateParams cp) {
473       super.createParams(cp);
474 
475       cp.className = STATUSBAR_CLASSNAME;
476    }
477 
478 
479    protected override void prevWndProc(ref Message msg) {
480       //msg.result = CallWindowProcA(statusbarPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam);
481       msg.result = dfl.internal.utf.callWindowProc(statusbarPrevWndProc, msg.hWnd, msg.msg, msg.wParam, msg.lParam);
482    }
483 
484 
485    /+
486    protected override void createHandle() {
487       //CreateStatusWindow
488    }
489    +/
490 
491 
492    //StatusBarPanelClickEventHandler panelClick;
493    //Event!(StatusBar, StatusBarPanelClickEventArgs) panelClick; ///
494 
495 
496  protected:
497 
498    // onDrawItem ...
499 
500 
501    /+
502 
503    void onPanelClick(StatusBarPanelClickEventArgs ea) {
504       panelClick(this, ea);
505    }
506    +/
507 
508 
509  private:
510 
511    StatusBarPanelCollection lpanels;
512    Dstring _simpletext = null;
513    bool _issimple = true;
514 
515 
516  package:
517  final:
518 
519    LRESULT prevwproc(UINT msg, WPARAM wparam, LPARAM lparam) {
520       //return CallWindowProcA(statusbarPrevWndProc, hwnd, msg, wparam, lparam);
521       return dfl.internal.utf.callWindowProc(statusbarPrevWndProc, hwnd, msg, wparam, lparam);
522    }
523 
524 
525    void _sendidxtext(int idx, WPARAM utype, Dstring txt) {
526       assert(isHandleCreated);
527 
528       if(dfl.internal.utf.useUnicode) {
529          prevwproc(SB_SETTEXTW, cast(WPARAM)idx | utype, cast(LPARAM)dfl.internal.utf.toUnicodez(txt));
530       } else {
531          prevwproc(SB_SETTEXTA, cast(WPARAM)idx | utype, cast(LPARAM)dfl.internal.utf.toAnsiz(txt));
532       }
533    }
534 }
535