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