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