ecere:gui:controls:DropBox; added rowCount property to be used instead of calling...
[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)
28    {
29       listBox.foreground = foreground;
30    };
31    watch(background)
32    {
33       listBox.background = background;
34    };
35
36 public:
37    property bool activeStipple
38    {
39       property_category $"Appearance" 
40       set
41       {
42          style.noStipple = !value;
43          Update(null);
44       }
45       get { return !style.noStipple; }
46    };
47    property bool showButton
48    {
49       property_category $"Appearance" 
50       set
51       {
52          button.visible = value;
53          listBox.borderStyle = value ? contour : none;
54       }
55       get { return button.visible; }
56    };
57    property Alignment alignment
58    {
59       property_category $"Appearance" 
60       set
61       {
62          alignment = value;
63          if(field)
64             field.alignment = value;
65       }
66       get { return alignment; }
67    };
68    property bool noHighlight
69    {
70       property_category $"Appearance" 
71       set
72       {
73          if(this)
74          {
75             style.noHighlight = value;
76             listBox.fullRowSelect = !value;
77             Update(null);
78          }
79       }
80       get { return style.noHighlight; }
81    };
82    property bool activeColor
83    {
84       property_category $"Appearance" 
85       set
86       {
87          if(this)
88          {
89             style.activeColor = value;
90             Update(null);
91          }
92       }
93       get { return style.activeColor; }
94    };
95    property DataRow currentRow
96    {
97       property_category $"Private" 
98       set
99       {
100          if(this)
101          {
102             currentRow = value;
103             listBox.currentRow = value ? value : (style.showNone ? noneRow : null);
104             if(style.editText && style.changeContents)
105             {
106                char tempString[4096];
107                if(currentRow)
108                   editBox.contents = ((char *(*)(void *, void *, char *, void *, bool *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, currentRow.GetData(null), tempString, null, null);
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 char * contents { property_category $"Data" set { if(editBox) editBox.contents = value; } get { return editBox ? editBox.contents : null; } };
128    property bool editText
129    {
130       property_category $"Behavior" 
131       set
132       {
133          if(this)
134          {
135             if(value)
136             {
137                if(!editBox)
138                {
139                   editBox = EditBox
140                   {
141                      this, textHorzScroll = true, borderStyle = 0;
142                      anchor = Anchor { left = 0, top = 0, right = BTN_WIDTH, bottom = 0 };
143                      // visible = false, modifyVirtualArea = false;
144                   };
145                   incref editBox;
146                   editBox.Create();
147                   button.inactive = false;
148                }      
149                style.editText = true;
150                tabCycle = false;
151             }
152             else
153             {
154                if(editBox)
155                {
156                   editBox.Destroy(0);
157                   delete editBox;
158                   button.inactive = true;
159                }
160                style.editText = false;
161             }
162          }
163       }
164       get { return style.editText; }
165    };
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
170    {
171       property_category $"Behavior" 
172       set
173       {
174          listBoxMaxShown = value;
175          OnPosition(position.x, position.y, clientSize.w, clientSize.h);
176       }
177       get { return listBoxMaxShown; }
178    };
179    property Window pullDown
180    {
181       get { return pulledWindow; }
182    }
183    property bool showNone
184    {
185       set
186       {
187          if(value != style.showNone)
188          {
189             if(style.showNone)
190             {
191                listBox.DeleteRow(noneRow);
192                noneRow = null;
193             }
194             style.showNone = value;
195             if(value)
196             {
197                noneRow = listBox.AddRowNone();
198             }
199          }
200       }
201       get { return style.showNone; }
202    }
203    property Color selectionColor { set { selectionColor = value; } get { return selectionColor; } isset { return selectionColor ? true : false; } };
204    property bool changeContents
205    {
206       set { style.changeContents = value; }
207       get { return style.changeContents; }
208    }
209
210    property ListBox listBox { get { return listBox; } }
211
212    property int rowCount { get { return listBox.rowCount; } }
213
214    // Notifications
215    virtual bool Window::NotifySelect(DropBox dropBox, DataRow row, Modifiers mods);
216    virtual bool Window::NotifyClose(DropBox dropBox);
217    virtual bool Window::NotifyHighlight(DropBox dropBox, DataRow row, Modifiers mods);
218    virtual bool Window::NotifyTextEntry(DropBox dropBox, char * string, bool confirmed);
219
220    virtual Window OnDropDown()
221    {
222       // NASTY BUG ON WINDOWS IN PROPERTIES SHEET IF WE DON'T RECREATE THE LISTBOX HERE
223       // To reproduce, comment out, select borderStyle property, alt-tab to another program, come back, drop down
224       // The listBox goes annoyingly to 0, 0
225       listBox.Destroy(0);
226       listBox.Create();
227
228       ResizeListbox();
229       // listBox.visible = true;
230       return listBox;   
231    }
232
233    virtual void OnCloseDropDown(Window pullDown)
234    {
235       listBox.visible = false;
236       if(style.editText)
237       {
238          editBox.ActivateEx(true, false, false, false, null, null);
239          editBox.SelectAll();
240       }
241    }
242
243    // Methods
244    DataRow AddStringf(char * format, ...)
245    {
246       if(this)
247       {
248          DataRow row;
249
250          char string[MAX_F_STRING];
251          va_list args;
252
253          va_start(args, format);
254          vsnprintf(string, sizeof(string), format, args);
255          string[sizeof(string)-1] = 0;
256          va_end(args);
257
258          row = AddRow();
259          row.SetData(null, string);
260          return row;
261       }
262       return null;
263    }
264
265    DataRow AddString(char * string)
266    {
267       if(this)
268       {
269          DataRow row;
270          row = AddRow();
271          row.SetData(null, string);
272          return row;
273       }
274       return null;
275    }
276
277    void DeleteRow(DataRow row)
278    {
279       if(!row) row = currentRow;
280       listBox.DeleteRow(row);
281       /*
282       if(row == currentRow)
283          currentRow = null;*/
284       Update(null);
285    }
286
287    // Convenience function using current rows
288    int64 GetTag()
289    {
290       return currentRow.tag;
291    }
292
293    void * SetData(DataField field, any_object data)
294    {
295       if(this)
296       {
297          if(currentRow)
298             return currentRow.SetData(field, data);
299       }
300       return null;
301    }
302
303    any_object GetData(DataField field)
304    {
305       if(this)
306       {
307          // TODO: Fix this shouldn't be required (memguard?)
308          return (void *)currentRow.GetData(field);
309       }
310       return 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 = ((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 = ((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*/) ? SELECTION_TEXT : 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          Update(null);
863
864          // Add code to set text to list box contents if it has an editbox
865
866          if(pulledWindow)
867          {
868             OnCloseDropDown(pulledWindow);
869             pulledWindow = null;
870             button.checked = false;
871             mods.closingDropDown = true;
872             if(!NotifyClose(master, this))
873                return false;
874          }
875          currentRow = (row && !row.noneRow) ? row : null;
876          if(style.editText && style.changeContents)
877          {
878             char tempString[4096];
879             if(currentRow)
880                editBox.contents = ((char *(*)(void *, void *, char *, void *, bool *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, currentRow.GetData(null), tempString, null, null);
881             else
882                editBox.contents = "";
883             if(active)
884                editBox.SelectAll();
885          }                  
886          button.Deactivate();
887          return NotifySelect(master, this, currentRow, mods);
888       }
889
890       bool NotifyHighlight(ListBox control, DataRow row, Modifiers mods)
891       {
892          return NotifyHighlight(master, this, row, mods);
893       }
894
895       bool NotifyKeyDown(ListBox listBox, DataRow selection, Key key, unichar ch)
896       {
897          return OnKeyDown(key, ch);
898          //return true;
899       }
900    };
901
902    bool OnPostCreate()
903    {
904       if(font)
905          listBox.font = { font.faceName, font.size };
906       return true;
907    }
908
909    DropBoxBits style;
910    Window pulledWindow;
911    DataRow currentRow;
912    int listBoxMaxShown;
913    Class dataType;
914    DataField field;
915    EditBox editBox;
916    Alignment alignment;
917    DataRow noneRow;
918    Color selectionColor;
919 };