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";
29 listBox.foreground = foreground;
33 listBox.background = background;
37 property bool activeStipple
39 property_category $"Appearance"
42 style.noStipple = !value;
45 get { return !style.noStipple; }
47 property bool showButton
49 property_category $"Appearance"
52 button.visible = value;
53 listBox.borderStyle = value ? contour : none;
55 get { return button.visible; }
57 property Alignment alignment
59 property_category $"Appearance"
64 field.alignment = value;
66 get { return alignment; }
68 property bool noHighlight
70 property_category $"Appearance"
75 style.noHighlight = value;
76 listBox.fullRowSelect = !value;
80 get { return style.noHighlight; }
82 property bool activeColor
84 property_category $"Appearance"
89 style.activeColor = value;
93 get { return style.activeColor; }
95 property DataRow currentRow
97 property_category $"Private"
103 listBox.currentRow = value ? value : (style.showNone ? noneRow : null);
104 if(style.editText && style.changeContents)
106 char tempString[4096];
108 editBox.contents = (char *)dataType._vTbl[__ecereVMethodID_class_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 char * contents { property_category $"Data" set { if(editBox) editBox.contents = value; } get { return editBox ? editBox.contents : null; } };
128 property bool editText
130 property_category $"Behavior"
141 this, textHorzScroll = true, borderStyle = 0;
142 anchor = Anchor { left = 0, top = 0, right = BTN_WIDTH, bottom = 0 };
143 // visible = false, modifyVirtualArea = false;
147 button.inactive = false;
149 style.editText = true;
158 button.inactive = true;
160 style.editText = false;
164 get { return style.editText; }
166 property EditBox editBox { get { return editBox; } }
167 property Seconds typingTimeout { property_category $"Behavior" set { listBox.typingTimeout = value; } get { return listBox.typingTimeout; } };
168 property int rowHeight { property_category $"Appearance" set { listBox.rowHeight = value; } get { return listBox.rowHeight; } };
169 property int maxShown
171 property_category $"Behavior"
174 listBoxMaxShown = value;
175 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
177 get { return listBoxMaxShown; }
179 property Window pullDown
181 get { return pulledWindow; }
183 property bool showNone
187 if(value != style.showNone)
191 listBox.DeleteRow(noneRow);
194 style.showNone = value;
197 noneRow = listBox.AddRowNone();
201 get { return style.showNone; }
203 property Color selectionColor { set { selectionColor = value; } get { return selectionColor; } isset { return selectionColor ? true : false; } };
204 property bool changeContents
206 set { style.changeContents = value; }
207 get { return style.changeContents; }
210 property ListBox listBox { get { return listBox; } }
213 virtual bool Window::NotifySelect(DropBox dropBox, DataRow row, Modifiers mods);
214 virtual bool Window::NotifyClose(DropBox dropBox);
215 virtual bool Window::NotifyHighlight(DropBox dropBox, DataRow row, Modifiers mods);
216 virtual bool Window::NotifyTextEntry(DropBox dropBox, char * string, bool confirmed);
218 virtual Window OnDropDown()
220 // NASTY BUG ON WINDOWS IN PROPERTIES SHEET IF WE DON'T RECREATE THE LISTBOX HERE
221 // To reproduce, comment out, select borderStyle property, alt-tab to another program, come back, drop down
222 // The listBox goes annoyingly to 0, 0
227 // listBox.visible = true;
231 virtual void OnCloseDropDown(Window pullDown)
233 listBox.visible = false;
236 editBox.ActivateEx(true, false, false, false, null, null);
242 DataRow AddStringf(char * format, ...)
248 char string[MAX_F_STRING];
251 va_start(args, format);
252 vsnprintf(string, sizeof(string), format, args);
253 string[sizeof(string)-1] = 0;
257 row.SetData(null, string);
263 DataRow AddString(char * string)
269 row.SetData(null, string);
275 void DeleteRow(DataRow row)
277 if(!row) row = currentRow;
278 listBox.DeleteRow(row);
280 if(row == currentRow)
285 // Convenience function using current rows
288 return currentRow.tag;
291 void * SetData(DataField field, any_object data)
296 return currentRow.SetData(field, data);
301 any_object GetData(DataField field)
305 // TODO: Fix this shouldn't be required (memguard?)
306 return (void *)currentRow.GetData(field);
311 void Sort(DataField field, int order)
313 listBox.Sort(field, order);
316 void AddField(DataField field)
321 field = DataField { alignment = alignment };
323 listBox.AddField(field);
324 this.field = listBox.firstField;
325 dataType = this.field.dataType;
334 row = listBox.AddRow();
335 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
340 DataRow AddRowAfter(DataRow after)
345 row = listBox.AddRowAfter(after);
346 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
353 return listBox.rowCount;
360 Window master = this.master;
363 if(currentRow && master)
366 NotifySelect(master, this, null, 0);
369 if(style.editText && style.changeContents)
370 editBox.contents = "";
373 noneRow = listBox.AddRowNone();
377 DataRow FindRow(int tag)
381 return listBox.FindRow(tag);
386 DataRow FindSubRow(int tag)
390 return listBox.FindSubRow(tag);
396 void SelectRow(DataRow row)
401 if(style.editText && style.changeContents)
403 char tempString[4096];
405 editBox.contents = (char *)dataType._vTbl[__ecereVMethodID_class_OnGetString](dataType, currentRow.GetData(null), tempString, null, null);
407 editBox.contents = "";
409 listBox.SelectRow(currentRow ? currentRow : (style.showNone ? noneRow : null));
417 if(editBox && editBox.modifiedDocument)
419 NotifyTextEntry(master, this, editBox.contents, true);
421 editBox.modifiedDocument = false;
430 listBoxMaxShown = 1000;
431 field = listBox.firstField;
432 dataType = field.dataType;
433 style.changeContents = true;
444 int rowCount = Min(listBox.rowCount, listBoxMaxShown);
445 int height = rowCount * ROW_HEIGHT;
446 listBox.clientSize = { clientSize.w, height };
449 void OnPosition(int x, int y, int width, int height)
453 int lx = absPosition.x - guiApp.desktop.absPosition.x;
454 int ly = absPosition.y - guiApp.desktop.absPosition.y;
455 int availHeight = pulledWindow.parent.clientSize.h;
456 int height = pulledWindow.clientSize.h;
458 // If it won't fit below but fits above, place it above...
459 if(ly + size.h + height > availHeight && height < ly)
464 if(ly + height > availHeight)
465 height = ((availHeight - ly) / ROW_HEIGHT) * ROW_HEIGHT;
468 if(!pulledWindow.initSize.w)
469 pulledWindow.size.w = size.w;
471 // Align it to the right (pull down button)
472 lx -= pulledWindow.size.w - size.w;
473 pulledWindow.position = { lx, ly };
474 pulledWindow.clientSize = { pulledWindow.clientSize.w, height };
478 bool OnKeyDown(Key key, unichar ch)
486 // ADDED THIS CHECK HERE TO NAVIGATE THROUGH GRID LISTBOX
489 if(eClass_IsDerived(master._class, class(DataBox)))
491 if(eClass_IsDerived(master.master._class, class(ListBox)))
494 else if(eClass_IsDerived(master._class, class(ListBox)))
497 if(key == escape && !pulledWindow)
499 //if(editBox) button.Deactivate();
500 //if(editBox) button.Activate();
503 if(editBox.modifiedDocument)
505 NotifyTextEntry(master, this, editBox.contents, false);
506 editBox.modifiedDocument = false;
508 //editBox.Deactivate();
512 if(style.editText && (key == space || key == right))
517 OnCloseDropDown(pulledWindow);
519 button.checked = false;
520 NotifyClose(master, this);
524 if(editBox.modifiedDocument)
526 NotifyTextEntry(master, this, editBox.contents, false);
527 editBox.modifiedDocument = false;
534 listBox.currentRow = currentRow ? currentRow : (style.showNone ? noneRow : null);
535 pulledWindow = OnDropDown();
536 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
537 if(pulledWindow) pulledWindow.visible = true;
538 button.checked = true;
548 if(editBox.modifiedDocument)
550 NotifyTextEntry(master, this, editBox.contents, true);
551 editBox.modifiedDocument = false;
552 //editBox.Deactivate();
555 // Add code to look through listbox and set current row if listbox is used
563 OnCloseDropDown(pulledWindow);
565 button.checked = false;
568 if(!NotifyClose(master, this))
574 // Moved this from below NotifySelect
575 currentRow = listBox.currentRow;
576 if(currentRow && currentRow.noneRow) currentRow = null;
577 if(style.editText && style.changeContents)
579 char tempString[4096];
581 editBox.contents = (char *)dataType._vTbl[__ecereVMethodID_class_OnGetString](dataType, currentRow.GetData(null), tempString, null, null);
583 editBox.contents = "";
586 NotifySelect(master, this, currentRow, key.modifiers | { closingDropDown = true });
593 // return listBox.OnKeyDown(key, ch);
598 void OnApplyGraphics()
600 button.anchor = { right = 0, top = 0, bottom = 0 };
601 button.size = { guiApp.textMode ? 8 : BTN_WIDTH, 0 };
606 window = this, delay = 0.01;
610 background = active ? red : lime;
611 parent.parent.background = parent.parent.active ? red : lime;
612 guiApp.desktop.Update(null);
617 void OnRedraw(Surface surface)
619 //timer.started = true;
622 if(active && !pulledWindow/*listBox.visible*/)
624 if(style.activeColor)
626 surface.SetBackground(selectionColor ? selectionColor : SELECTION_COLOR);
627 if(!style.noHighlight || !currentRow)
629 surface.Area(0,0, clientSize.w-1,clientSize.h-1);
634 surface.SetForeground(Color { 85,85,85 } );
636 surface.SetForeground((active && style.activeColor && !pulledWindow /*listBox.visible*/) ? SELECTION_TEXT : foreground);
637 surface.TextOpacity(true);
641 DataDisplayFlags displayFlags { active = active, current = true, dropBox = true, selected = true, fullRow = true };
642 dataType._vTbl[__ecereVMethodID_class_OnDisplay](dataType, currentRow.GetData(null), surface, 3,
643 1+(clientSize.h - listBox.rowHeight) / 2, clientSize.w - (button.visible ? button.size.w : 0) - 3,
644 field.userData, alignment, displayFlags);
647 surface.WriteText(2,2, "(none)", 6);
649 if(!style.noStipple && (!style.noHighlight || !currentRow))
651 surface.SetForeground(0xFFFFFF80);
652 if(active && !pulledWindow /*listBox.visible*/)
654 surface.Rectangle(0,0,clientSize.w-1-BTN_WIDTH,clientSize.h-1);
655 surface.SetForeground(black);
656 surface.LineStipple(0xAAAA);
657 surface.Rectangle(0,0,clientSize.w-1-BTN_WIDTH,clientSize.h-1);
658 surface.LineStipple(0);
664 bool OnResizing(int *width, int *height)
668 display.FontExtent(fontObject, "W", 1, null, &rowHeight);
669 rowHeight = Max(rowHeight, 16);
671 if(!*width) *width = Max(*width, rowHeight * 100 / 16);
673 //if(!*width) *width = Max(*width, 100);
674 //if(!*height) *height = Max(*height, 20);
675 if(!*height) *height = Max(*height, rowHeight * 20 / 16);
683 SetInitSize(initSize);
687 bool OnLeftButtonDown(int x, int y, Modifiers mods)
692 OnCloseDropDown(pulledWindow);
693 button.checked = false;
696 if(!NotifyClose(master, this))
701 listBox.currentRow = currentRow ? currentRow : (style.showNone ? noneRow : null);
702 pulledWindow = OnDropDown();
703 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
704 if(pulledWindow) pulledWindow.visible = true;
705 if(listBox.freeSelect)
706 pulledWindow.OnLeftButtonDown(-2,-2, 0);
707 button.checked = true;
712 bool OnKeyHit(Key key, unichar ch)
714 DataRow currentRow = this.currentRow;
716 if(!pulledWindow /*listBox.visible*/)
719 if(style.showNone && !currentRow) currentRow = noneRow;
724 case down: currentRow = currentRow ? currentRow.next : null; break;
726 case up: currentRow = currentRow ? currentRow.prev : null; break;
728 for(c = 0; c<listBoxMaxShown && currentRow && currentRow.next; c++, currentRow = currentRow.next);
731 for(c = 0; c<listBoxMaxShown && currentRow && currentRow.prev; c++, currentRow = currentRow.prev);
734 for(; currentRow && currentRow.next; currentRow = currentRow.next);
737 for(; currentRow && currentRow.prev; currentRow = currentRow.prev);
740 if(!editBox || button.active || !editBox.active || editBox.OnKeyHit(key, ch))
742 return listBox.OnKeyHit(key, ch);
749 if(currentRow.noneRow) currentRow = null;
750 property::currentRow = currentRow;
752 NotifySelect(master, this, currentRow, key.modifiers);
759 if(listBox.vertScroll)
762 listBox.vertScroll.Action(up, 0, key);
763 else if(key == wheelDown)
764 listBox.vertScroll.Action(down, 0, key);
766 return listBox.OnKeyHit(key, ch);
771 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
773 // WAS !active JUST MISSING HERE ?
774 if(!active && style.editText)
776 if(editBox.modifiedDocument)
778 if(editBox) editBox.modifiedDocument = false;
779 NotifyTextEntry(master, this, editBox.contents, true); //false);
780 // MOVED THIS ABOVE TO AVOID INFINITE RECURSION
781 // if(editBox) editBox.modifiedDocument = false;
783 //editBox.Deactivate();
791 this, toggle = true, bevel = true, inactive = true,
792 anchor = Anchor { right = 0, top = 0, bottom = 0 },
793 size = Size { BTN_WIDTH, 0 },
795 bitmap = { "<:ecere>elements/arrowDown.png" };
797 bool NotifyPushed(Button control, int x, int y, Modifiers mods)
801 OnCloseDropDown(pulledWindow);
803 button.checked = false;
804 NotifyClose(master, this);
809 if(editBox && editBox.modifiedDocument)
811 NotifyTextEntry(master, this, editBox.contents, true);
812 editBox.modifiedDocument = false;
814 pulledWindow = OnDropDown();
817 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
818 if(listBox.freeSelect)
819 pulledWindow.OnLeftButtonDown(-2,-2, 0);
820 button.checked = true;
821 pulledWindow.visible = true;
832 master = this, fullRowSelect = true, freeSelect = true, /* noHighlight = style.noHighlight , */
833 interim = true, hasVertScroll = true, borderStyle = contour, position = { absPosition.x, absPosition.y + size.h },
834 size.w = size.w, visible = false;
836 bool NotifyActivate(Window control, bool active, Window swap)
841 if(swap != button && swap != this)
843 if(editBox && editBox.modifiedDocument)
845 NotifyTextEntry(master, this, editBox.contents, true);
846 editBox.modifiedDocument = false;
849 OnCloseDropDown(pulledWindow);
851 button.checked = false;
852 NotifyClose(master, this);
858 bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
862 // Add code to set text to list box contents if it has an editbox
866 OnCloseDropDown(pulledWindow);
868 button.checked = false;
869 mods.closingDropDown = true;
870 if(!NotifyClose(master, this))
873 currentRow = (row && !row.noneRow) ? row : null;
874 if(style.editText && style.changeContents)
876 char tempString[4096];
878 editBox.contents = (char *)dataType._vTbl[__ecereVMethodID_class_OnGetString](dataType, currentRow.GetData(null), tempString, null, null);
880 editBox.contents = "";
885 return NotifySelect(master, this, currentRow, mods);
888 bool NotifyHighlight(ListBox control, DataRow row, Modifiers mods)
890 return NotifyHighlight(master, this, row, mods);
893 bool NotifyKeyDown(ListBox listBox, DataRow selection, Key key, unichar ch)
895 return OnKeyDown(key, ch);
903 listBox.font = { font.faceName, font.size };
916 Color selectionColor;