fd46e7190b900f39b882bfbbd6d1f00912044019
[sdk] / eda / libeda / src / gui.ec
1 import "idList"
2
3 define sgs = 3; // screen sgs size
4 define shadowS = 4;
5
6 default:
7 extern int __ecereVMethodID_class_OnFree;
8 extern int __ecereVMethodID_class_OnGetString;
9 private:
10
11 char * defaultNameField = "Name";
12 char * defaultIdField = "Id";
13 char * defaultActiveField = "Active";
14
15 public void SetDefaultIdField(char * value) { defaultIdField = value; }
16 public void SetDefaultNameField(char * value) { defaultNameField = value; }
17
18 public class ButtonStyle : Button
19 {
20    font = { $"Arial", 10, bold = true };
21    creationActivation = doNothing;
22 }
23
24 public class Group : Window
25 {
26    size = { 84, 31 };
27    tabCycle = true;
28    //inactive = true; // TOFIX causes problems...
29
30    public Label title { this, font = { $"Arial", 10, bold = true }, position = { 16, 2 } };
31
32    bool OnCreate()
33    {
34       title.labeledWindow = this;
35       return true;
36    }
37
38    void OnRedraw(Surface surface)
39    {
40       int x = clientSize.w - 1, y = clientSize.h - 1;
41
42       surface.SetBackground(gray);
43
44       surface.Rectangle(0, 10, x - shadowS, y - shadowS);
45       surface.Area(shadowS / 2, y - shadowS + 1, x, y);
46       surface.Area(x - shadowS + 1, 10 + shadowS / 2, x, y);
47
48       surface.SetBackground(white);
49
50       surface.Rectangle(10, 0, title.size.w + 22, title.size.h + 4);
51       surface.Area(11, 1, title.size.w + 21, title.size.h + 3);
52    }
53 }
54
55 public class CheckBool : bool
56 {
57    Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
58    {
59       if(this || !this) {     // FIXME
60       Button button = dataBox.keepEditor ? (Button)obsolete : null;
61       if(!button)
62       {
63          button = Button
64          {
65             dataBox, borderStyle = 0, text = dataBox.text, anchor = { 0, 0, 0, 0 },
66             // size = { 100, 22 };
67             modifyVirtualArea = false, isCheckbox = true;            
68
69             bool DataBox::NotifyClicked(Button control, int x, int y, Modifiers mods)
70             {
71                bool checked = control.checked;
72                SetData(&checked, false);
73                return true;
74             }
75          };
76       }
77       button.checked = this;
78       button.Create();
79       return button;
80       }
81       return null;
82    }
83 }
84
85 String GetNameString(Row r, Field nameField)
86 {
87    String s = null;
88    if(nameField.type != class(String) && nameField.type != class(char *))
89    {
90       char tempString[4096];
91       Class type = nameField.type;
92       int64 data = 0;
93       if(type.type == structClass)
94          data = (int64)new0 byte[type.structSize];
95       ((bool (*)())(void *)r.GetData)(r, nameField, type, (type.type == structClass) ? (void *)data : &data);
96       s = CopyString((String)type._vTbl[__ecereVMethodID_class_OnGetString](type, (void *)data, tempString, null, null));
97       type._vTbl[__ecereVMethodID_class_OnFree](type, data);
98       if(type.type == structClass)
99       {
100          void * _data = (void *)data;
101          delete _data;
102       }
103    }
104    else
105       r.GetData(nameField, s);
106    return s;
107 }
108
109 public class TableDropBox : DropBox
110 {
111    anchor = { left = 130, top = 180, right = shadowS + sgs * 2 };
112    borderStyle = deep;
113
114    public uint filter;
115    public bool filtered;
116    public Field nameField;
117    public uint exclusion;
118    public Table table;
119    public Field filterField;
120
121    public property uint filter
122    {
123       set
124       {
125          filter = value;
126          filtered = true;
127       }
128       get { return filter; }
129    }
130    public property Field nameField { set { nameField = value; } }
131    public property uint exclusion { set { exclusion = value; } }
132    public property Table table { set { table = value; if(!nameField && value) nameField = value.FindField(defaultNameField); } }
133
134    public virtual void Refill()
135    {
136       Clear();
137       if(table)
138       {
139          Field fldId = table.FindField(defaultIdField);
140          if(fldId && nameField)
141          {
142             Row r { table };
143             if(filterField && filtered)
144             {
145                if(eClass_IsDerived(filterField.type, class(Id)))
146                {
147                   FieldIndex indexedFields[1];
148                   // Table tbl = table.db.OpenTable(table.name, { tableRows });
149                   char * name = table.name;
150                   Database db = table.db;
151                   Table tbl = db.OpenTable(name, { tableRows });
152                   if(tbl)
153                   {
154                      delete r;
155
156                      indexedFields[0] = { filterField };
157                      tbl.GenerateIndex(1, indexedFields, false);
158
159                      r = Row { tbl };
160                      
161                      for(r.Find(filterField, middle, nil, filter); !r.nil; r.Next()) //while(r.Next())
162                      {
163                         Id id;
164                         Id idFilter;
165                         r.GetData(filterField, idFilter);
166                         r.GetData(fldId, id);
167                         if(idFilter != filter)
168                            break;
169                         if(!exclusion || id != exclusion)
170                         {
171                            String s = GetNameString(r, nameField);
172                            AddString(s).tag = id;
173                            delete s;
174                         }
175                      }
176                   }
177                }
178                else if(eClass_IsDerived(filterField.type, class(IdList)))
179                {
180                   while(r.Next())
181                   {
182                      Id id;
183                      IdList idList;
184                      r.GetData(filterField, idList);
185                      r.GetData(fldId, id);
186                      if(idList && idList.Includes(filter) && (!exclusion || !idList.Includes(exclusion)))
187                      {
188                         String s = GetNameString(r, nameField);
189                         AddString(s).tag = id;
190                         delete s;
191                      }
192                      delete idList;
193                   }
194                }
195             }
196             else if(exclusion)
197             {
198                while(r.Next())
199                {
200                   Id id;
201                   r.GetData(fldId, id);
202                   if(id != exclusion)
203                   {
204                      String s = GetNameString(r, nameField);
205                      AddString(s).tag = id;
206                      delete s;
207                   }
208                }
209             }
210             else
211             {
212                while(r.Next())
213                {
214                   Id id;
215                   String s = GetNameString(r, nameField);
216                   r.GetData(fldId, id);
217                   AddString(s).tag = id;
218                   delete s;
219                }
220             }
221             delete r;
222          }
223       }
224       Sort(null, 1);
225    }
226
227    public property Field filterField { set { filterField = value; } }
228
229    bool OnKeyHit(Key key, unichar ch)
230    {
231       if((SmartKey)key == del)
232       {
233          SelectRow(null); //currentRow = null;
234          return false;
235       }
236       else if((SmartKey)key == enter)
237          parent.CycleChildren(true, false, false, true);
238       
239       return DropBox::OnKeyHit(key, ch);
240    }
241
242    bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
243    {
244       modifiedDocument = true;
245       return true;
246    }
247
248    bool OnCreate()
249    {
250       Refill();
251       return true;
252    }
253
254    public void EditNotifyCharsAdded()
255    {
256       if(!editBox.NotifyUpdate || editBox.NotifyUpdate == EditBox::NotifyUpdate)
257          editBox.NotifyUpdate = EditNotifyUpdate;
258    }
259
260    public void EditNotifyUpdate(EditBox editBox)
261    {
262       DataRow row;
263       char * contents = editBox.contents;
264       int len = strlen(contents);
265       if(len && editBox.charPos == len)
266       {
267          EditLine line = editBox.firstLine;
268          int x1, x2;
269
270          editBox.GetSelPos(null, null, &x1, null, null, &x2, false);
271          if(x2 == x1)
272          {
273             for(row = firstRow; row; row = row.next)
274             {
275                char * string = row.string;
276                if(string && SearchString(string, 0, contents, false, false) == string)
277                {
278                   // SelectRow(row);
279                   editBox.contents = row.string;
280                   editBox.SetSelPos(line, 0, len, line, 0, strlen(string));
281                   break;
282                }
283             }
284          }
285       }
286       editBox.NotifyUpdate = null;
287    }
288 }
289
290 public class DropDataBox : DataBox
291 {
292    size.h = 24;
293    keepEditor = true;
294    borderStyle = deep;
295
296    Field nameField;
297    Field filterField;
298    uint exclusion;
299    uint filter;
300    bool filtered;
301    bool showNone;
302    showNone = false; //true;
303
304    public property uint filter { set { filtered = true; filter = value; } get { return filter; } }
305    public property bool filtered { set { filtered = value; } }
306    public property uint exclusion { set { exclusion = value; } }
307    public property Field filterField { set { filterField = value; } }
308    public property Field nameField { set { nameField = value; } }
309    public virtual void TableDropBox::RefillFunction();
310    public property bool showNone { set { showNone = value; } }
311
312    public void Refill()
313    {
314       if(editor)
315       {
316          TableDropBox dropBox = (TableDropBox) editor;
317          uint id = data ? *(uint *)data : MAXDWORD;
318          void * notifyChanged = (void *)NotifyChanged;
319
320          OnConfigure(dropBox);
321
322          NotifyChanged = null;
323          dropBox.Refill();
324          NotifyChanged = notifyChanged;
325
326          if(id != MAXDWORD) dropBox.SelectRow(dropBox.FindSubRow(id));
327       }
328    }
329
330    void OnConfigure(TableDropBox dropBox)
331    {
332       if(RefillFunction != DropDataBox::RefillFunction) dropBox.Refill = RefillFunction;
333       if(nameField) dropBox.nameField = nameField;
334       if(filterField) dropBox.filterField = filterField;
335       if(filtered)
336          dropBox.filter = filter;
337       else
338          dropBox.filtered = false;
339       
340       dropBox.exclusion = exclusion;
341       dropBox.showNone = showNone;
342    }
343 }
344
345 public class EditDropDataBox : DropDataBox
346 {
347    void OnConfigure(TableDropBox dropBox)
348    {
349       DropDataBox::OnConfigure(dropBox);
350       dropBox.editText = true;
351       dropBox.editBox.NotifyCharsAdded = (void *)TableDropBox::EditNotifyCharsAdded;
352    }
353 }
354
355 public class FieldDataBox : DataBox
356 {
357    size = { 100, 22 };
358    anchor = { left = 110, right = shadowS + sgs * 2 };
359    borderStyle = deep;
360
361    Field field;
362    int64 dataHolder; // THERE SEEMS TO BE A BUG WHEN ACCESSING row ACROSS .so
363    Row row;
364
365    public property Row row
366    {
367       set { row = value; }
368       get { return row; }
369    }
370    public property EditSection editor
371    {
372       set
373       {
374          parent = value.editArea;
375          master = value;
376          value.AddFieldEditor(this);
377          row = value.editRow;
378       }
379    };
380
381    public property Field field
382    {
383       set
384       {
385          Class dataType;
386          if(field) type = null;
387
388          if(dataHolder)
389          {
390             type._vTbl[__ecereVMethodID_class_OnFree](type, dataHolder);
391             if(type.type == structClass)
392             {
393                void * dataPtr = (void *)dataHolder;
394                delete dataPtr;
395             }
396             dataHolder = 0;
397          }
398
399          field = value;
400          dataType = value ? value.type : null;
401          if(!text)
402             text = field ? field.name : null;
403
404          if(dataType && dataType.type == structClass)
405          {
406             dataHolder = (int64)new0 byte[dataType.structSize];
407             data = (void *)dataHolder;
408          }
409          else if(dataType && (dataType.type == noHeadClass || dataType.type == normalClass))
410          {
411             if(eClass_IsDerived(dataType, class(String)))
412                dataHolder = (int64)CopyString("");
413             else
414                dataHolder = (int64)eInstance_New(dataType);
415             data = (void *)&dataHolder;
416          }
417          else
418          {
419             dataHolder = 0;
420             data = &dataHolder;
421          }
422          if(!type) type = dataType;
423       }
424    }
425
426    public void Clear()
427    {
428       if(visible)
429       {
430          if(data)
431             SetData(null, false);
432
433          if(type && (type.type == noHeadClass || type.type == normalClass))
434          {
435             if(eClass_IsDerived(type, class(String)))
436                dataHolder = (int64)CopyString("");
437             else
438                dataHolder = (int64)eInstance_New(type);
439             data = (void *)&dataHolder;
440          }
441
442          if(created)
443             Refresh();
444       }
445    }
446
447    public void Load()
448    {
449       if(visible && field && row)
450       {
451          SetData(null, false);
452          master.modifiedDocument = false;
453
454          ((bool (*)())(void *)Row::GetData)(row, field, field.type, data);
455
456          if(!dataHolder && type && (type.type == noHeadClass || type.type == normalClass))
457          {
458             if(eClass_IsDerived(type, class(String)))
459                dataHolder = (int64)CopyString("");
460             else
461                dataHolder = (int64)eInstance_New(type);
462             data = (void *)&dataHolder;
463          }
464
465          // if(created)
466          Refresh();
467       }
468    }
469
470    public virtual void Save()
471    {
472       bool result;
473       if(visible && field && row)
474       {
475          Class type = field.type;
476          if(!DataBox::SaveData())
477             Refresh();
478
479          ((bool (*)())(void *)Row::SetData)(row, field, type, 
480             (type.type == noHeadClass || type.type == normalClass) ? *(void **)data : data);
481       }
482    }
483
484    public void Init()
485    {
486       if(visible && created)
487          Refresh();
488    }
489
490    bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
491    {
492       if(!active)
493       {
494          if(modifiedDocument && !DataBox::SaveData())
495             Refresh();
496       }
497       return true;
498    }
499
500    bool OnKeyDown(Key key, unichar ch)
501    {
502       if((SmartKey)key == enter)
503       {
504          DataBox::OnKeyDown(key, ch);
505          return true;
506       }
507       else
508          return DataBox::OnKeyDown(key, ch);
509    }
510
511    bool OnKeyHit(Key key, unichar ch)
512    {
513       if((SmartKey)key == enter)
514          parent.CycleChildren(true, false, false, true);
515       
516       return DataBox::OnKeyHit(key, ch);
517    }
518
519    public bool Window::NotifyChanged(bool closingDropDown)
520    {
521       modifiedDocument = true;
522       return true;
523    }
524
525    public bool Window::NotifyModified()
526    {
527       modifiedDocument = true;
528       return true;
529    }
530
531    ~FieldDataBox()
532    {
533       if(data)
534          SetData(null, false);
535
536       if(dataHolder)
537       {
538          type._vTbl[__ecereVMethodID_class_OnFree](type, dataHolder);
539          if(type.type == structClass)
540          {
541             void * dataPtr = (void *)dataHolder;
542             delete dataPtr;
543          }
544          dataHolder = 0;
545       }
546    }
547 }
548
549 public class FieldCheckButton : FieldDataBox
550 {
551    borderStyle = 0;
552    type = class(CheckBool);
553    // TOCHECK: When not here, the virtual area goes wild (anchor.right is not reset)
554    position = { 0, 0 };
555 }
556
557 public class FieldDropDataBox : FieldDataBox
558 {
559    size.h = 24;
560    keepEditor = true;
561
562    Field nameField;
563    Field filterField;
564    uint exclusion;
565    uint filter;
566    bool filtered;
567    bool showNone;
568    showNone = true;
569
570    public property uint filter { set { filtered = true; filter = value; } get { return filter; } }
571    public property bool filtered { set { filtered = value; } }
572    public property uint exclusion { set { exclusion = value; } }
573    public property Field filterField { set { filterField = value; } }
574    public property Field nameField { set { nameField = value; } }
575    public virtual void TableDropBox::RefillFunction();
576    public property bool showNone { set { showNone = value; } }
577
578    public void Refill()
579    {
580       if(editor)
581       {
582          TableDropBox dropBox = (TableDropBox) editor;
583          uint id = data ? *(uint *)data : MAXDWORD;
584          OnConfigure(dropBox);
585          dropBox.Refill();
586          if(id != MAXDWORD) dropBox.SelectRow(dropBox.FindSubRow(id));
587       }
588    }
589
590    void OnConfigure(TableDropBox dropBox)
591    {
592       if(RefillFunction != FieldDropDataBox::RefillFunction) dropBox.Refill = RefillFunction;
593       if(nameField) dropBox.nameField = nameField;
594       if(filterField) dropBox.filterField = filterField;
595       if(filtered)
596          dropBox.filter = filter;
597       else
598          dropBox.filtered = false;
599       dropBox.exclusion = exclusion;
600       dropBox.showNone = showNone;
601    }
602 }
603
604 public class EditFieldDropDataBox : FieldDropDataBox
605 {
606    // showNone = false;
607
608    void OnConfigure(TableDropBox dropBox)
609    {
610       FieldDropDataBox::OnConfigure(dropBox);
611       dropBox.editText = true;
612       dropBox.editBox.NotifyCharsAdded = (void *)TableDropBox::EditNotifyCharsAdded;
613    }
614
615    void Save()
616    {
617       TableDropBox dropBox = (TableDropBox) editor;
618       
619       if(!dropBox.currentRow && dropBox.contents[0])
620       {
621          Row row { dropBox.table };
622          Id sysID;
623          OnAddTextEntry(row, dropBox, dropBox.contents);
624          sysID = row.sysID;
625          delete row;
626
627          dropBox.Refill();
628          dropBox.SelectRow(dropBox.FindSubRow(sysID));
629       }
630       FieldDataBox::Save();
631    }
632
633    public virtual bool OnAddTextEntry(Row row, TableDropBox dropBox, char * entry)
634    {
635       row.Add();
636       row.SetData(dropBox.nameField, entry);
637       return true;
638    }
639 }
640
641 public class ListSection : Group
642 {
643    text = $"List";
644    size = { 710, 287 };
645    anchor = { left = sgs, top = 32 + sgs * 3, bottom = 55 + sgs * 3 };
646
647    EditSection editor;
648
649    public property EditSection editor
650    {
651       set
652       {
653          editor = value;
654          value.list = this;
655       }
656    }
657
658    public property Table table
659    {
660       set
661       {
662          if(value)
663          {
664             table = value;
665             if(table)
666             {
667                FieldIndex indexedFields[1];
668                
669                if(!fldId) fldId = table.FindField(defaultIdField);
670                if(!fldName) fldName = table.FindField(defaultNameField);
671                if(!fldActive) fldActive = table.FindField(defaultActiveField);
672                
673                indexedFields[0] = { fldId };
674                table.Index(1, indexedFields);
675                
676                editor.editRow.tbl = table;
677                
678                RefillList();
679             }
680          }
681       }
682    }
683    Table table;
684    public Field fldId, fldName, fldActive;
685
686    public virtual DialogResult Window::NotifySaveConfirmation(ListSection listSection)
687    {
688       return MessageBox { master = this, type = yesNoCancel, text = $"List Editor", contents = $"You have modified this entry. Would you like to save it before proceeding?" }.Modal();
689    }
690    
691    bool OnClose(bool parentClosing)
692    {
693       if(editor && editor.modifiedDocument)
694       {
695          switch(NotifySaveConfirmation(master, this))
696          {
697             case cancel:
698                return false;
699             case yes:
700                editor.EditSave();
701             case no:
702                editor.modifiedDocument = false;
703                break;
704          }
705       }
706       return true;
707    }
708
709    public void RefillList()
710    {
711       list.Clear();
712       //if(fldId && fldName)
713       {
714          Row r { table };
715          NotifyRefillList(master, this, r);
716          delete r;
717       }
718       list.Sort(null, 1);
719       editor.modifiedDocument = false;
720    }
721
722    public virtual void Window::NotifyRefillList(ListSection listSection, Row r)
723    {
724       if(listSection.fldId && listSection.fldName)
725       {
726          bool stringName = !strcmp(listSection.fldName.type.dataTypeString, "char *");
727          while(r.Next())
728          {
729             Id id = 0;
730             String s = null;
731             r.GetData(listSection.fldId, id);
732             if(stringName)
733                r.GetData(listSection.fldName, s);
734             else
735                s = PrintString("Entry ", id);
736             listSection.list.AddString(s).tag = id;
737             delete s;
738          }
739       }
740    }
741
742    public virtual bool Window::NotifyNew(ListSection listSection, Row r);
743
744    public ButtonStyle btnNew
745    {
746       this, anchor = { right = shadowS + sgs * 2, top = 24 }, hotKey = altW, text = $"New";
747
748       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
749       {
750          list.NotifySelect(this, list, null, 0);
751          if(!editor.modifiedDocument)
752          {
753             uint id; // = table.rowsCount + 1; // this is bad with deleted rows, won't work, how to have unique id? 
754             Row r { table };
755          
756             if(r.Last())   // this will reuse ids in cases where the item(s) with the last id have been deleted
757             {
758                r.GetData(fldId, id);
759                id++;
760             }
761             else
762                id = 1;
763          
764             editor.EditClear();
765             {
766                bool active = true;
767                r.Add();
768                {
769                   // Patch for SQLite driver which auto-increments IDs
770                   int curID = 0;
771                   if(r.GetData(fldId, curID))
772                      id = curID;
773                   else
774                      r.SetData(fldId, id);
775                }
776                if(!strcmp(fldName.type.dataTypeString, "char *"))
777                   r.SetData(fldName, $"[New]");
778
779                if(fldActive)
780                   r.SetData(fldActive, active);
781
782                if(NotifyNew(master, this, r))
783                   list.currentRow = list.AddString($"[New]");
784                delete r;
785             }
786
787             list.Sort(null, 1);
788             list.currentRow.tag = id;
789             SelectListRow(list.currentRow);
790             RefreshState();
791          }
792          return true;
793       }
794    };
795
796    public virtual bool Window::NotifyDeleteConfirmation(ListSection listSection)
797    {
798       return MessageBox {  master = this, type = yesNo, text = $"List Editor", 
799                            contents =  $"You are about to delete an entry.\n"
800                                         "Do you wish to continue?"
801                   }.Modal() == yes;
802    }
803
804    public virtual void Window::NotifyDeleting(ListSection listSection);
805    public virtual void Window::NotifyDeleted(ListSection listSection);
806
807    public ButtonStyle btnDelete
808    {
809       this, anchor = { right = shadowS + sgs * 2, top = 24 }, hotKey = altD, text = $"Delete";
810
811       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
812       {
813          if(list.currentRow)
814          {
815             if(NotifyDeleteConfirmation(master, this))
816             {
817                NotifyDeleting(master, this);
818
819                editor.editRow.Delete();
820                list.DeleteRow(list.currentRow);
821                editor.EditClear();
822
823                NotifyDeleted(master, this);
824
825                SelectListRow(list.currentRow);
826                RefreshState();
827             }
828          }
829          return true;
830       }
831    };
832
833    public bool FilterNotifyChanged(bool closeDropDown)
834    {
835       editor.EditClear();
836       RefillList();
837       if(list.firstRow)
838          SelectListRow(list.firstRow);
839       RefreshState();
840       return true;
841    }
842
843    DataRow lastRow;
844    public ListBox list
845    {
846       this, anchor = { left = sgs * 2, top = 22 + 22 + sgs * 4, right = shadowS + sgs * 2, bottom = shadowS + sgs * 2 };
847       alwaysHighLight = true;
848       
849       bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
850       {
851          bool result = true;
852          if(/*row && */row != lastRow)
853          {
854             uint id;
855             if(editor.modifiedDocument)
856             {
857                if(row)
858                   list.currentRow = lastRow;
859                result = false;
860                switch(NotifySaveConfirmation(master, this))
861                {
862                   case cancel:
863                      return false;
864                   case yes:
865                      editor.EditSave();
866                   case no:
867                      editor.modifiedDocument = false;
868                      list.currentRow = row;
869                      break;
870                }
871             }
872             SelectListRow(row);
873          }
874          return result;
875       }
876    };
877
878    public virtual void Window::NotifySelectListRow(ListSection listSection, uint id);
879    
880    public void SelectListRow(DataRow row)
881    {
882       // Time startTime = GetTime();
883       if(row)
884       {
885          uint id = row.tag;
886          lastRow = row;
887
888          if(list.currentRow != row)
889             list.currentRow = row;
890          if(editor.editRow.Find(fldId, middle, nil, id))
891          {
892             editor.listRow = row;
893             NotifySelectListRow(master, this, id);
894             editor.EditLoad();
895          }
896       }
897       // Logf("SelectListRow took %f seconds\n", GetTime() - startTime);
898    }
899
900    public void SelectFirst()
901    {
902       if(list.firstRow)
903          SelectListRow(list.firstRow);
904       RefreshState();
905    }
906
907    public void RefreshState()
908    {
909       if(editor)
910       {
911          editor.btnSave.disabled = !(bool)list.currentRow;
912          editor.btnReload.disabled = !(bool)list.currentRow;
913          btnDelete.disabled = !(bool)list.currentRow;
914          editor.disabled = !(bool)list.firstRow;
915       }
916    }
917    
918    void OnResize(int width, int height)
919    {
920       int x = width - btnDelete.size.w - 20;
921
922       btnDelete.position.x = x;
923       if(btnNew.visible)
924          btnNew.position.x = x = x - btnNew.size.w - sgs * 2;
925    }
926
927    bool OnPostCreate(void)
928    {
929       OnResize(clientSize.w, clientSize.h);
930       SelectFirst();
931       if(editor) editor.modifiedDocument = false;
932       return Window::OnPostCreate();
933    }
934
935 }
936
937 public class EditSection : Group
938 {
939    tabCycle = true;
940    text = $"Entry";
941    size = { 710, 55 };
942    anchor = { right = sgs, top = 32 + sgs * 3, bottom = 55 + sgs * 3 };
943
944    ~EditSection()
945    {
946       editBoxes.Free(null);
947    }
948
949 public:
950    ListSection list;
951
952    property Table table
953    {
954       set
955       {
956          if(value)
957          {
958             table = value;
959             InitFields();
960          }
961       }
962    }
963    Table table;
964
965    Row editRow { };
966    DataRow listRow;
967    OldList editBoxes { };
968
969    public Window editArea { this, borderStyle = deep, tabCycle = true, anchor = { left = 8, top = 54, right = 10, bottom = 10 }, hasVertScroll = true, dontHideScroll = true };
970    
971    public ButtonStyle btnSave
972    {
973       this, anchor = { right = shadowS + sgs * 2, top = 24 }, hotKey = altV, text = $"Save";
974
975       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
976       {
977          EditSave();
978          return true;
979       }
980    };
981
982    public ButtonStyle btnReload
983    {
984       this, anchor = { left = 10, top = 24 }, hotKey = altV, text = $"Revert";
985
986       bool NotifyClicked(Button button, int x, int y, Modifiers mods)
987       {
988          EditLoad();
989          return true;
990       }
991    };
992
993
994    void AddFieldEditor(FieldDataBox box)
995    {
996       editBoxes.Add(OldLink { data = box });
997    }
998
999    virtual void Window::NotifyInitFields(EditSection editSection);
1000    
1001    void InitFields()
1002    {
1003       OldLink link;
1004       for(link = editBoxes.first; link; link = link.next)
1005       {
1006          FieldDataBox dataBox = link.data;
1007          dataBox.Init();
1008       }
1009       NotifyInitFields(master, this);
1010    }
1011
1012    void EditNew()
1013    {
1014       modifiedDocument = false;
1015    }
1016
1017    virtual void Window::NotifyEditSave(EditSection edit, String name)
1018    {
1019       edit.listRow.string = name;
1020    }
1021    
1022    void EditSave()
1023    {
1024       bool stringName = !strcmp(list.fldName.type.dataTypeString, "char *");
1025       OldLink link;
1026       String name = null;
1027
1028       editRow.tbl.db.Begin();
1029       for(link = editBoxes.first; link; link = link.next)
1030       {
1031          FieldDataBox dataBox = link.data;
1032          dataBox.Save();
1033       }
1034       editRow.tbl.db.Commit();
1035       // ADDED THIS HERE FOR SQLITE TO REFRESH
1036       editRow.Find(list.fldId, middle, nil, list.list.currentRow.tag);
1037
1038       if(stringName)
1039          editRow.GetData(list.fldName, name);
1040       else
1041          name = PrintString("Entry ", list.list.currentRow.tag);
1042
1043       NotifyEditSave(master, this, name);
1044       delete name;
1045       list.list.Sort(null, 1);
1046       list.list.currentRow = list.list.currentRow;
1047
1048       modifiedDocument = false;
1049    }
1050
1051    virtual void Window::NotifyEditLoad(EditSection editSection);
1052
1053    void EditLoad()
1054    {
1055       OldLink link;
1056       for(link = editBoxes.first; link; link = link.next)
1057       {
1058          FieldDataBox dataBox = link.data;
1059          dataBox.Load();
1060       }
1061       NotifyEditLoad(master, this);
1062
1063       modifiedDocument = false;
1064    }
1065
1066    virtual void Window::NotifyEditClear(EditSection editSection);
1067
1068    void EditClear()
1069    {
1070       OldLink link;
1071       for(link = editBoxes.first; link; link = link.next)
1072       {
1073          FieldDataBox dataBox = link.data;
1074          editRow.Select(nil);
1075          dataBox.Clear();
1076       }
1077       NotifyEditClear(master, this);
1078       modifiedDocument = false;
1079    }
1080
1081    bool OnPostCreate()
1082    {
1083       // TO CHECK: Why is there a jump in the scroll thumb size when this is not here?
1084       anchor = anchor;
1085
1086       modifiedDocument = false;
1087       return true;
1088    }
1089 }