1 /** DGui project file.
2 
3 Copyright: Trogu Antonio Davide 2011-2013
4 
5 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
6 
7 Authors: Trogu Antonio Davide
8 */
9 module dguihub.tooltip;
10 
11 import dguihub.core.controls.subclassedcontrol;
12 
13 enum ToolTipIcons {
14    none = TTI_NONE,
15    info = TTI_INFO,
16    warning = TTI_WARNING,
17    error = TTI_ERROR,
18 }
19 
20 class ToolTip : SubclassedControl {
21    private ToolTipIcons _ttIcon = ToolTipIcons.none;
22    private bool _creating = false;
23    private Control _ctrl;
24    private string _title;
25 
26    public override void dispose() {
27       if (this._ctrl) {
28          this.removeTool();
29       }
30 
31       super.dispose();
32    }
33 
34    private void addTool(Control c) {
35       this._ctrl = c;
36 
37       TOOLINFOW ti;
38 
39       ti.cbSize = TOOLINFOW.sizeof;
40       ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
41       ti.lpszText = cast(wchar*)LPSTR_TEXTCALLBACKW;
42       ti.hwnd = c.parent ? c.parent.handle : c.handle;
43       ti.uId = cast(uint)c.handle;
44 
45       this.sendMessage(TTM_ADDTOOLW, 0, cast(LPARAM)&ti);
46    }
47 
48    private void removeTool() {
49       TOOLINFOW ti;
50 
51       ti.cbSize = TOOLINFOW.sizeof;
52       ti.hwnd = this._ctrl.parent ? this._ctrl.parent.handle : this._ctrl.handle;
53       ti.uId = cast(uint)this._ctrl.handle;
54 
55       this.sendMessage(TTM_DELTOOLW, 0, cast(LPARAM)&ti);
56       this._ctrl = null;
57    }
58 
59    @property public void icon(ToolTipIcons tti) {
60       this._ttIcon = tti;
61 
62       if (this.created) {
63          this.sendMessage(TTM_SETTITLEW, this._ttIcon, cast(LPARAM)toUTFz!(wchar*)(this._title));
64       }
65    }
66 
67    @property public string title() {
68       return this._title;
69    }
70 
71    @property public void title(string s) {
72       this._title = s;
73 
74       if (this.created) {
75          this.sendMessage(TTM_SETTITLEW, this._ttIcon, cast(LPARAM)toUTFz!(wchar*)(this._title));
76       }
77    }
78 
79    @property public void baloonTip(bool b) {
80       this.setStyle(TTS_BALLOON, b);
81    }
82 
83    @property public void closeButton(bool b) {
84       this.setStyle(TTS_CLOSE, b);
85    }
86 
87    @property public void alwaysTip(bool b) {
88       this.setStyle(TTS_ALWAYSTIP, b);
89    }
90 
91    @property public override void parent(Control c) {
92       if (this._creating) {
93          super.parent = c;
94       } else {
95          throwException!(DGuiException)("A ToolTip cannot have a parent");
96       }
97    }
98 
99    public final void activate(Control c) {
100       if (!this.created) {
101          this._creating = true;
102          this.parent = c.parent ? c.parent : c;
103          this.show();
104          this._creating = false;
105       }
106 
107       if (this._ctrl !is c) {
108          if (this._ctrl) {
109             this.removeTool();
110          }
111 
112          this.addTool(c);
113       }
114 
115       this.sendMessage(TTM_ACTIVATE, true, 0);
116    }
117 
118    public override void show() {
119       if (this._creating) {
120          super.show();
121       } else {
122          throwException!(DGuiException)("Cannot create a ToolTip directly");
123       }
124    }
125 
126    protected override void createControlParams(ref CreateControlParams ccp) {
127       ccp.superclassName = WC_TOOLTIP;
128       ccp.className = WC_DTOOLTIP;
129       ccp.defaultBackColor = SystemColors.colorInfo;
130       ccp.defaultForeColor = SystemColors.colorInfoText;
131 
132       this.setStyle(WS_POPUP | TTS_NOPREFIX, true);
133       this.setExStyle(WS_EX_TOPMOST | WS_EX_TOOLWINDOW, true);
134 
135       /* According To MSDN:
136 		    The window procedure for the tooltip control automatically sets the size, position, and visibility of the control.
137 		    The height of the tooltip window is based on the height of the font currently selected into the device context
138 		    for the tooltip control.
139 		    The width varies based on the length of the string currently in the tooltip window. */
140       this.bounds = Rect(CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT);
141 
142       ToolTip.setBit(this._cBits, ControlBits.cannotAddChild | ControlBits.useCachedText, true);
143       super.createControlParams(ccp);
144    }
145 
146    protected override void onReflectedMessage(ref Message m) {
147       if (m.msg == WM_NOTIFY) {
148          NMHDR* pNotify = cast(NMHDR*)m.lParam;
149 
150          if (pNotify.code == TTN_GETDISPINFOW) {
151             NMTTDISPINFOW* pDispInfo = cast(NMTTDISPINFOW*)pNotify;
152             pDispInfo.lpszText = toUTFz!(wchar*)(this.text);
153          }
154       }
155 
156       super.onReflectedMessage(m);
157    }
158 
159    protected override void onHandleCreated(EventArgs e) {
160       if (this._ttIcon !is ToolTipIcons.none || this._title.length) {
161          this.sendMessage(TTM_SETTITLEW, this._ttIcon, cast(LPARAM)toUTFz!(wchar*)(this._title));
162       }
163 
164       SetWindowPos(this._handle, cast(HWND)HWND_TOPMOST, 0, 0, 0, 0,
165             SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
166       super.onHandleCreated(e);
167    }
168 }