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.combobox; 10 11 import std.utf: toUTFz; 12 import dgui.core.controls.subclassedcontrol; 13 import dgui.core.utils; 14 public import dgui.imagelist; 15 16 enum DropDownStyles: uint 17 { 18 none = 0, // Internal Use 19 simple = CBS_SIMPLE, 20 dropdown = CBS_DROPDOWN, 21 dropdownList = CBS_DROPDOWNLIST, 22 } 23 24 class ComboBoxItem 25 { 26 private ComboBox _owner; 27 private string _text; 28 private int _imgIndex = -1; 29 30 mixin tagProperty; 31 32 package this(string txt, int idx = -1) 33 { 34 this._text = txt; 35 this._imgIndex = idx; 36 } 37 38 @property public final int index() 39 { 40 if(this._owner.items) 41 { 42 foreach(int i, ComboBoxItem cbi; this._owner.items) 43 { 44 if(cbi is this) 45 { 46 return i; 47 } 48 } 49 } 50 51 return -1; 52 } 53 54 @property public final ComboBox comboBox() 55 { 56 return this._owner; 57 } 58 59 @property package void comboBox(ComboBox cbx) 60 { 61 this._owner = cbx; 62 } 63 64 @property public final int imageIndex() 65 { 66 return this._imgIndex; 67 } 68 69 @property public final void imageIndex(int idx) 70 { 71 this._imgIndex = idx; 72 73 if(this._owner && this._owner.created) 74 { 75 COMBOBOXEXITEMW cbei; 76 77 cbei.mask = CBEIF_IMAGE; 78 cbei.iImage = idx; 79 cbei.iItem = this.index; 80 81 this._owner.sendMessage(CBEM_SETITEMW, 0, cast(LPARAM)&cbei); 82 } 83 } 84 85 @property public final string text() 86 { 87 return this._text; 88 } 89 90 @property public final void text(string txt) 91 { 92 this._text = txt; 93 94 if(this._owner && this._owner.created) 95 { 96 COMBOBOXEXITEMW cbei; 97 98 cbei.mask = CBEIF_TEXT; 99 cbei.pszText = toUTFz!(wchar*)(txt); 100 cbei.iItem = this.index; 101 102 this._owner.sendMessage(CBEM_SETITEMW, 0, cast(LPARAM)&cbei); 103 } 104 } 105 } 106 107 class ComboBox: SubclassedControl 108 { 109 public Event!(Control, EventArgs) itemChanged; 110 111 private Collection!(ComboBoxItem) _items; 112 private DropDownStyles _oldDDStyle = DropDownStyles.none; 113 private int _selectedIndex; 114 private ImageList _imgList; 115 116 public this() 117 { 118 this.setStyle(DropDownStyles.dropdown, true); 119 } 120 121 public final ComboBoxItem addItem(string s, int imgIndex = -1) 122 { 123 if(!this._items) 124 { 125 this._items = new Collection!(ComboBoxItem); 126 } 127 128 ComboBoxItem cbi = new ComboBoxItem(s, imgIndex); 129 this._items.add(cbi); 130 131 if(this.created) 132 { 133 return this.insertItem(cbi); 134 } 135 136 return cbi; 137 } 138 139 public final void removeItem(int idx) 140 { 141 if(this.created) 142 { 143 this.sendMessage(CB_DELETESTRING, idx, 0); 144 } 145 146 this._items.removeAt(idx); 147 } 148 149 @property public final int selectedIndex() 150 { 151 if(this.created) 152 { 153 return this.sendMessage(CB_GETCURSEL, 0, 0); 154 } 155 156 return this._selectedIndex; 157 } 158 159 @property public final void selectedIndex(int i) 160 { 161 this._selectedIndex = i; 162 163 if(this.created) 164 { 165 this.sendMessage(CB_SETCURSEL, i, 0); 166 } 167 } 168 169 public void clear() 170 { 171 if(this._items) 172 { 173 foreach(ComboBoxItem cbi; this._items) 174 { 175 this.sendMessage(CB_DELETESTRING, 0, 0); 176 } 177 178 this._items.clear(); 179 } 180 181 this.selectedIndex = -1; 182 } 183 184 @property public final ComboBoxItem selectedItem() 185 { 186 if(this.created) 187 { 188 return this._items[this._selectedIndex]; 189 } 190 else 191 { 192 int idx = this.selectedIndex; 193 194 if(this._items) 195 { 196 return this._items[idx]; 197 } 198 } 199 200 return null; 201 } 202 203 @property public override bool focused() 204 { 205 if(this.created) 206 { 207 return GetFocus() == cast(HWND)this.sendMessage(CBEM_GETCOMBOCONTROL, 0, 0); 208 } 209 210 return false; 211 } 212 213 @property public final ImageList imageList() 214 { 215 return this._imgList; 216 } 217 218 @property public void imageList(ImageList imgList) 219 { 220 this._imgList = imgList; 221 222 if(this.created) 223 { 224 this.sendMessage(CBEM_SETIMAGELIST, 0, cast(LPARAM)this._imgList.handle); 225 } 226 } 227 228 @property public final void dropDownStyle(DropDownStyles dds) 229 { 230 if(dds !is this._oldDDStyle) 231 { 232 this.setStyle(this._oldDDStyle, false); //Rimuovo il vecchio 233 this.setStyle(dds, true); //Aggiungo il nuovo 234 235 this._oldDDStyle = dds; 236 } 237 } 238 239 @property public final ComboBoxItem[] items() 240 { 241 if(this._items) 242 { 243 return this._items.get(); 244 } 245 246 return null; 247 } 248 249 private ComboBoxItem insertItem(ComboBoxItem cbi) 250 { 251 COMBOBOXEXITEMW cbei; 252 253 cbei.mask = CBEIF_TEXT | CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_LPARAM; 254 cbei.iItem = -1; 255 cbei.iImage = cbi.imageIndex; 256 cbei.iSelectedImage = cbi.imageIndex; 257 cbei.pszText = toUTFz!(wchar*)(cbi.text); 258 cbei.lParam = winCast!(LPARAM)(cbi); 259 260 this.sendMessage(CBEM_INSERTITEMW, 0, cast(LPARAM)&cbei); 261 cbi.comboBox = this; 262 return cbi; 263 } 264 265 protected void onItemChanged(EventArgs e) 266 { 267 this.itemChanged(this, e); 268 } 269 270 protected override void createControlParams(ref CreateControlParams ccp) 271 { 272 // Use Original Paint Routine, the double buffered one causes some issues 273 274 ccp.superclassName = WC_COMBOBOXEX; 275 ccp.className = WC_DCOMBOBOX; 276 277 this.setStyle(WS_CLIPCHILDREN | WS_CLIPSIBLINGS, true); //Clip child ComboBox 278 //this.setStyle(CBS_NOINTEGRALHEIGHT, true); 279 280 super.createControlParams(ccp); 281 } 282 283 protected override void onHandleCreated(EventArgs e) 284 { 285 if(this._imgList) 286 { 287 this.sendMessage(CBEM_SETIMAGELIST, 0, cast(LPARAM)this._imgList.handle); 288 } 289 290 if(this._items) 291 { 292 foreach(ComboBoxItem cbi; this._items) 293 { 294 this.insertItem(cbi); 295 } 296 } 297 298 if(this._selectedIndex != -1) 299 { 300 this.sendMessage(CB_SETCURSEL, this._selectedIndex, 0); 301 } 302 303 super.onHandleCreated(e); 304 } 305 306 protected override void onReflectedMessage(ref Message m) 307 { 308 if(m.msg == WM_COMMAND && HIWORD(m.wParam) == CBN_SELCHANGE) 309 { 310 this._selectedIndex = this.sendMessage(CB_GETCURSEL, 0, 0); 311 this.onItemChanged(EventArgs.empty); 312 } 313 314 super.onReflectedMessage(m); 315 } 316 317 protected override void wndProc(ref Message m) 318 { 319 switch(m.msg) 320 { 321 case WM_COMMAND: 322 { 323 /* Retrieve focus notifications from child ComboBox */ 324 if(HIWORD(m.wParam) == CBN_SETFOCUS || HIWORD(m.wParam) == CBN_KILLFOCUS) 325 { 326 this.onFocusChanged(EventArgs.empty); 327 } 328 329 super.wndProc(m); 330 } 331 break; 332 333 case WM_SETFOCUS, WM_KILLFOCUS: 334 this.originalWndProc(m); //Don't send focusChanged event here! 335 break; 336 337 default: 338 super.wndProc(m); 339 break; 340 } 341 } 342 }