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