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)
242 listBox.visible = false;
245 editBox.ActivateEx(true, false, false, false, null, null);
252 DataRow AddStringf(const char * format, ...)
258 char string[MAX_F_STRING];
261 va_start(args, format);
262 vsnprintf(string, sizeof(string), format, args);
263 string[sizeof(string)-1] = 0;
267 row.SetData(null, string);
273 DataRow AddString(const char * string)
279 row.SetData(null, string);
285 void DeleteRow(DataRow row)
287 if(!row) row = currentRow;
288 listBox.DeleteRow(row);
290 if(row == currentRow)
295 // Convenience function using current rows
298 return currentRow.tag;
301 void * SetData(DataField field, any_object data)
306 return currentRow.SetData(field, data);
311 any_object GetData(DataField field)
313 return this ? currentRow.GetData(field) : null;
316 void Sort(DataField field, int order)
318 listBox.Sort(field, order);
321 void AddField(DataField field)
326 field = DataField { alignment = alignment };
328 listBox.AddField(field);
329 this.field = listBox.firstField;
330 dataType = this.field.dataType;
339 row = listBox.AddRow();
340 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
345 DataRow AddRowAfter(DataRow after)
350 row = listBox.AddRowAfter(after);
351 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
358 return listBox.rowCount;
365 Window master = this.master;
368 if(currentRow && master)
371 NotifySelect(master, this, null, 0);
374 if(style.editText && style.changeContents)
375 editBox.contents = "";
378 noneRow = listBox.AddRowNone();
382 DataRow FindRow(int64 tag)
386 return listBox.FindRow(tag);
391 DataRow FindSubRow(int64 tag)
395 return listBox.FindSubRow(tag);
401 void SelectRow(DataRow row)
406 if(style.editText && style.changeContents)
408 char tempString[4096];
411 const char *(* onGetString)(void *, void *, char *, void *, bool *) = (void *)dataType._vTbl[__ecereVMethodID_class_OnGetString];
412 editBox.contents = onGetString(dataType, currentRow.GetData(null), tempString, null, null);
415 editBox.contents = "";
417 listBox.SelectRow(currentRow ? currentRow : (style.showNone ? noneRow : null));
425 if(editBox && editBox.modifiedDocument)
427 NotifyTextEntry(master, this, editBox.contents, true);
429 editBox.modifiedDocument = false;
438 listBoxMaxShown = 1000;
439 field = listBox.firstField;
440 dataType = field.dataType;
441 style.changeContents = true;
452 int rowCount = Min(listBox.rowCount, listBoxMaxShown);
453 int height = rowCount * ROW_HEIGHT;
454 listBox.clientSize = { clientSize.w, height };
457 void OnPosition(int x, int y, int width, int height)
461 int lx = absPosition.x - guiApp.desktop.absPosition.x;
462 int ly = absPosition.y - guiApp.desktop.absPosition.y;
463 int availHeight = pulledWindow.parent.clientSize.h;
464 int height = pulledWindow.clientSize.h;
466 // If it won't fit below but fits above, place it above...
467 if(ly + size.h + height > availHeight && height < ly)
472 if(ly + height > availHeight)
473 height = ((availHeight - ly) / ROW_HEIGHT) * ROW_HEIGHT;
476 if(!pulledWindow.initSize.w)
477 pulledWindow.size.w = size.w;
479 // Align it to the right (pull down button)
480 lx -= pulledWindow.size.w - size.w;
481 pulledWindow.position = { lx, ly };
482 pulledWindow.clientSize = { pulledWindow.clientSize.w, height };
486 bool OnKeyDown(Key key, unichar ch)
494 // ADDED THIS CHECK HERE TO NAVIGATE THROUGH GRID LISTBOX
497 if(eClass_IsDerived(master._class, class(DataBox)))
499 if(eClass_IsDerived(master.master._class, class(ListBox)))
502 else if(eClass_IsDerived(master._class, class(ListBox)))
505 if(key == escape && !pulledWindow)
507 //if(editBox) button.Deactivate();
508 //if(editBox) button.Activate();
511 if(editBox.modifiedDocument)
513 NotifyTextEntry(master, this, editBox.contents, false);
514 editBox.modifiedDocument = false;
516 //editBox.Deactivate();
520 if(style.editText && (key == space || key == right))
525 OnCloseDropDown(pulledWindow);
527 button.checked = false;
528 NotifyClose(master, this);
532 if(editBox.modifiedDocument)
534 NotifyTextEntry(master, this, editBox.contents, false);
535 editBox.modifiedDocument = false;
542 listBox.currentRow = currentRow ? currentRow : (style.showNone ? noneRow : null);
543 pulledWindow = OnDropDown();
544 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
545 if(pulledWindow) pulledWindow.visible = true;
546 button.checked = true;
556 if(editBox.modifiedDocument)
558 NotifyTextEntry(master, this, editBox.contents, true);
559 editBox.modifiedDocument = false;
560 //editBox.Deactivate();
563 // Add code to look through listbox and set current row if listbox is used
571 OnCloseDropDown(pulledWindow);
573 button.checked = false;
576 if(!NotifyClose(master, this))
582 // Moved this from below NotifySelect
583 currentRow = listBox.currentRow;
584 if(currentRow && currentRow.noneRow) currentRow = null;
585 if(style.editText && style.changeContents)
587 char tempString[4096];
590 const char *(* onGetString)(void *, void *, char *, void *, bool *) = (void *)dataType._vTbl[__ecereVMethodID_class_OnGetString];
591 editBox.contents = onGetString(dataType, currentRow.GetData(null), tempString, null, null);
594 editBox.contents = "";
597 NotifySelect(master, this, currentRow, key.modifiers | { closingDropDown = true });
604 // return listBox.OnKeyDown(key, ch);
609 void OnApplyGraphics()
611 button.anchor = { right = 0, top = 0, bottom = 0 };
612 button.size = { guiApp.textMode ? 8 : BTN_WIDTH, 0 };
617 window = this, delay = 0.01;
621 background = active ? red : lime;
622 parent.parent.background = parent.parent.active ? red : lime;
623 guiApp.desktop.Update(null);
628 void OnRedraw(Surface surface)
630 //timer.started = true;
633 if(active && !pulledWindow/*listBox.visible*/)
635 if(style.activeColor)
637 surface.SetBackground(selectionColor ? selectionColor : SELECTION_COLOR);
638 if(!style.noHighlight || !currentRow)
640 surface.Area(0,0, clientSize.w-1,clientSize.h-1);
645 surface.SetForeground(Color { 85,85,85 } );
647 surface.SetForeground((active && style.activeColor && !pulledWindow /*listBox.visible*/) ? selectionText : foreground);
648 surface.TextOpacity(true);
652 DataDisplayFlags displayFlags { active = active, current = true, dropBox = true, selected = true, fullRow = true };
653 void (* onDisplay)(void *, void *, void *, int, int, int, void *, uint, uint) = (void *)dataType._vTbl[__ecereVMethodID_class_OnDisplay];
655 onDisplay(dataType, currentRow.GetData(null), surface, 3,
656 1+(clientSize.h - listBox.rowHeight) / 2, clientSize.w - (button.visible ? button.size.w : 0) - 3,
657 field.userData, alignment, displayFlags);
660 surface.WriteText(2,2, "(none)", 6);
662 if(!style.noStipple && (!style.noHighlight || !currentRow))
664 surface.SetForeground(0xFFFFFF80);
665 if(active && !pulledWindow /*listBox.visible*/)
667 surface.Rectangle(0,0,clientSize.w-1-BTN_WIDTH,clientSize.h-1);
668 surface.SetForeground(black);
669 surface.LineStipple(0xAAAA);
670 surface.Rectangle(0,0,clientSize.w-1-BTN_WIDTH,clientSize.h-1);
671 surface.LineStipple(0);
677 bool OnResizing(int *width, int *height)
681 display.FontExtent(fontObject, "W", 1, null, &rowHeight);
682 rowHeight = Max(rowHeight, 16);
684 if(!*width) *width = Max(*width, rowHeight * 100 / 16);
686 //if(!*width) *width = Max(*width, 100);
687 //if(!*height) *height = Max(*height, 20);
688 if(!*height) *height = Max(*height, rowHeight * 20 / 16);
696 SetInitSize(initSize);
700 bool OnLeftButtonDown(int x, int y, Modifiers mods)
705 OnCloseDropDown(pulledWindow);
706 button.checked = false;
709 if(!NotifyClose(master, this))
714 listBox.currentRow = currentRow ? currentRow : (style.showNone ? noneRow : null);
715 pulledWindow = OnDropDown();
716 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
717 if(pulledWindow) pulledWindow.visible = true;
718 if(listBox.freeSelect)
719 pulledWindow.OnLeftButtonDown(-2,-2, 0);
720 button.checked = true;
725 bool OnKeyHit(Key key, unichar ch)
727 DataRow currentRow = this.currentRow;
729 if(!pulledWindow /*listBox.visible*/)
732 if(style.showNone && !currentRow) currentRow = noneRow;
737 case down: currentRow = currentRow ? currentRow.next : null; break;
739 case up: currentRow = currentRow ? currentRow.prev : null; break;
741 for(c = 0; c<listBoxMaxShown && currentRow && currentRow.next; c++, currentRow = currentRow.next);
744 for(c = 0; c<listBoxMaxShown && currentRow && currentRow.prev; c++, currentRow = currentRow.prev);
747 for(; currentRow && currentRow.next; currentRow = currentRow.next);
750 for(; currentRow && currentRow.prev; currentRow = currentRow.prev);
753 if(!editBox || button.active || !editBox.active || editBox.OnKeyHit(key, ch))
755 return listBox.OnKeyHit(key, ch);
762 if(currentRow.noneRow) currentRow = null;
763 property::currentRow = currentRow;
765 NotifySelect(master, this, currentRow, key.modifiers);
772 if(listBox.vertScroll)
775 listBox.vertScroll.Action(up, 0, key);
776 else if(key == wheelDown)
777 listBox.vertScroll.Action(down, 0, key);
779 return listBox.OnKeyHit(key, ch);
784 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
786 // WAS !active JUST MISSING HERE ?
787 if(!active && style.editText)
789 if(editBox.modifiedDocument)
791 if(editBox) editBox.modifiedDocument = false;
792 NotifyTextEntry(master, this, editBox.contents, true); //false);
793 // MOVED THIS ABOVE TO AVOID INFINITE RECURSION
794 // if(editBox) editBox.modifiedDocument = false;
796 //editBox.Deactivate();
804 this, toggle = true, bevel = true, inactive = true,
805 anchor = Anchor { right = 0, top = 0, bottom = 0 },
806 size = Size { BTN_WIDTH, 0 },
808 bitmap = { "<:ecere>elements/arrowDown.png" };
810 bool NotifyPushed(Button control, int x, int y, Modifiers mods)
814 OnCloseDropDown(pulledWindow);
816 button.checked = false;
817 NotifyClose(master, this);
822 if(editBox && editBox.modifiedDocument)
824 NotifyTextEntry(master, this, editBox.contents, true);
825 editBox.modifiedDocument = false;
827 pulledWindow = OnDropDown();
830 OnPosition(position.x, position.y, clientSize.w, clientSize.h);
831 if(listBox.freeSelect)
832 pulledWindow.OnLeftButtonDown(-2,-2, 0);
833 button.checked = true;
834 pulledWindow.visible = true;
845 master = this, fullRowSelect = true, freeSelect = true, /* noHighlight = style.noHighlight , */
846 interim = true, hasVertScroll = true, borderStyle = contour, position = { absPosition.x, absPosition.y + size.h },
847 size.w = size.w, visible = false;
849 bool NotifyActivate(Window control, bool active, Window swap)
854 if(swap != button && swap != this)
856 if(editBox && editBox.modifiedDocument)
858 NotifyTextEntry(master, this, editBox.contents, true);
859 editBox.modifiedDocument = false;
862 OnCloseDropDown(pulledWindow);
864 button.checked = false;
865 NotifyClose(master, this);
871 bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
877 // Add code to set text to list box contents if it has an editbox
881 OnCloseDropDown(pulledWindow);
883 button.checked = false;
884 mods.closingDropDown = true;
885 if(!NotifyClose(master, this))
891 currentRow = (row && !row.noneRow) ? row : null;
892 if(style.editText && style.changeContents)
894 char tempString[4096];
897 const char *(* onGetString)(void *, void *, char *, void *, bool *) = (void *)dataType._vTbl[__ecereVMethodID_class_OnGetString];
898 editBox.contents = onGetString(dataType, currentRow.GetData(null), tempString, null, null);
901 editBox.contents = "";
906 result = NotifySelect(master, this, currentRow, mods);
911 bool NotifyHighlight(ListBox control, DataRow row, Modifiers mods)
913 return NotifyHighlight(master, this, row, mods);
916 bool NotifyKeyDown(ListBox listBox, DataRow selection, Key key, unichar ch)
918 return OnKeyDown(key, ch);
926 listBox.font = { font.faceName, font.size };
939 ColorAlpha selectionColor, selectionText;
941 // TO REVIEW: This was blacked out when currentSkin was not yet initialized
942 selectionColor = guiApp.currentSkin ? SELECTION_COLOR : Color { 10, 36, 106 };
943 selectionText = guiApp.currentSkin ? SELECTION_TEXT : white;