1 namespace gui::controls;
9 #define ROW_HEIGHT listBox.rowHeight /*16*/
12 extern int __ecereVMethodID_class_OnDisplay;
13 extern int __ecereVMethodID_class_OnGetString;
17 class DropBoxBits { bool noHighlight:1, noStipple:1, editText:1, activeColor:1, showNone:1, changeContents:1; };
19 public class DropBox : CommonControl
23 style.activeColor = true;
25 class_property(icon) = "<:ecere>controls/dropBox.png";
27 watch(foreground) { listBox.foreground = foreground; if(editBox) editBox.foreground = foreground; };
28 watch(background) { listBox.background = background; if(editBox) editBox.background = background; };
29 watch(selectionColor) { listBox.selectionColor = selectionColor; if(editBox) editBox.selectionColor = selectionColor; };
30 watch(selectionText) { listBox.selectionText = selectionText; if(editBox) editBox.selectionText = selectionText; };
31 watch(opacity) { listBox.opacity = opacity; if(editBox) editBox.opacity = opacity; };
34 property bool activeStipple
36 property_category $"Appearance"
39 style.noStipple = !value;
42 get { return !style.noStipple; }
44 property bool showButton
46 property_category $"Appearance"
49 button.visible = value;
50 listBox.borderStyle = value ? contour : none;
52 get { return button.visible; }
54 property Alignment alignment
56 property_category $"Appearance"
61 field.alignment = value;
63 get { return alignment; }
65 property bool noHighlight
67 property_category $"Appearance"
72 style.noHighlight = value;
73 listBox.fullRowSelect = !value;
77 get { return style.noHighlight; }
79 property bool activeColor
81 property_category $"Appearance"
86 style.activeColor = value;
90 get { return style.activeColor; }
92 property DataRow currentRow
94 property_category $"Private"
100 listBox.currentRow = value ? value : (style.showNone ? noneRow : null);
101 if(style.editText && style.changeContents)
103 char tempString[4096];
106 const char *(* onGetString)(void *, void *, char *, void *, bool *) = (void *)dataType._vTbl[__ecereVMethodID_class_OnGetString];
107 editBox.contents = onGetString(dataType, currentRow.GetData(null), tempString, null, null);
110 editBox.contents = "";
115 if(editBox.modifiedDocument)
117 NotifyTextEntry(master, this, editBox.contents, false);
118 editBox.modifiedDocument = false;
120 // editBox.Deactivate();
124 get { return currentRow; }
126 property DataRow firstRow { get { return this ? listBox.firstRow : null; } };
127 property DataRow lastRow { get { return this ? listBox.lastRow : null; } };
128 property const char * contents { property_category $"Data" set { if(editBox) editBox.contents = value; } get { return editBox ? editBox.contents : null; } };
129 property bool editText
131 property_category $"Behavior"
142 this, textHorzScroll = true, borderStyle = 0;
143 anchor = Anchor { left = 0, top = 0, right = BTN_WIDTH, bottom = 0 };
144 // visible = false, modifyVirtualArea = false;
145 foreground = foreground;
146 background = background;
147 selectionColor = selectionColor;
148 selectionText = selectionText;
152 button.inactive = false;
154 style.editText = true;
163 button.inactive = true;
165 style.editText = false;
169 get { return style.editText; }
171 property EditBox editBox { get { return editBox; } }
172 property Seconds typingTimeout { property_category $"Behavior" set { listBox.typingTimeout = value; } get { return listBox.typingTimeout; } };
173 property int rowHeight { property_category $"Appearance" set { listBox.rowHeight = value; } get { return listBox.rowHeight; } };
174 property int maxShown
176 property_category $"Behavior"
179 listBoxMaxShown = value;
180 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
182 get { return listBoxMaxShown; }
184 property Window pullDown
186 get { return pulledWindow; }
188 property bool showNone
192 if(value != style.showNone)
196 listBox.DeleteRow(noneRow);
199 style.showNone = value;
202 noneRow = listBox.AddRowNone();
206 get { return style.showNone; }
208 property Color selectionColor { set { selectionColor = value; } get { return selectionColor; } isset { return selectionColor ? true : false; } };
209 property Color selectionText { set { selectionText = value; } get { return selectionText; } isset { return selectionText ? true : false; } };
210 property bool changeContents
212 set { style.changeContents = value; }
213 get { return style.changeContents; }
216 property ListBox listBox { get { return listBox; } }
218 property int rowCount { get { return listBox.rowCount; } }
221 virtual bool Window::NotifySelect(DropBox dropBox, DataRow row, Modifiers mods);
222 virtual bool Window::NotifyClose(DropBox dropBox);
223 virtual bool Window::NotifyHighlight(DropBox dropBox, DataRow row, Modifiers mods);
224 virtual bool Window::NotifyTextEntry(DropBox dropBox, const char * string, bool confirmed);
226 virtual Window OnDropDown()
228 // NASTY BUG ON WINDOWS IN PROPERTIES SHEET IF WE DON'T RECREATE THE LISTBOX HERE
229 // To reproduce, comment out, select borderStyle property, alt-tab to another program, come back, drop down
230 // The listBox goes annoyingly to 0, 0
235 // listBox.visible = true;
239 virtual void OnCloseDropDown(Window pullDown)
241 listBox.visible = false;
244 editBox.ActivateEx(true, false, false, false, null, null);
250 DataRow AddStringf(const char * format, ...)
256 char string[MAX_F_STRING];
259 va_start(args, format);
260 vsnprintf(string, sizeof(string), format, args);
261 string[sizeof(string)-1] = 0;
265 row.SetData(null, string);
271 DataRow AddString(const char * string)
277 row.SetData(null, string);
283 void DeleteRow(DataRow row)
285 if(!row) row = currentRow;
286 listBox.DeleteRow(row);
288 if(row == currentRow)
293 // Convenience function using current rows
296 return currentRow.tag;
299 void * SetData(DataField field, any_object data)
304 return currentRow.SetData(field, data);
309 any_object GetData(DataField field)
311 return this ? currentRow.GetData(field) : null;
314 void Sort(DataField field, int order)
316 listBox.Sort(field, order);
319 void AddField(DataField field)
324 field = DataField { alignment = alignment };
326 listBox.AddField(field);
327 this.field = listBox.firstField;
328 dataType = this.field.dataType;
337 row = listBox.AddRow();
338 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
343 DataRow AddRowAfter(DataRow after)
348 row = listBox.AddRowAfter(after);
349 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
356 return listBox.rowCount;
363 Window master = this.master;
366 if(currentRow && master)
369 NotifySelect(master, this, null, 0);
372 if(style.editText && style.changeContents)
373 editBox.contents = "";
376 noneRow = listBox.AddRowNone();
380 DataRow FindRow(int64 tag)
384 return listBox.FindRow(tag);
389 DataRow FindSubRow(int64 tag)
393 return listBox.FindSubRow(tag);
399 void SelectRow(DataRow row)
404 if(style.editText && style.changeContents)
406 char tempString[4096];
409 const char *(* onGetString)(void *, void *, char *, void *, bool *) = (void *)dataType._vTbl[__ecereVMethodID_class_OnGetString];
410 editBox.contents = onGetString(dataType, currentRow.GetData(null), tempString, null, null);
413 editBox.contents = "";
415 listBox.SelectRow(currentRow ? currentRow : (style.showNone ? noneRow : null));
423 if(editBox && editBox.modifiedDocument)
425 NotifyTextEntry(master, this, editBox.contents, true);
427 editBox.modifiedDocument = false;
436 listBoxMaxShown = 1000;
437 field = listBox.firstField;
438 dataType = field.dataType;
439 style.changeContents = true;
450 int rowCount = Min(listBox.rowCount, listBoxMaxShown);
451 int height = rowCount * ROW_HEIGHT;
452 listBox.clientSize = { clientSize.w, height };
455 void OnPosition(int x, int y, int width, int height)
459 int lx = absPosition.x - guiApp.desktop.absPosition.x;
460 int ly = absPosition.y - guiApp.desktop.absPosition.y;
461 int availHeight = pulledWindow.parent.clientSize.h;
462 int height = pulledWindow.clientSize.h;
464 // If it won't fit below but fits above, place it above...
465 if(ly + size.h + height > availHeight && height < ly)
470 if(ly + height > availHeight)
471 height = ((availHeight - ly) / ROW_HEIGHT) * ROW_HEIGHT;
474 if(!pulledWindow.initSize.w)
475 pulledWindow.size.w = size.w;
477 // Align it to the right (pull down button)
478 lx -= pulledWindow.size.w - size.w;
479 pulledWindow.position = { lx, ly };
480 pulledWindow.clientSize = { pulledWindow.clientSize.w, height };
484 bool OnKeyDown(Key key, unichar ch)
492 // ADDED THIS CHECK HERE TO NAVIGATE THROUGH GRID LISTBOX
495 if(eClass_IsDerived(master._class, class(DataBox)))
497 if(eClass_IsDerived(master.master._class, class(ListBox)))
500 else if(eClass_IsDerived(master._class, class(ListBox)))
503 if(key == escape && !pulledWindow)
505 //if(editBox) button.Deactivate();
506 //if(editBox) button.Activate();
509 if(editBox.modifiedDocument)
511 NotifyTextEntry(master, this, editBox.contents, false);
512 editBox.modifiedDocument = false;
514 //editBox.Deactivate();
518 if(style.editText && (key == space || key == right))
523 OnCloseDropDown(pulledWindow);
525 button.checked = false;
526 NotifyClose(master, this);
530 if(editBox.modifiedDocument)
532 NotifyTextEntry(master, this, editBox.contents, false);
533 editBox.modifiedDocument = false;
540 listBox.currentRow = currentRow ? currentRow : (style.showNone ? noneRow : null);
541 pulledWindow = OnDropDown();
542 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
543 if(pulledWindow) pulledWindow.visible = true;
544 button.checked = true;
554 if(editBox.modifiedDocument)
556 NotifyTextEntry(master, this, editBox.contents, true);
557 editBox.modifiedDocument = false;
558 //editBox.Deactivate();
561 // Add code to look through listbox and set current row if listbox is used
569 OnCloseDropDown(pulledWindow);
571 button.checked = false;
574 if(!NotifyClose(master, this))
580 // Moved this from below NotifySelect
581 currentRow = listBox.currentRow;
582 if(currentRow && currentRow.noneRow) currentRow = null;
583 if(style.editText && style.changeContents)
585 char tempString[4096];
588 const char *(* onGetString)(void *, void *, char *, void *, bool *) = (void *)dataType._vTbl[__ecereVMethodID_class_OnGetString];
589 editBox.contents = onGetString(dataType, currentRow.GetData(null), tempString, null, null);
592 editBox.contents = "";
595 NotifySelect(master, this, currentRow, key.modifiers | { closingDropDown = true });
602 // return listBox.OnKeyDown(key, ch);
607 void OnApplyGraphics()
609 button.anchor = { right = 0, top = 0, bottom = 0 };
610 button.size = { guiApp.textMode ? 8 : BTN_WIDTH, 0 };
615 window = this, delay = 0.01;
619 background = active ? red : lime;
620 parent.parent.background = parent.parent.active ? red : lime;
621 guiApp.desktop.Update(null);
626 void OnRedraw(Surface surface)
628 //timer.started = true;
631 if(active && !pulledWindow/*listBox.visible*/)
633 if(style.activeColor)
635 surface.SetBackground(selectionColor ? selectionColor : SELECTION_COLOR);
636 if(!style.noHighlight || !currentRow)
638 surface.Area(0,0, clientSize.w-1,clientSize.h-1);
643 surface.SetForeground(Color { 85,85,85 } );
645 surface.SetForeground((active && style.activeColor && !pulledWindow /*listBox.visible*/) ? selectionText : foreground);
646 surface.TextOpacity(true);
650 DataDisplayFlags displayFlags { active = active, current = true, dropBox = true, selected = true, fullRow = true };
651 void (* onDisplay)(void *, void *, void *, int, int, int, void *, uint, uint) = (void *)dataType._vTbl[__ecereVMethodID_class_OnDisplay];
653 onDisplay(dataType, currentRow.GetData(null), surface, 3,
654 1+(clientSize.h - listBox.rowHeight) / 2, clientSize.w - (button.visible ? button.size.w : 0) - 3,
655 field.userData, alignment, displayFlags);
658 surface.WriteText(2,2, "(none)", 6);
660 if(!style.noStipple && (!style.noHighlight || !currentRow))
662 surface.SetForeground(0xFFFFFF80);
663 if(active && !pulledWindow /*listBox.visible*/)
665 surface.Rectangle(0,0,clientSize.w-1-BTN_WIDTH,clientSize.h-1);
666 surface.SetForeground(black);
667 surface.LineStipple(0xAAAA);
668 surface.Rectangle(0,0,clientSize.w-1-BTN_WIDTH,clientSize.h-1);
669 surface.LineStipple(0);
675 bool OnResizing(int *width, int *height)
679 display.FontExtent(fontObject, "W", 1, null, &rowHeight);
680 rowHeight = Max(rowHeight, 16);
682 if(!*width) *width = Max(*width, rowHeight * 100 / 16);
684 //if(!*width) *width = Max(*width, 100);
685 //if(!*height) *height = Max(*height, 20);
686 if(!*height) *height = Max(*height, rowHeight * 20 / 16);
694 SetInitSize(initSize);
698 bool OnLeftButtonDown(int x, int y, Modifiers mods)
703 OnCloseDropDown(pulledWindow);
704 button.checked = false;
707 if(!NotifyClose(master, this))
712 listBox.currentRow = currentRow ? currentRow : (style.showNone ? noneRow : null);
713 pulledWindow = OnDropDown();
714 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
715 if(pulledWindow) pulledWindow.visible = true;
716 if(listBox.freeSelect)
717 pulledWindow.OnLeftButtonDown(-2,-2, 0);
718 button.checked = true;
723 bool OnKeyHit(Key key, unichar ch)
725 DataRow currentRow = this.currentRow;
727 if(!pulledWindow /*listBox.visible*/)
730 if(style.showNone && !currentRow) currentRow = noneRow;
735 case down: currentRow = currentRow ? currentRow.next : null; break;
737 case up: currentRow = currentRow ? currentRow.prev : null; break;
739 for(c = 0; c<listBoxMaxShown && currentRow && currentRow.next; c++, currentRow = currentRow.next);
742 for(c = 0; c<listBoxMaxShown && currentRow && currentRow.prev; c++, currentRow = currentRow.prev);
745 for(; currentRow && currentRow.next; currentRow = currentRow.next);
748 for(; currentRow && currentRow.prev; currentRow = currentRow.prev);
751 if(!editBox || button.active || !editBox.active || editBox.OnKeyHit(key, ch))
753 return listBox.OnKeyHit(key, ch);
760 if(currentRow.noneRow) currentRow = null;
761 property::currentRow = currentRow;
763 NotifySelect(master, this, currentRow, key.modifiers);
770 if(listBox.vertScroll)
773 listBox.vertScroll.Action(up, 0, key);
774 else if(key == wheelDown)
775 listBox.vertScroll.Action(down, 0, key);
777 return listBox.OnKeyHit(key, ch);
782 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
784 // WAS !active JUST MISSING HERE ?
785 if(!active && style.editText)
787 if(editBox.modifiedDocument)
789 if(editBox) editBox.modifiedDocument = false;
790 NotifyTextEntry(master, this, editBox.contents, true); //false);
791 // MOVED THIS ABOVE TO AVOID INFINITE RECURSION
792 // if(editBox) editBox.modifiedDocument = false;
794 //editBox.Deactivate();
802 this, toggle = true, bevel = true, inactive = true,
803 anchor = Anchor { right = 0, top = 0, bottom = 0 },
804 size = Size { BTN_WIDTH, 0 },
806 bitmap = { "<:ecere>elements/arrowDown.png" };
808 bool NotifyPushed(Button control, int x, int y, Modifiers mods)
812 OnCloseDropDown(pulledWindow);
814 button.checked = false;
815 NotifyClose(master, this);
820 if(editBox && editBox.modifiedDocument)
822 NotifyTextEntry(master, this, editBox.contents, true);
823 editBox.modifiedDocument = false;
825 pulledWindow = OnDropDown();
828 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
829 if(listBox.freeSelect)
830 pulledWindow.OnLeftButtonDown(-2,-2, 0);
831 button.checked = true;
832 pulledWindow.visible = true;
843 master = this, fullRowSelect = true, freeSelect = true, /* noHighlight = style.noHighlight , */
844 interim = true, hasVertScroll = true, borderStyle = contour, position = { absPosition.x, absPosition.y + size.h },
845 size.w = size.w, visible = false;
847 bool NotifyActivate(Window control, bool active, Window swap)
852 if(swap != button && swap != this)
854 if(editBox && editBox.modifiedDocument)
856 NotifyTextEntry(master, this, editBox.contents, true);
857 editBox.modifiedDocument = false;
860 OnCloseDropDown(pulledWindow);
862 button.checked = false;
863 NotifyClose(master, this);
869 bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
873 // Add code to set text to list box contents if it has an editbox
877 OnCloseDropDown(pulledWindow);
879 button.checked = false;
880 mods.closingDropDown = true;
881 if(!NotifyClose(master, this))
884 currentRow = (row && !row.noneRow) ? row : null;
885 if(style.editText && style.changeContents)
887 char tempString[4096];
890 const char *(* onGetString)(void *, void *, char *, void *, bool *) = (void *)dataType._vTbl[__ecereVMethodID_class_OnGetString];
891 editBox.contents = onGetString(dataType, currentRow.GetData(null), tempString, null, null);
894 editBox.contents = "";
899 return NotifySelect(master, this, currentRow, mods);
902 bool NotifyHighlight(ListBox control, DataRow row, Modifiers mods)
904 return NotifyHighlight(master, this, row, mods);
907 bool NotifyKeyDown(ListBox listBox, DataRow selection, Key key, unichar ch)
909 return OnKeyDown(key, ch);
917 listBox.font = { font.faceName, font.size };
930 ColorAlpha selectionColor, selectionText;
932 selectionColor = SELECTION_COLOR;
933 selectionText = SELECTION_TEXT;