ecere, ide: Replaced integer types by 64 bit ints for tags, ids
[sdk] / ecere / src / gui / Anchor.ec
1 namespace gui;
2
3 import "Window"
4
5 public struct AnchorValue
6 {
7    AnchorValueType type;
8
9    union
10    {
11       int distance;
12       float percent;      
13    };
14    property int
15    {
16       set { distance = value; type = offset; }
17       get { return distance; }
18    }
19    property double
20    {
21       set { percent = (float) value; type = relative; }
22       get { return (double) percent; }
23    }
24
25    char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
26    {
27       if(type == offset)
28       {
29          sprintf(stringOutput, "%d", distance);
30       }
31       else if(type == relative)
32       {
33          int c;
34          int last = 0;
35          sprintf(stringOutput, "%f", percent);
36          c = strlen(stringOutput)-1;
37          for( ; c >= 0; c--)
38          {
39             if(stringOutput[c] != '0') 
40                last = Max(last, c);
41             if(stringOutput[c] == '.')
42             {
43                if(last == c)
44                {
45                   stringOutput[c+1] = '0';
46                   stringOutput[c+2] = 0;
47                }
48                else
49                   stringOutput[last+1] = 0;
50                break;
51             }
52          }
53       }
54       if(needClass) *needClass = false;
55       return stringOutput;
56    }
57
58    bool OnGetDataFromString(char * stringOutput)
59    {
60       char * end;
61       if(strchr(stringOutput, '.'))
62       {
63          float percent = (float)strtod(stringOutput, &end);
64          
65          if(end != stringOutput)
66          {
67             this.percent = percent;
68             type = relative;
69             return true;
70          }
71       }
72       else if(stringOutput[0])
73       {
74          int distance = strtol(stringOutput, &end, 0);
75          if(end != stringOutput)
76          {
77             this.distance = distance;
78             type = offset;
79             return true;
80          }
81       }
82       else
83       {
84          distance = 0;
85          type = 0;
86          return true;
87       }
88       return false;
89    }
90 };
91
92 public struct MiddleAnchorValue
93 {
94    AnchorValueType type;
95
96    union
97    {
98       int distance;
99       float percent;      
100    };
101    property int
102    {
103       set { distance = value; type = none; }
104       get { return distance; }
105    }
106    property double
107    {
108       set { percent = (float) value; type = middleRelative; }
109       get { return (double) percent; }
110    }
111
112    char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
113    {
114       if(type == middleRelative)
115       {
116          int c;
117          int last = 0;
118          sprintf(stringOutput, "%f", percent);
119          c = strlen(stringOutput)-1;
120          for( ; c >= 0; c--)
121          {
122             if(stringOutput[c] != '0') 
123                last = Max(last, c);
124             if(stringOutput[c] == '.')
125             {
126                if(last == c)
127                {
128                   stringOutput[c+1] = '0';
129                   stringOutput[c+2] = 0;
130                }
131                else
132                   stringOutput[last+1] = 0;
133                break;
134             }
135          }
136       }
137       else if(type == none && distance)
138       {
139          sprintf(stringOutput, "%d", distance);
140       }
141       if(needClass) *needClass = false;
142       return stringOutput;
143    }
144
145    bool OnGetDataFromString(char * stringOutput)
146    {
147       if(strchr(stringOutput, '.'))
148       {
149          percent = (float)strtod(stringOutput, null);
150          type = middleRelative;
151       }
152       else
153       {
154          distance = strtol(stringOutput, null, 0);
155          type = none;
156       }
157       return true;
158    }
159 };
160
161 public enum AnchorValueType { none, offset, relative, middleRelative, cascade, vTiled, hTiled };
162
163 public struct Anchor
164 {
165    union { AnchorValue left; MiddleAnchorValue horz; };
166    union { AnchorValue top; MiddleAnchorValue vert; };
167    AnchorValue right, bottom;      
168
169    char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
170    {
171       char tempString[256];
172       char * anchorValue;
173       bool subNeedClass;
174
175       tempString[0] = '\0';
176       anchorValue = left.OnGetString(tempString, null, &subNeedClass);
177       if(anchorValue[0]) { if(stringOutput[0]) strcat(stringOutput, ", "); strcat(stringOutput, "left = "); strcat(stringOutput, anchorValue); }
178       
179       //if(((!left.type && !right.type) && horz.distance) || horz.type == middleRelative)
180       if(!right.type && ((!left.type && horz.distance) || horz.type == middleRelative))
181       {
182          tempString[0] = '\0';
183          anchorValue = horz.OnGetString(tempString, null, &subNeedClass);
184          if(anchorValue[0]) { if(stringOutput[0]) strcat(stringOutput, ", "); strcat(stringOutput, "horz = "); strcat(stringOutput, anchorValue); }
185       }
186       
187       tempString[0] = '\0';
188       anchorValue = top.OnGetString(tempString, null, &subNeedClass);
189       if(anchorValue[0]) { if(stringOutput[0]) strcat(stringOutput, ", "); strcat(stringOutput, "top = "); strcat(stringOutput, anchorValue); }
190       
191       tempString[0] = '\0';
192       anchorValue = right.OnGetString(tempString, null, &subNeedClass);
193       if(anchorValue[0]) { if(stringOutput[0]) strcat(stringOutput, ", "); strcat(stringOutput, "right = "); strcat(stringOutput, anchorValue); }
194
195       // if(((!top.type && !bottom.type) && vert.distance) || vert.type == middleRelative)
196       if(!bottom.type && ((!top.type && vert.distance) || vert.type == middleRelative))
197       {
198          tempString[0] = '\0';
199          anchorValue = vert.OnGetString(tempString, null, &subNeedClass);
200          if(anchorValue[0]) { if(stringOutput[0]) strcat(stringOutput, ", "); strcat(stringOutput, "vert = "); strcat(stringOutput, anchorValue); }
201       }
202       
203       tempString[0] = '\0';
204       anchorValue = bottom.OnGetString(tempString, null, &subNeedClass);
205       if(anchorValue[0]) { if(stringOutput[0]) strcat(stringOutput, ", "); strcat(stringOutput, "bottom = "); strcat(stringOutput, anchorValue); }
206       
207       return stringOutput;
208    }
209
210    bool OnGetDataFromString(char * string)
211    {
212       this = Anchor {};
213       return class::OnGetDataFromString(string);
214    }
215
216    bool OnSaveEdit(DropBox dropBox, void * object)
217    {
218       return dropBox.Save();
219    }
220
221    Window OnEdit(Window listBox, Window master, int x, int y, int w, int h, Window control)
222    {
223       char * string = "";
224       AnchorDropBox comboBox
225       {
226          editText = true;
227          parent = listBox;
228          master = master;
229          position = Point { x, y };
230          //clientSize = Size { h = h };
231          //size.w = w;
232          size = { w, h };
233          anchorValue = this;
234          control = control;
235          borderStyle = 0;
236       };
237       
238       comboBox.Create();
239
240       {
241          char tempString[MAX_F_STRING] = "";
242          bool needClass = false;
243          char * result = OnGetString(tempString, null, &needClass);
244          if(result) string = result;
245       }
246       comboBox.contents = string;
247       return comboBox;
248    }
249 };
250
251 private class AnchorButton : Button
252 {
253    toggle = true, bevel = false;
254
255    void OnRedraw(Surface surface)
256    {
257       int cw = clientSize.w;
258       int ch = clientSize.h;
259
260       surface.SetForeground(black);
261       if(checked)
262       {
263          surface.SetBackground(Color { 85,85,85 });
264          surface.Area(0,0, cw-1, ch-1);
265       }
266       else
267          surface.LineStipple(0xAAAA);
268
269       surface.Rectangle(0,0,cw-1,ch-1);
270
271       if(active)
272       {
273          surface.LineStipple(0xAAAA);
274          surface.Rectangle(2,2,cw-3,ch-3);
275       }
276    }
277
278    bool AnchorEditor::NotifyClicked(Button button, int x, int y, Modifiers mods)
279    {
280       AnchorDropBox anchorDropBox = (AnchorDropBox)master;
281       Anchor anchor = anchorDropBox.anchorValue;
282       Window control = anchorDropBox.control;
283       DataBox dropMaster = (DataBox)anchorDropBox.master;
284       int64 id = button.id;
285
286       switch(id)
287       {
288          case 0: anchor.left.type   = button.checked ? offset : none; break;
289          case 1: anchor.top.type    = button.checked ? offset : none; break;
290          case 2: anchor.right.type  = button.checked ? offset : none; break;
291          case 3: anchor.bottom.type = button.checked ? offset : none; break;
292       }
293
294       if(anchor.horz.type == middleRelative && (id == 0 || id == 2))
295       {
296          anchorDropBox.relButtons[0].checked = false;
297          anchorDropBox.relButtons[2].checked = false;
298       }
299       if(anchor.vert.type == middleRelative && (id == 1 || id == 3))
300       {
301          anchorDropBox.relButtons[1].checked = false;
302          anchorDropBox.relButtons[3].checked = false;
303       }
304       anchorDropBox.relButtons[id].checked = false;
305
306       //anchor.horz.type = none;
307       //anchor.vert.type = none;
308
309       {
310          int vpw, vph;
311          int x,y,w,h;
312          Window parent = control.parent;
313
314          // Fix Anchor
315          x = control.position.x;
316          y = control.position.y;
317          w = control.size.w;
318          h = control.size.h;
319
320          vpw = parent.clientSize.w;
321          vph = parent.clientSize.h;
322          if(control.nonClient)
323          {
324             vpw = parent.size.w;
325             vph = parent.size.h;
326          }
327          else if(((BorderBits)control.borderStyle).fixed)
328          {
329             if(!control.dontScrollHorz && parent.scrollArea.w) vpw = parent.scrollArea.w;
330             if(!control.dontScrollVert && parent.scrollArea.h) vph = parent.scrollArea.h;
331          }
332
333          if(anchor.left.type == offset) anchor.left.distance = x;
334          else if(anchor.left.type == relative) anchor.left.percent = (float)x / vpw;
335          if(anchor.top.type == offset) anchor.top.distance = y;
336          else if(anchor.top.type == relative) anchor.top.percent = (float)y / vph;
337          if(anchor.right.type == offset) anchor.right.distance = vpw - (x + w);
338          //else if(anchor.right.type == relative) anchor.right.percent = (float) (x + w) / vpw;
339          else if(anchor.right.type == relative) anchor.right.percent = (float) (vpw - (x + w)) / vpw;
340          if(anchor.bottom.type == offset) anchor.bottom.distance = vph - (y + h);
341          //else if(anchor.bottom.type == relative) anchor.bottom.percent = (float) (y + h) / vph;
342          else if(anchor.bottom.type == relative) anchor.bottom.percent = (float) (vph - (y + h)) / vph;
343
344          if(!anchor.left.type && !anchor.right.type)
345          {
346             anchor.horz.distance = (x + w / 2) - (vpw / 2);
347             //anchor.horz.type = anchor.horz.distance ? offset : 0;
348          }
349          else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
350          if(!anchor.top.type && !anchor.bottom.type)
351          {
352             anchor.vert.distance = (y + h / 2) - (vph / 2);
353             //anchor.vert.type = anchor.vert.distance ? offset : 0;
354          }
355          else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
356       }
357
358       {
359          char tempString[1024] = "";
360          bool needClass = false;
361          char * string = anchor.OnGetString(tempString, null, &needClass);
362          anchorDropBox.contents = string;
363       }
364
365       dropMaster.SetData(&anchor, false);
366       anchorDropBox.anchorValue = anchor;
367       return true;
368    }
369 }
370
371 private class AnchorRelButton : Button
372 {
373    toggle = true;
374    bevel = false;
375    text = "%";
376    //bevelOver = true;
377
378    void OnRedraw(Surface surface)
379    {
380       int cw = clientSize.w;
381       int ch = clientSize.h;
382       
383       if(checked)
384       {
385          surface.SetForeground(black);
386       }
387       else
388       {
389          surface.SetForeground(Color{170,170,170});
390       }
391       surface.WriteText(5,2, "%", 1);
392
393       if(active)
394       {
395          surface.LineStipple(0xAAAA);
396          surface.Rectangle(3,3,cw-4,ch-4);
397       }
398    }
399
400    bool AnchorEditor::NotifyClicked(Button button, int x, int y, Modifiers mods)
401    {
402       AnchorDropBox anchorDropBox = (AnchorDropBox)master;
403       Anchor anchor = anchorDropBox.anchorValue;
404       Window control = anchorDropBox.control;
405       DataBox dropMaster = (DataBox)anchorDropBox.master;
406       int64 id = button.id;
407
408       if((id == 0 || id == 2) && ((!anchor.left.type && !anchor.right.type) || anchor.left.type == middleRelative))
409       {
410          if(button.checked) anchor.horz.type = middleRelative; else anchor.horz.type = none;
411          anchorDropBox.relButtons[(id + 2)%4].checked = button.checked;
412       }
413       else if((id == 1 || id == 3) && ((!anchor.top.type && !anchor.bottom.type) || anchor.top.type == middleRelative))
414       {
415          if(button.checked) anchor.vert.type = middleRelative; else anchor.vert.type = none;
416          anchorDropBox.relButtons[(id + 2)%4].checked = button.checked;
417       }
418       else
419       {
420          switch(id)
421          {
422             case 0: anchor.left.type   = button.checked ? relative : (anchor.left.type   ? offset : none); break;
423             case 1: anchor.top.type    = button.checked ? relative : (anchor.top.type    ? offset : none); break;
424             case 2: anchor.right.type  = button.checked ? relative : (anchor.right.type  ? offset : none); break;
425             case 3: anchor.bottom.type = button.checked ? relative : (anchor.bottom.type ? offset : none); break;
426          }
427          anchorDropBox.buttons[id].checked = true;
428          if(anchor.horz.type == middleRelative) anchor.horz.type = none;
429          if(anchor.vert.type == middleRelative) anchor.vert.type = none;
430       }
431
432       {
433          int vpw, vph;
434          int x,y,w,h;
435          Window parent = control.parent;
436
437          // Fix Anchor
438          x = control.position.x;
439          y = control.position.y;
440          w = control.size.w;
441          h = control.size.h;
442
443          vpw = parent.clientSize.w;
444          vph = parent.clientSize.h;
445          if(control.nonClient)
446          {
447             vpw = parent.size.w;
448             vph = parent.size.h;
449          }
450          else if(((BorderBits)control.borderStyle).fixed)
451          {
452             if(!control.dontScrollHorz && parent.scrollArea.w)  vpw = parent.scrollArea.w;
453             if(!control.dontScrollVert && parent.scrollArea.h) vph = parent.scrollArea.h;
454          }
455
456          if(anchor.left.type == offset) anchor.left.distance = x;
457          else if(anchor.left.type == relative) anchor.left.percent = (float)x / vpw;
458          if(anchor.top.type == offset) anchor.top.distance = y;
459          else if(anchor.top.type == relative) anchor.top.percent = (float)y / vph;
460          if(anchor.right.type == offset) anchor.right.distance = vpw - (x + w);
461          //else if(anchor.right.type == relative) anchor.right.percent = (float) (x + w) / vpw;
462          else if(anchor.right.type == relative) anchor.right.percent = (float) (vpw - (x + w)) / vpw;
463          if(anchor.bottom.type == offset) anchor.bottom.distance = vph - (y + h);
464          //else if(anchor.bottom.type == relative) anchor.bottom.percent = (float) (y + h) / vph;
465          else if(anchor.bottom.type == relative) anchor.bottom.percent = (float) (vph - (y + h)) / vph;
466
467          if(!anchor.left.type && !anchor.right.type)
468          {
469             anchor.horz.distance = (x + w / 2) - (vpw / 2);
470             //anchor.horz.type = anchor.horz.distance ? offset : none;
471          }
472          else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
473          if(!anchor.top.type && !anchor.bottom.type) 
474          {
475             anchor.vert.distance = (y + h / 2) - (vph / 2);
476             //anchor.vert.type = anchor.vert.distance ? offset : none;
477          }
478          else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
479       }
480
481       {
482          char tempString[1024] = "";
483          bool needClass = false;
484          char * string = anchor.OnGetString(tempString, null, &needClass);
485          anchorDropBox.contents = string;
486       }
487
488       dropMaster.SetData(&anchor, false);
489       anchorDropBox.anchorValue = anchor;
490       return true;
491    }
492 }
493
494 private class AnchorEditor : Window
495 {
496    interim = true;
497    borderStyle = deepContour;
498    size.h = 92;
499
500    bool OnKeyDown(Key key, unichar ch)
501    {
502       if(key == escape)
503          return master.OnKeyDown(key, ch);
504       return true;
505    }
506 }
507
508 private class AnchorDropBox : DropBox
509 {
510    Anchor anchorValue;
511    Window control;
512    Button relButtons[4], buttons[4];
513
514    AnchorEditor anchorEditor
515    {
516       master = this;
517       autoCreate = false;
518    };
519
520    Window OnDropDown()
521    {
522       int c;
523       Button
524       {
525          anchorEditor,
526          anchor = Anchor { left = 28, top = 28, right = 28, bottom = 28 },
527          inactive = true, disabled = true
528       };
529       for(c = 0; c<4; c++)
530       {
531          Button button = buttons[c] = AnchorButton 
532          { 
533             anchorEditor, id = c,
534             size = Size { (c%2)?10:28, (c%2)?28:10 }
535          };
536          Button relButton = relButtons[c] = AnchorRelButton
537          {
538             anchorEditor, id = c;
539          };
540
541          switch(c)
542          {
543             case 0:
544                if(anchorValue.left.type && anchorValue.left.type != middleRelative) button.checked = true;
545                if(anchorValue.left.type == relative || anchorValue.horz.type == middleRelative) relButton.checked = true;
546                
547                button.anchor = Anchor { left = 0 };
548                relButton.anchor = Anchor { left = 5, vert = 16 };
549                break;
550             case 1:
551                if(anchorValue.top.type && anchorValue.top.type != middleRelative) button.checked = true;
552                if(anchorValue.top.type == relative || anchorValue.vert.type == middleRelative) relButton.checked = true;
553
554                button.anchor = Anchor { top = 0 };
555                relButton.anchor = Anchor { top = 5, horz = 16 };
556                break;
557             case 2: 
558                if(anchorValue.right.type && anchorValue.right.type != middleRelative) button.checked = true;
559                if(anchorValue.right.type == relative || anchorValue.horz.type == middleRelative) relButton.checked = true;
560                
561                button.anchor = Anchor { right = 0 };
562                relButton.anchor = Anchor { right = 5, vert = 16 };
563                break;
564             case 3: 
565                if(anchorValue.bottom.type && anchorValue.bottom.type != middleRelative) button.checked = true;
566                if(anchorValue.bottom.type == relative || anchorValue.vert.type == middleRelative) relButton.checked = true;
567
568                button.anchor = Anchor { bottom = 0 };
569                relButton.anchor = Anchor { bottom = 5, horz = 16 };
570                break;
571          }
572       }
573       anchorEditor.Create();
574       return anchorEditor;
575    }
576       
577    void OnCloseDropDown(Window anchorEditor)
578    {
579       // TOFIX: Patch for update bug
580       master.Update(null);
581       anchorEditor.Destroy(0);
582    }
583
584    bool DataBox::NotifyTextEntry(AnchorDropBox dropBox, char * string, bool save)
585    {
586       Anchor anchor = dropBox.anchorValue;
587       Window control = dropBox.control;
588
589       if(save)
590       {
591          if(anchor.OnGetDataFromString(string))
592          {
593             SetData(&anchor, false);
594             dropBox.anchorValue = anchor;
595          }
596       }
597       else
598       {
599          char tempString[1024] = "";
600          bool needClass = false;
601          char * string = anchor.OnGetString(tempString, null, &needClass);
602          dropBox.contents = string;
603       }
604       return true;
605    }
606 }