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.toolbar; 10 11 import dguihub.core.controls.subclassedcontrol; 12 import dguihub.core.utils; 13 public import dguihub.imagelist; 14 15 enum ToolButtonStyle : ubyte { 16 button = TBSTYLE_BUTTON, 17 separator = TBSTYLE_SEP, 18 dropdown = TBSTYLE_DROPDOWN, 19 } 20 21 class ToolButton { 22 public Event!(ToolButton, EventArgs) click; 23 24 private ToolBar _owner; 25 private ContextMenu _ctxMenu; 26 private ToolButtonStyle _tbs; 27 private int _imgIndex; 28 private bool _enabled; 29 30 package this(ToolBar tb, ToolButtonStyle tbs, int imgIndex, bool enabled) { 31 this._owner = tb; 32 this._tbs = tbs; 33 this._imgIndex = imgIndex; 34 this._enabled = enabled; 35 } 36 37 @property public final int index() { 38 if (this._owner && this._owner.created && this._owner.buttons) { 39 int i = 0; 40 41 foreach (ToolButton tbtn; this._owner.buttons) { 42 if (tbtn is this) { 43 return i; 44 } 45 46 i++; 47 } 48 } 49 50 return -1; 51 } 52 53 @property public final ToolButtonStyle style() { 54 return this._tbs; 55 } 56 57 @property public final void style(ToolButtonStyle tbs) { 58 this._tbs = tbs; 59 60 if (this._owner && this._owner.created) { 61 TBBUTTONINFOW tbinfo = void; 62 63 tbinfo.cbSize = TBBUTTONINFOW.sizeof; 64 tbinfo.dwMask = TBIF_BYINDEX | TBIF_STYLE; 65 tbinfo.fsStyle = tbs; 66 67 this._owner.sendMessage(TB_SETBUTTONINFOW, this.index, cast(LPARAM)&tbinfo); 68 } 69 } 70 71 @property public final int imageIndex() { 72 return this._imgIndex; 73 } 74 75 @property public final void imageIndex(int idx) { 76 this._imgIndex = idx; 77 78 if (this._owner && this._owner.created) { 79 TBBUTTONINFOW tbinfo = void; 80 81 tbinfo.cbSize = TBBUTTONINFOW.sizeof; 82 tbinfo.dwMask = TBIF_BYINDEX | TBIF_IMAGE; 83 tbinfo.iImage = idx; 84 85 this._owner.sendMessage(TB_SETBUTTONINFOW, this.index, cast(LPARAM)&tbinfo); 86 } 87 } 88 89 @property public final bool enabled() { 90 return this._enabled; 91 } 92 93 @property public final void enabled(bool b) { 94 this._enabled = b; 95 96 if (this._owner && this._owner.created) { 97 TBBUTTONINFOW tbinfo = void; 98 99 tbinfo.cbSize = TBBUTTONINFOW.sizeof; 100 tbinfo.dwMask = TBIF_BYINDEX | TBIF_STATE; 101 this._owner.sendMessage(TB_GETBUTTONINFOW, this.index, cast(LPARAM)&tbinfo); //Ricavo i dati completi. 102 103 b ? (tbinfo.fsState |= TBSTATE_ENABLED) : (tbinfo.fsState &= ~TBSTATE_ENABLED); 104 this._owner.sendMessage(TB_SETBUTTONINFOW, this.index, cast(LPARAM)&tbinfo); 105 } 106 } 107 108 @property public ContextMenu contextMenu() { 109 return this._ctxMenu; 110 } 111 112 @property public void contextMenu(ContextMenu cm) { 113 this._ctxMenu = cm; 114 } 115 116 @property public final ToolBar toolBar() { 117 return this._owner; 118 } 119 120 package void onToolBarButtonClick(EventArgs e) { 121 this.click(this, e); 122 } 123 } 124 125 class ToolBar : SubclassedControl { 126 private Collection!(ToolButton) _buttons; 127 private ImageList _imgList; 128 129 @property public final ImageList imageList() { 130 return this._imgList; 131 } 132 133 @property public final void imageList(ImageList imgList) { 134 this._imgList = imgList; 135 136 if (this.created) { 137 this.sendMessage(TB_SETIMAGELIST, 0, cast(LPARAM)this._imgList.handle); 138 } 139 } 140 141 public final ToolButton addDropdownButton(int imgIndex, ContextMenu ctxMenu, bool en = true) { 142 if (!this._buttons) { 143 this._buttons = new Collection!(ToolButton)(); 144 } 145 146 ToolButton tb = new ToolButton(this, ToolButtonStyle.dropdown, imgIndex, en); 147 tb.contextMenu = ctxMenu; 148 this._buttons.add(tb); 149 150 if (this.created) { 151 ToolBar.addItem(tb); 152 } 153 154 return tb; 155 } 156 157 public final ToolButton addButton(int imgIndex, bool en = true) { 158 if (!this._buttons) { 159 this._buttons = new Collection!(ToolButton)(); 160 } 161 162 ToolButton tb = new ToolButton(this, ToolButtonStyle.button, imgIndex, en); 163 this._buttons.add(tb); 164 165 if (this.created) { 166 ToolBar.addItem(tb); 167 } 168 169 return tb; 170 } 171 172 public final void addSeparator() { 173 if (!this._buttons) { 174 this._buttons = new Collection!(ToolButton)(); 175 } 176 177 ToolButton tb = new ToolButton(this, ToolButtonStyle.separator, -1, true); 178 this._buttons.add(tb); 179 180 if (this.created) { 181 ToolBar.addItem(tb); 182 } 183 } 184 185 public final void removeButton(int idx) { 186 this._buttons.removeAt(idx); 187 188 if (this.created) { 189 this.sendMessage(TB_DELETEBUTTON, idx, 0); 190 } 191 } 192 193 @property public final ToolButton[] buttons() { 194 if (this._buttons) { 195 return this._buttons.get(); 196 } 197 198 return null; 199 } 200 201 private void forceToolbarSize() { 202 uint sz = this.sendMessage(TB_GETBUTTONSIZE, 0, 0); 203 204 this.size = Size(LOWORD(sz), HIWORD(sz)); 205 } 206 207 private static void addItem(ToolButton tb) { 208 TBBUTTON tbtn; 209 210 switch (tb.style) { 211 case ToolButtonStyle.button, ToolButtonStyle.dropdown: 212 tbtn.iBitmap = tb.imageIndex; 213 tbtn.fsStyle = cast(ubyte)tb.style; 214 tbtn.fsState = cast(ubyte)(tb.enabled ? TBSTATE_ENABLED : 0); 215 tbtn.dwData = winCast!(uint)(tb); 216 break; 217 218 case ToolButtonStyle.separator: 219 tbtn.fsStyle = cast(ubyte)tb.style; 220 break; 221 222 default: 223 assert(false, "Unknown ToolButton Style"); 224 } 225 226 if (tb.toolBar._dock is DockStyle.left || tb.toolBar._dock is DockStyle.right) { 227 tbtn.fsState |= TBSTATE_WRAP; 228 } 229 230 tb.toolBar.sendMessage(TB_INSERTBUTTONW, tb.index, cast(LPARAM)&tbtn); 231 } 232 233 protected override void createControlParams(ref CreateControlParams ccp) { 234 ccp.superclassName = WC_TOOLBAR; 235 ccp.className = WC_DTOOLBAR; 236 this.setStyle(TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NOPARENTALIGN, true); 237 238 if (this._dock is DockStyle.none) { 239 this._dock = DockStyle.top; 240 } 241 242 if (this._dock is DockStyle.left || this._dock is DockStyle.right) { 243 this.setStyle(CCS_VERT, true); 244 } 245 246 super.createControlParams(ccp); 247 } 248 249 protected override void onHandleCreated(EventArgs e) { 250 this.sendMessage(TB_BUTTONSTRUCTSIZE, TBBUTTON.sizeof, 0); 251 int exStyle = this.sendMessage(TB_GETEXTENDEDSTYLE, 0, 0); 252 this.sendMessage(TB_SETEXTENDEDSTYLE, 0, exStyle | TBSTYLE_EX_DRAWDDARROWS); 253 this.forceToolbarSize(); // HACK: Forza il ridimensionamento della barra strumenti. 254 255 if (this._imgList) { 256 this.sendMessage(TB_SETIMAGELIST, 0, cast(LPARAM)this._imgList.handle); 257 } 258 259 if (this._buttons) { 260 foreach (ToolButton tb; this._buttons) { 261 ToolBar.addItem(tb); 262 } 263 } 264 265 super.onHandleCreated(e); 266 } 267 268 protected override void onReflectedMessage(ref Message m) { 269 switch (m.msg) { 270 case WM_NOTIFY: { 271 NMHDR* pNmhdr = cast(NMHDR*)m.lParam; 272 273 switch (pNmhdr.code) { 274 case NM_CLICK: { 275 NMMOUSE* pNMouse = cast(NMMOUSE*)m.lParam; 276 ToolButton tBtn = winCast!(ToolButton)(pNMouse.dwItemData); 277 278 if (tBtn) { 279 tBtn.onToolBarButtonClick(EventArgs.empty); //FIXME! 280 } 281 } 282 break; 283 284 case TBN_DROPDOWN: { 285 NMTOOLBARW* pNmToolbar = cast(NMTOOLBARW*)m.lParam; 286 287 Point pt = Cursor.position; 288 convertPoint(pt, null, this); 289 int idx = this.sendMessage(TB_HITTEST, 0, cast(LPARAM)&pt.point); 290 291 if (idx != -1) { 292 ToolButton tbtn = this._buttons[idx]; 293 294 if (tbtn && tbtn.contextMenu) { 295 tbtn.contextMenu.popupMenu(this._handle, Cursor.position); 296 } 297 } 298 } 299 break; 300 301 default: 302 break; 303 } 304 } 305 break; 306 307 default: 308 break; 309 } 310 311 super.onReflectedMessage(m); 312 } 313 314 protected override void wndProc(ref Message m) { 315 if (m.msg == WM_WINDOWPOSCHANGING) { 316 /* 317 * HACK: Forza il ridimensionamento della barra strumenti. 318 */ 319 320 WINDOWPOS* pWindowPos = cast(WINDOWPOS*)m.lParam; 321 uint sz = this.sendMessage(TB_GETBUTTONSIZE, 0, 0); 322 323 switch (this._dock) { 324 case DockStyle.top, DockStyle.bottom: 325 pWindowPos.cy = HIWORD(sz); 326 break; 327 328 case DockStyle.left, DockStyle.right: 329 pWindowPos.cx = LOWORD(sz); 330 break; 331 332 default: 333 break; 334 } 335 } 336 337 super.wndProc(m); 338 } 339 }