abed8ad5d88ce98cb77f335a6f4d916be965e63a
[sdk] / ecere / src / gui / controls / DropBox.ec
1 namespace gui::controls;
2
3 import "Window"
4
5 #include <stdarg.h>
6
7 //#define BTN_WIDTH       20
8 #define BTN_WIDTH       16
9 #define ROW_HEIGHT      listBox.rowHeight /*16*/
10
11 default:
12 extern int __ecereVMethodID_class_OnDisplay;
13 extern int __ecereVMethodID_class_OnGetString;
14
15 private:
16
17 class DropBoxBits { bool noHighlight:1, noStipple:1, editText:1, activeColor:1, showNone:1, changeContents:1; };
18
19 public class DropBox : CommonControl
20 {
21    tabCycle = true;
22    borderStyle = deep;
23    style.activeColor = true;
24
25    class_property(icon) = "<:ecere>controls/dropBox.png";
26
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; };
32
33 public:
34    property bool activeStipple
35    {
36       property_category $"Appearance"
37       set
38       {
39          style.noStipple = !value;
40          Update(null);
41       }
42       get { return !style.noStipple; }
43    };
44    property bool showButton
45    {
46       property_category $"Appearance"
47       set
48       {
49          button.visible = value;
50          listBox.borderStyle = value ? contour : none;
51       }
52       get { return button.visible; }
53    };
54    property Alignment alignment
55    {
56       property_category $"Appearance"
57       set
58       {
59          alignment = value;
60          if(field)
61             field.alignment = value;
62       }
63       get { return alignment; }
64    };
65    property bool noHighlight
66    {
67       property_category $"Appearance"
68       set
69       {
70          if(this)
71          {
72             style.noHighlight = value;
73             listBox.fullRowSelect = !value;
74             Update(null);
75          }
76       }
77       get { return style.noHighlight; }
78    };
79    property bool activeColor
80    {
81       property_category $"Appearance"
82       set
83       {
84          if(this)
85          {
86             style.activeColor = value;
87             Update(null);
88          }
89       }
90       get { return style.activeColor; }
91    };
92    property DataRow currentRow
93    {
94       property_category $"Private"
95       set
96       {
97          if(this)
98          {
99             currentRow = value;
100             listBox.currentRow = value ? value : (style.showNone ? noneRow : null);
101             if(style.editText && style.changeContents)
102             {
103                char tempString[4096];
104                if(currentRow)
105                {
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);
108                }
109                else
110                   editBox.contents = "";
111             }
112             Update(null);
113             if(style.editText)
114             {
115                if(editBox.modifiedDocument)
116                {
117                   NotifyTextEntry(master, this, editBox.contents, false);
118                   editBox.modifiedDocument = false;
119                }
120                // editBox.Deactivate();
121             }
122          }
123       }
124       get { return currentRow; }
125    };
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
130    {
131       property_category $"Behavior"
132       set
133       {
134          if(this)
135          {
136             if(value)
137             {
138                if(!editBox)
139                {
140                   editBox = EditBox
141                   {
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;
149                   };
150                   incref editBox;
151                   editBox.Create();
152                   button.inactive = false;
153                }
154                style.editText = true;
155                tabCycle = false;
156             }
157             else
158             {
159                if(editBox)
160                {
161                   editBox.Destroy(0);
162                   delete editBox;
163                   button.inactive = true;
164                }
165                style.editText = false;
166             }
167          }
168       }
169       get { return style.editText; }
170    };
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
175    {
176       property_category $"Behavior"
177       set
178       {
179          listBoxMaxShown = value;
180          OnPosition(position.x, position.y, clientSize.w, clientSize.h);
181       }
182       get { return listBoxMaxShown; }
183    };
184    property Window pullDown
185    {
186       get { return pulledWindow; }
187    }
188    property bool showNone
189    {
190       set
191       {
192          if(value != style.showNone)
193          {
194             if(style.showNone)
195             {
196                listBox.DeleteRow(noneRow);
197                noneRow = null;
198             }
199             style.showNone = value;
200             if(value)
201             {
202                noneRow = listBox.AddRowNone();
203             }
204          }
205       }
206       get { return style.showNone; }
207    }
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
211    {
212       set { style.changeContents = value; }
213       get { return style.changeContents; }
214    }
215
216    property ListBox listBox { get { return listBox; } }
217
218    property int rowCount { get { return listBox.rowCount; } }
219
220    // Notifications
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);
225
226    virtual Window OnDropDown()
227    {
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
231       listBox.Destroy(0);
232       listBox.Create();
233
234       ResizeListbox();
235       // listBox.visible = true;
236       return listBox;
237    }
238
239    virtual void OnCloseDropDown(Window pullDown)
240    {
241       listBox.visible = false;
242       if(style.editText)
243       {
244          editBox.ActivateEx(true, false, false, false, null, null);
245          editBox.SelectAll();
246       }
247    }
248
249    // Methods
250    DataRow AddStringf(const char * format, ...)
251    {
252       if(this)
253       {
254          DataRow row;
255
256          char string[MAX_F_STRING];
257          va_list args;
258
259          va_start(args, format);
260          vsnprintf(string, sizeof(string), format, args);
261          string[sizeof(string)-1] = 0;
262          va_end(args);
263
264          row = AddRow();
265          row.SetData(null, string);
266          return row;
267       }
268       return null;
269    }
270
271    DataRow AddString(const char * string)
272    {
273       if(this)
274       {
275          DataRow row;
276          row = AddRow();
277          row.SetData(null, string);
278          return row;
279       }
280       return null;
281    }
282
283    void DeleteRow(DataRow row)
284    {
285       if(!row) row = currentRow;
286       listBox.DeleteRow(row);
287       /*
288       if(row == currentRow)
289          currentRow = null;*/
290       Update(null);
291    }
292
293    // Convenience function using current rows
294    int64 GetTag()
295    {
296       return currentRow.tag;
297    }
298
299    void * SetData(DataField field, any_object data)
300    {
301       if(this)
302       {
303          if(currentRow)
304             return currentRow.SetData(field, data);
305       }
306       return null;
307    }
308
309    any_object GetData(DataField field)
310    {
311       return this ? currentRow.GetData(field) : null;
312    }
313
314    void Sort(DataField field, int order)
315    {
316       listBox.Sort(field, order);
317    }
318
319    void AddField(DataField field)
320    {
321       if(this)
322       {
323          if(!field)
324             field = DataField { alignment = alignment };
325
326          listBox.AddField(field);
327          this.field = listBox.firstField;
328          dataType = this.field.dataType;
329       }
330    }
331
332    DataRow AddRow()
333    {
334       DataRow row = null;
335       if(this)
336       {
337          row = listBox.AddRow();
338          OnPosition(position.x, position.y, clientSize.w, clientSize.h);
339       }
340       return row;
341    }
342
343    DataRow AddRowAfter(DataRow after)
344    {
345       DataRow row = null;
346       if(this)
347       {
348          row = listBox.AddRowAfter(after);
349          OnPosition(position.x, position.y, clientSize.w, clientSize.h);
350       }
351       return row;
352    }
353
354    int GetRowCount()
355    {
356       return listBox.rowCount;
357    }
358
359    void Clear()
360    {
361       if(this)
362       {
363          Window master = this.master;
364          listBox.Clear();
365
366          if(currentRow && master)
367          {
368             currentRow = null;
369             NotifySelect(master, this, null, 0);
370          }
371          currentRow = null;
372          if(style.editText && style.changeContents)
373             editBox.contents = "";
374          Update(null);
375          if(style.showNone)
376             noneRow = listBox.AddRowNone();
377       }
378    }
379
380    DataRow FindRow(int64 tag)
381    {
382       if(this)
383       {
384          return listBox.FindRow(tag);
385       }
386       return null;
387    }
388
389    DataRow FindSubRow(int64 tag)
390    {
391       if(this)
392       {
393          return listBox.FindSubRow(tag);
394       }
395       return null;
396    }
397
398    // Drop Box Specific
399    void SelectRow(DataRow row)
400    {
401       if(this)
402       {
403          currentRow = row;
404          if(style.editText && style.changeContents)
405          {
406             char tempString[4096];
407             if(currentRow)
408             {
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);
411             }
412             else
413                editBox.contents = "";
414          }
415          listBox.SelectRow(currentRow ? currentRow : (style.showNone ? noneRow : null));
416
417          Update(null);
418       }
419    }
420
421    bool Save()
422    {
423       if(editBox && editBox.modifiedDocument)
424       {
425          NotifyTextEntry(master, this, editBox.contents, true);
426          if(editBox)
427             editBox.modifiedDocument = false;
428          return true;
429       }
430       return false;
431    }
432
433 private:
434    DropBox()
435    {
436       listBoxMaxShown = 1000;
437       field = listBox.firstField;
438       dataType = field.dataType;
439       style.changeContents = true;
440       return true;
441    }
442
443    ~DropBox()
444    {
445       delete editBox;
446    }
447
448    void ResizeListbox()
449    {
450       int rowCount = Min(listBox.rowCount, listBoxMaxShown);
451       int height = rowCount * ROW_HEIGHT;
452       listBox.clientSize = { clientSize.w, height };
453    }
454
455    void OnPosition(int x, int y, int width, int height)
456    {
457       if(pulledWindow)
458       {
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;
463
464          // If it won't fit below but fits above, place it above...
465          if(ly + size.h + height > availHeight && height < ly)
466             ly -= height;
467          else
468          {
469             ly += size.h;
470             if(ly + height > availHeight)
471                height = ((availHeight - ly) / ROW_HEIGHT) * ROW_HEIGHT;
472          }
473
474          if(!pulledWindow.initSize.w)
475             pulledWindow.size.w = size.w;
476          else
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 };
481       }
482    }
483
484    bool OnKeyDown(Key key, unichar ch)
485    {
486       switch(key)
487       {
488          case hotKey:
489          case space:
490          case right:
491          case escape:
492             // ADDED THIS CHECK HERE TO NAVIGATE THROUGH GRID LISTBOX
493             if(key == right)
494             {
495                if(eClass_IsDerived(master._class, class(DataBox)))
496                {
497                   if(eClass_IsDerived(master.master._class, class(ListBox)))
498                      return true;
499                }
500                else if(eClass_IsDerived(master._class, class(ListBox)))
501                   return true;
502             }
503             if(key == escape && !pulledWindow)
504             {
505                //if(editBox) button.Deactivate();
506                //if(editBox) button.Activate();
507                if(style.editText)
508                {
509                   if(editBox.modifiedDocument)
510                   {
511                      NotifyTextEntry(master, this, editBox.contents, false);
512                      editBox.modifiedDocument = false;
513                   }
514                   //editBox.Deactivate();
515                }
516                break;
517             }
518             if(style.editText && (key == space || key == right))
519                break;
520
521             if(pulledWindow)
522             {
523                OnCloseDropDown(pulledWindow);
524                pulledWindow = null;
525                button.checked = false;
526                NotifyClose(master, this);
527
528                if(style.editText)
529                {
530                   if(editBox.modifiedDocument)
531                   {
532                      NotifyTextEntry(master, this, editBox.contents, false);
533                      editBox.modifiedDocument = false;
534                   }
535                   editBox.Activate();
536                }
537             }
538             else
539             {
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;
545             }
546             Update(null);
547             return false;
548          case enter:
549          case keyPadEnter:
550             if(!pulledWindow)
551             {
552                if(style.editText)
553                {
554                   if(editBox.modifiedDocument)
555                   {
556                      NotifyTextEntry(master, this, editBox.contents, true);
557                      editBox.modifiedDocument = false;
558                      //editBox.Deactivate();
559                   }
560
561                   // Add code to look through listbox and set current row if listbox is used
562                }
563                break;
564             }
565             else
566             {
567                incref this;
568
569                OnCloseDropDown(pulledWindow);
570                pulledWindow = null;
571                button.checked = false;
572                Update(null);
573
574                if(!NotifyClose(master, this))
575                {
576                   delete this;
577                   return false;
578                }
579
580                // Moved this from below NotifySelect
581                currentRow = listBox.currentRow;
582                if(currentRow && currentRow.noneRow) currentRow = null;
583                if(style.editText && style.changeContents)
584                {
585                   char tempString[4096];
586                   if(currentRow)
587                   {
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);
590                   }
591                   else
592                      editBox.contents = "";
593                }
594
595                NotifySelect(master, this, currentRow, key.modifiers | { closingDropDown = true });
596
597                delete this;
598                return false;
599             }
600             return false;
601          //default:
602          //   return listBox.OnKeyDown(key, ch);
603       }
604       return true;
605    }
606
607    void OnApplyGraphics()
608    {
609       button.anchor = { right = 0, top = 0, bottom = 0 };
610       button.size = { guiApp.textMode ? 8 : BTN_WIDTH, 0 };
611    }
612
613    /*Timer timer
614    {
615       window = this, delay = 0.01;
616
617       bool DelayExpired()
618       {
619          background = active ? red : lime;
620          parent.parent.background = parent.parent.active ? red : lime;
621          guiApp.desktop.Update(null);
622          return true;
623       }
624    };*/
625
626    void OnRedraw(Surface surface)
627    {
628       //timer.started = true;
629       if(!style.editText)
630       {
631          if(active && !pulledWindow/*listBox.visible*/)
632          {
633             if(style.activeColor)
634             {
635                surface.SetBackground(selectionColor ? selectionColor : SELECTION_COLOR);
636                if(!style.noHighlight || !currentRow)
637                {
638                   surface.Area(0,0, clientSize.w-1,clientSize.h-1);
639                }
640             }
641          }
642          if(!isEnabled)
643             surface.SetForeground(Color { 85,85,85 } );
644          else
645             surface.SetForeground((active && style.activeColor && !pulledWindow /*listBox.visible*/) ? selectionText : foreground);
646          surface.TextOpacity(true);
647
648          if(currentRow)
649          {
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];
652             if(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);
656          }
657          else
658             surface.WriteText(2,2, "(none)", 6);
659
660          if(!style.noStipple && (!style.noHighlight || !currentRow))
661          {
662             surface.SetForeground(0xFFFFFF80);
663             if(active && !pulledWindow /*listBox.visible*/)
664             {
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);
670             }
671          }
672       }
673    }
674
675    bool OnResizing(int *width, int *height)
676    {
677       int rowHeight = 0;
678
679       display.FontExtent(fontObject, "W", 1, null, &rowHeight);
680       rowHeight = Max(rowHeight, 16);
681
682       if(!*width) *width = Max(*width, rowHeight * 100 / 16);
683
684       //if(!*width) *width = Max(*width, 100);
685       //if(!*height) *height = Max(*height, 20);
686       if(!*height) *height = Max(*height, rowHeight * 20 / 16);
687
688       return true;
689    }
690
691    /*
692    watch(font)
693    {
694       SetInitSize(initSize);
695    };
696    */
697
698    bool OnLeftButtonDown(int x, int y, Modifiers mods)
699    {
700       Update(null);
701       if(pulledWindow)
702       {
703          OnCloseDropDown(pulledWindow);
704          button.checked = false;
705          pulledWindow = null;
706
707          if(!NotifyClose(master, this))
708             return false;
709       }
710       else
711       {
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;
719       }
720       return true;
721    }
722
723    bool OnKeyHit(Key key, unichar ch)
724    {
725       DataRow currentRow = this.currentRow;
726
727       if(!pulledWindow /*listBox.visible*/)
728       {
729          int c;
730          if(style.showNone && !currentRow) currentRow = noneRow;
731
732          switch(key)
733          {
734             case wheelDown:
735             case down: currentRow = currentRow ? currentRow.next : null; break;
736             case wheelUp:
737             case up:   currentRow = currentRow ? currentRow.prev : null; break;
738             case pageDown:
739                for(c = 0; c<listBoxMaxShown && currentRow && currentRow.next; c++, currentRow = currentRow.next);
740                break;
741             case pageUp:
742                for(c = 0; c<listBoxMaxShown && currentRow && currentRow.prev; c++, currentRow = currentRow.prev);
743                break;
744             case end:
745                for(; currentRow && currentRow.next; currentRow = currentRow.next);
746                break;
747             case home:
748                for(; currentRow && currentRow.prev; currentRow = currentRow.prev);
749                break;
750             default:
751                if(!editBox || button.active || !editBox.active || editBox.OnKeyHit(key, ch))
752                {
753                   return listBox.OnKeyHit(key, ch);
754                }
755                else
756                   return false;
757          }
758          if(currentRow)
759          {
760             if(currentRow.noneRow) currentRow = null;
761             property::currentRow = currentRow;
762             //return
763                NotifySelect(master, this, currentRow, key.modifiers);
764             //return false;
765          }
766          return false;
767       }
768       else
769       {
770          if(listBox.vertScroll)
771          {
772             if(key == wheelUp)
773                listBox.vertScroll.Action(up, 0, key);
774             else if(key == wheelDown)
775                listBox.vertScroll.Action(down, 0, key);
776          }
777          return listBox.OnKeyHit(key, ch);
778       }
779       return true;
780    }
781
782    bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
783    {
784       // WAS !active JUST MISSING HERE ?
785       if(!active && style.editText)
786       {
787          if(editBox.modifiedDocument)
788          {
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;
793          }
794          //editBox.Deactivate();
795       }
796       Update(null);
797       return true;
798    }
799
800    public Button button
801    {
802       this, toggle = true, bevel = true, inactive = true,
803       anchor = Anchor { right = 0, top = 0, bottom = 0 },
804       size = Size { BTN_WIDTH, 0 },
805       symbol = 25;
806       bitmap = { "<:ecere>elements/arrowDown.png" };
807
808       bool NotifyPushed(Button control, int x, int y, Modifiers mods)
809       {
810          if(pulledWindow)
811          {
812             OnCloseDropDown(pulledWindow);
813             pulledWindow = null;
814             button.checked = false;
815             NotifyClose(master, this);
816          }
817          else
818          {
819             incref this;
820             if(editBox && editBox.modifiedDocument)
821             {
822                NotifyTextEntry(master, this, editBox.contents, true);
823                editBox.modifiedDocument = false;
824             }
825             pulledWindow = OnDropDown();
826             if(pulledWindow)
827             {
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;
833             }
834             delete this;
835          }
836          Update(null);
837          return true;
838       }
839    };
840
841    ListBox listBox
842    {
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;
846
847       bool NotifyActivate(Window control, bool active, Window swap)
848       {
849          if(!active)
850          {
851             Update(null);
852             if(swap != button && swap != this)
853             {
854                if(editBox && editBox.modifiedDocument)
855                {
856                   NotifyTextEntry(master, this, editBox.contents, true);
857                   editBox.modifiedDocument = false;
858                }
859
860                OnCloseDropDown(pulledWindow);
861                pulledWindow = null;
862                button.checked = false;
863                NotifyClose(master, this);
864             }
865          }
866          return true;
867       }
868
869       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
870       {
871          Update(null);
872
873          // Add code to set text to list box contents if it has an editbox
874
875          if(pulledWindow)
876          {
877             OnCloseDropDown(pulledWindow);
878             pulledWindow = null;
879             button.checked = false;
880             mods.closingDropDown = true;
881             if(!NotifyClose(master, this))
882                return false;
883          }
884          currentRow = (row && !row.noneRow) ? row : null;
885          if(style.editText && style.changeContents)
886          {
887             char tempString[4096];
888             if(currentRow)
889             {
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);
892             }
893             else
894                editBox.contents = "";
895             if(active)
896                editBox.SelectAll();
897          }
898          button.Deactivate();
899          return NotifySelect(master, this, currentRow, mods);
900       }
901
902       bool NotifyHighlight(ListBox control, DataRow row, Modifiers mods)
903       {
904          return NotifyHighlight(master, this, row, mods);
905       }
906
907       bool NotifyKeyDown(ListBox listBox, DataRow selection, Key key, unichar ch)
908       {
909          return OnKeyDown(key, ch);
910          //return true;
911       }
912    };
913
914    bool OnPostCreate()
915    {
916       if(font)
917          listBox.font = { font.faceName, font.size };
918       return true;
919    }
920
921    DropBoxBits style;
922    Window pulledWindow;
923    DataRow currentRow;
924    int listBoxMaxShown;
925    Class dataType;
926    DataField field;
927    EditBox editBox;
928    Alignment alignment;
929    DataRow noneRow;
930    ColorAlpha selectionColor, selectionText;
931
932    selectionColor = SELECTION_COLOR;
933    selectionText = SELECTION_TEXT;
934 };