1 //
2 // "$Id$"
3 //
4 // Widget type code for the Fast Light Tool Kit (FLTK).
5 //
6 // Each object described by Fluid is one of these objects.  They
7 // are all stored in a double-linked list.
8 //
9 // They "type" of the object is covered by the virtual functions.
10 // There will probably be a lot of these virtual functions.
11 //
12 // The type browser is also a list of these objects, but they
13 // are "factory" instances, not "real" ones.  These objects exist
14 // only so the "make" method can be called on them.  They are
15 // not in the linked list and are not written to files or
16 // copied or otherwise examined.
17 //
18 // Copyright 1998-2016 by Bill Spitzak and others.
19 //
20 // This library is free software. Distribution and use rights are outlined in
21 // the file "COPYING" which should have been included with this file.  If this
22 // file is missing or damaged, see the license at:
23 //
24 //     http://www.fltk.org/COPYING.php
25 //
26 // Please report all bugs and problems on the following page:
27 //
28 //     http://www.fltk.org/str.php
29 //
30 
31 #include <FL/Fl.H>
32 #include <FL/Fl_Browser_.H>
33 #include <FL/fl_draw.H>
34 #include <stdlib.h>
35 #include "../src/flstring.h"
36 #include <stdio.h>
37 
38 #include "Fl_Type.h"
39 #include "undo.h"
40 
41 #include <FL/Fl_Pixmap.H>
42 #include "pixmaps/lock.xpm"
43 #include "pixmaps/protected.xpm"
44 //#include "pixmaps/unlock.xpm"
45 
46 static Fl_Pixmap	lock_pixmap(lock_xpm);
47 static Fl_Pixmap	protected_pixmap(protected_xpm);
48 //static Fl_Pixmap	unlock_pixmap(unlock_xpm);
49 
50 #include "pixmaps/flWindow.xpm"
51 #include "pixmaps/flButton.xpm"
52 #include "pixmaps/flCheckButton.xpm"
53 #include "pixmaps/flRoundButton.xpm"
54 #include "pixmaps/flBox.xpm"
55 #include "pixmaps/flGroup.xpm"
56 #include "pixmaps/flFunction.xpm"
57 #include "pixmaps/flCode.xpm"
58 #include "pixmaps/flCodeBlock.xpm"
59 #include "pixmaps/flComment.xpm"
60 #include "pixmaps/flData.xpm"
61 #include "pixmaps/flDeclaration.xpm"
62 #include "pixmaps/flDeclarationBlock.xpm"
63 #include "pixmaps/flClass.xpm"
64 #include "pixmaps/flTabs.xpm"
65 #include "pixmaps/flInput.xpm"
66 #include "pixmaps/flChoice.xpm"
67 #include "pixmaps/flMenuitem.xpm"
68 #include "pixmaps/flMenubar.xpm"
69 #include "pixmaps/flSubmenu.xpm"
70 #include "pixmaps/flScroll.xpm"
71 #include "pixmaps/flTile.xpm"
72 #include "pixmaps/flWizard.xpm"
73 #include "pixmaps/flPack.xpm"
74 #include "pixmaps/flReturnButton.xpm"
75 #include "pixmaps/flLightButton.xpm"
76 #include "pixmaps/flRepeatButton.xpm"
77 #include "pixmaps/flMenuButton.xpm"
78 #include "pixmaps/flOutput.xpm"
79 #include "pixmaps/flTextDisplay.xpm"
80 #include "pixmaps/flTextEdit.xpm"
81 #include "pixmaps/flFileInput.xpm"
82 #include "pixmaps/flBrowser.xpm"
83 #include "pixmaps/flCheckBrowser.xpm"
84 #include "pixmaps/flFileBrowser.xpm"
85 #include "pixmaps/flClock.xpm"
86 #include "pixmaps/flHelp.xpm"
87 #include "pixmaps/flProgress.xpm"
88 #include "pixmaps/flSlider.xpm"
89 #include "pixmaps/flScrollBar.xpm"
90 #include "pixmaps/flValueSlider.xpm"
91 #include "pixmaps/flAdjuster.xpm"
92 #include "pixmaps/flCounter.xpm"
93 #include "pixmaps/flDial.xpm"
94 #include "pixmaps/flRoller.xpm"
95 #include "pixmaps/flValueInput.xpm"
96 #include "pixmaps/flValueOutput.xpm"
97 #include "pixmaps/flSpinner.xpm"
98 #include "pixmaps/flWidgetClass.xpm"
99 #include "pixmaps/flTree.xpm"
100 #include "pixmaps/flTable.xpm"
101 
102 static Fl_Pixmap	window_pixmap(flWindow_xpm);
103 static Fl_Pixmap	button_pixmap(flButton_xpm);
104 static Fl_Pixmap	checkbutton_pixmap(flCheckButton_xpm);
105 static Fl_Pixmap	roundbutton_pixmap(flRoundButton_xpm);
106 static Fl_Pixmap	box_pixmap(flBox_xpm);
107 static Fl_Pixmap	group_pixmap(flGroup_xpm);
108 static Fl_Pixmap	function_pixmap(flFunction_xpm);
109 static Fl_Pixmap	code_pixmap(flCode_xpm);
110 static Fl_Pixmap	codeblock_pixmap(flCodeBlock_xpm);
111 static Fl_Pixmap	comment_pixmap(flComment_xpm);
112 static Fl_Pixmap	declaration_pixmap(flDeclaration_xpm);
113 static Fl_Pixmap	declarationblock_pixmap(flDeclarationBlock_xpm);
114 static Fl_Pixmap	class_pixmap(flClass_xpm);
115 static Fl_Pixmap	tabs_pixmap(flTabs_xpm);
116 static Fl_Pixmap	input_pixmap(flInput_xpm);
117 static Fl_Pixmap	choice_pixmap(flChoice_xpm);
118 static Fl_Pixmap	menuitem_pixmap(flMenuitem_xpm);
119 static Fl_Pixmap	menubar_pixmap(flMenubar_xpm);
120 static Fl_Pixmap	submenu_pixmap(flSubmenu_xpm);
121 static Fl_Pixmap	scroll_pixmap(flScroll_xpm);
122 static Fl_Pixmap	tile_pixmap(flTile_xpm);
123 static Fl_Pixmap	wizard_pixmap(flWizard_xpm);
124 static Fl_Pixmap	pack_pixmap(flPack_xpm);
125 static Fl_Pixmap	returnbutton_pixmap(flReturnButton_xpm);
126 static Fl_Pixmap	lightbutton_pixmap(flLightButton_xpm);
127 static Fl_Pixmap	repeatbutton_pixmap(flRepeatButton_xpm);
128 static Fl_Pixmap	menubutton_pixmap(flMenuButton_xpm);
129 static Fl_Pixmap	output_pixmap(flOutput_xpm);
130 static Fl_Pixmap	textdisplay_pixmap(flTextDisplay_xpm);
131 static Fl_Pixmap	textedit_pixmap(flTextEdit_xpm);
132 static Fl_Pixmap	fileinput_pixmap(flFileInput_xpm);
133 static Fl_Pixmap	browser_pixmap(flBrowser_xpm);
134 static Fl_Pixmap	checkbrowser_pixmap(flCheckBrowser_xpm);
135 static Fl_Pixmap	filebrowser_pixmap(flFileBrowser_xpm);
136 static Fl_Pixmap	clock_pixmap(flClock_xpm);
137 static Fl_Pixmap	help_pixmap(flHelp_xpm);
138 static Fl_Pixmap	progress_pixmap(flProgress_xpm);
139 static Fl_Pixmap	slider_pixmap(flSlider_xpm);
140 static Fl_Pixmap	scrollbar_pixmap(flScrollBar_xpm);
141 static Fl_Pixmap	valueslider_pixmap(flValueSlider_xpm);
142 static Fl_Pixmap	adjuster_pixmap(flAdjuster_xpm);
143 static Fl_Pixmap	counter_pixmap(flCounter_xpm);
144 static Fl_Pixmap	dial_pixmap(flDial_xpm);
145 static Fl_Pixmap	roller_pixmap(flRoller_xpm);
146 static Fl_Pixmap	valueinput_pixmap(flValueInput_xpm);
147 static Fl_Pixmap	valueoutput_pixmap(flValueOutput_xpm);
148 static Fl_Pixmap	spinner_pixmap(flSpinner_xpm);
149 static Fl_Pixmap	widgetclass_pixmap(flWidgetClass_xpm);
150 static Fl_Pixmap	data_pixmap(flData_xpm);
151 static Fl_Pixmap	tree_pixmap(flTree_xpm);
152 static Fl_Pixmap	table_pixmap(flTable_xpm);
153 
154 Fl_Pixmap *pixmap[] = { 0, &window_pixmap, &button_pixmap, &checkbutton_pixmap, &roundbutton_pixmap, /* 0..4 */
155  &box_pixmap, &group_pixmap, &function_pixmap, &code_pixmap, &codeblock_pixmap, &declaration_pixmap, /* 5..10 */
156  &declarationblock_pixmap, &class_pixmap, &tabs_pixmap, &input_pixmap, &choice_pixmap,               /* 11..15 */
157  &menuitem_pixmap, &menubar_pixmap, &submenu_pixmap, &scroll_pixmap, &tile_pixmap, &wizard_pixmap,   /* 16..21 */
158  &pack_pixmap, &returnbutton_pixmap, &lightbutton_pixmap, &repeatbutton_pixmap, &menubutton_pixmap,  /* 22..26 */
159  &output_pixmap, &textdisplay_pixmap, &textedit_pixmap, &fileinput_pixmap, &browser_pixmap,          /* 27..32 */
160  &checkbrowser_pixmap, &filebrowser_pixmap, &clock_pixmap, &help_pixmap, &progress_pixmap,	     /* 33..36 */
161  &slider_pixmap, &scrollbar_pixmap, &valueslider_pixmap, &adjuster_pixmap, &counter_pixmap,          /* 37..41 */
162  &dial_pixmap, &roller_pixmap, &valueinput_pixmap, &valueoutput_pixmap, &comment_pixmap,             /* 42..46 */
163  &spinner_pixmap, &widgetclass_pixmap, &data_pixmap, &tree_pixmap, &table_pixmap };                  /* 47..51 */
164 
165 extern int show_comments;
166 
167 ////////////////////////////////////////////////////////////////
168 
169 // Copy the given string str to buffer p with no more than maxl characters.
170 // Add "..." if string was truncated.
171 // If parameter quote is true (not 0) the string is quoted with "".
172 // Quote characters are NOT counted.
173 // The returned buffer (string) is terminated with a null byte.
174 // Returns pointer to end of string (before terminating null byte).
175 // Note: the buffer p must be large enough to hold (4 * (maxl+1) + 1) bytes
176 // or (4 * (maxl+1) + 3) bytes if quoted, e.g. "123..." because each UTF-8
177 // character can consist of 4 bytes, "..." adds 3 bytes, quotes '""' add two
178 // bytes, and the terminating null byte adds another byte.
179 // This supports Unicode code points up to U+10FFFF (standard as of 10/2016).
180 // Sanity checks for illegal UTF-8 sequences are included.
181 
copy_trunc(char * p,const char * str,int maxl,int quote)182 static char *copy_trunc(char *p, const char *str, int maxl, int quote) {
183 
184   int size = 0;				// truncated string size in characters
185   int bs;				// size of UTF-8 character in bytes
186   const char *end = str + strlen(str);	// end of input string
187   if (quote) *p++ = '"';		// opening quote
188   while (size < maxl) {			// maximum <maxl> characters
189     if (!(*str & (-32))) break;		// end of string (0 or control char)
190     bs = fl_utf8len(*str);		// size of next character
191     if (bs <= 0) break;			// some error - leave
192     if (str + bs > end) break;		// UTF-8 sequence beyond end of string
193     while (bs--) *p++ = *str++;		// copy that character into the buffer
194     size++;				// count copied characters
195   }
196   if (*str) {				// string was truncated
197     strcpy(p,"..."); p += 3;
198   }
199   if (quote) *p++ = '"';		// closing quote
200   *p = 0;				// terminating null byte
201   return p;
202 }
203 
204 ////////////////////////////////////////////////////////////////
205 
206 class Widget_Browser : public Fl_Browser_ {
207   friend class Fl_Type;
208 
209   // required routines for Fl_Browser_ subclass:
210   void *item_first() const ;
211   void *item_next(void *) const ;
212   void *item_prev(void *) const ;
213   int item_selected(void *) const ;
214   void item_select(void *,int);
215   int item_width(void *) const ;
216   int item_height(void *) const ;
217   void item_draw(void *,int,int,int,int) const ;
218   int incr_height() const ;
219 
220 public:
221 
222   int handle(int);
223   void callback();
224   Widget_Browser(int,int,int,int,const char * =0);
225 };
226 
227 static Widget_Browser *widget_browser;
make_widget_browser(int x,int y,int w,int h)228 Fl_Widget *make_widget_browser(int x,int y,int w,int h) {
229   return (widget_browser = new Widget_Browser(x,y,w,h));
230 }
231 
redraw_widget_browser(Fl_Type * caller)232 void redraw_widget_browser(Fl_Type *caller)
233 {
234   if (caller) {
235     widget_browser->display(caller);
236   }
237   widget_browser->redraw();
238 }
239 
select(Fl_Type * o,int v)240 void select(Fl_Type *o, int v) {
241   widget_browser->select(o,v,1);
242   //  Fl_Type::current = o;
243 }
244 
select_only(Fl_Type * o)245 void select_only(Fl_Type *o) {
246   widget_browser->select_only(o,1);
247 }
248 
deselect()249 void deselect() {
250   widget_browser->deselect();
251   //Fl_Type::current = 0; // this breaks the paste & merge functions
252 }
253 
254 Fl_Type *Fl_Type::first;
255 Fl_Type *Fl_Type::last;
256 
Widget_Browser_callback(Fl_Widget * o,void *)257 static void Widget_Browser_callback(Fl_Widget *o,void *) {
258   ((Widget_Browser *)o)->callback();
259 }
260 
Widget_Browser(int X,int Y,int W,int H,const char * l)261 Widget_Browser::Widget_Browser(int X,int Y,int W,int H,const char*l)
262 : Fl_Browser_(X,Y,W,H,l) {
263   type(FL_MULTI_BROWSER);
264   Fl_Widget::callback(Widget_Browser_callback);
265   when(FL_WHEN_RELEASE);
266 }
267 
item_first() const268 void *Widget_Browser::item_first() const {return Fl_Type::first;}
269 
item_next(void * l) const270 void *Widget_Browser::item_next(void *l) const {return ((Fl_Type*)l)->next;}
271 
item_prev(void * l) const272 void *Widget_Browser::item_prev(void *l) const {return ((Fl_Type*)l)->prev;}
273 
item_selected(void * l) const274 int Widget_Browser::item_selected(void *l) const {return ((Fl_Type*)l)->new_selected;}
275 
item_select(void * l,int v)276 void Widget_Browser::item_select(void *l,int v) {((Fl_Type*)l)->new_selected = v;}
277 
item_height(void * l) const278 int Widget_Browser::item_height(void *l) const {
279   Fl_Type *t = (Fl_Type*)l;
280   if (t->visible) {
281     if (show_comments && t->comment())
282       return textsize()*2+4;
283     else
284       return textsize()+5;
285   }
286   return 0;
287 }
288 
incr_height() const289 int Widget_Browser::incr_height() const {return textsize()+2;}
290 
291 static Fl_Type* pushedtitle;
292 
293 // Generate a descriptive text for this item, to put in browser & window titles
title()294 const char* Fl_Type::title() {
295   const char* c = name(); if (c) return c;
296   return type_name();
297 }
298 
299 extern const char* subclassname(Fl_Type*);
300 
301 
302 /**
303   Draw an item in the widget browser.
304 
305   A browser line starts with a variable size space. This space directly
306   relates to the level of the type entry.
307 
308   If this type has the ability to store children, a triangle follows,
309   pointing right (closed) or pointing down (open, children shown).
310 
311   Next follows an icon that is specific to the type. This makes it easy to
312   spot certain types.
313 
314   Now follows some text. For classes and widgets, this is the type itself,
315   followed by the name of the object. Other objects show their content as
316   text, possibly abbreviated with an ellipsis.
317 
318   \param v	v is a pointer to the actual widget type and can be cast safely
319 		to Fl_Type
320   \param X,Y	these give the position in window coordinates of the top left
321 		corner of this line
322 */
item_draw(void * v,int X,int Y,int,int) const323 void Widget_Browser::item_draw(void *v, int X, int Y, int, int) const {
324   // cast to a more general type
325   Fl_Type *l = (Fl_Type *)v;
326 
327   char buf[340]; // edit buffer: large enough to hold 80 UTF-8 chars + nul
328 
329   // calculate the horizontal start position of this item
330   // 3 is the edge of the browser
331   // 13 is the width of the arrow that indicates children for the item
332   // 18 is the width of the icon
333   // 12 is the indent per level
334   X += 3 + 13 + 18 + l->level * 12;
335 
336   // calculate the horizontal start position and width of the separator line
337   int x1 = X;
338   int w1 = w() - x1;
339 
340   // items can contain a comment. If they do, the comment gets a second text
341   // line inside this browser line
342   int comment_incr = 0;
343   if (show_comments && l->comment()) {
344     copy_trunc(buf, l->comment(), 80, 0);
345     comment_incr = textsize()-1;
346     if (l->new_selected) fl_color(fl_contrast(FL_DARK_GREEN,FL_SELECTION_COLOR));
347     else fl_color(fl_contrast(FL_DARK_GREEN,color()));
348     fl_font(textfont()+FL_ITALIC, textsize()-2);
349     fl_draw(buf, X, Y+12);
350     Y += comment_incr/2;
351     comment_incr -= comment_incr/2;
352   }
353 
354   if (l->new_selected) fl_color(fl_contrast(FL_FOREGROUND_COLOR,FL_SELECTION_COLOR));
355   else fl_color(FL_FOREGROUND_COLOR);
356 
357   // Width=10: Draw the triangle that indicates possible children
358   if (l->is_parent()) {
359     X = X - 18 - 13;
360     if (!l->next || l->next->level <= l->level) {
361       if (l->open_!=(l==pushedtitle)) {
362         // an outlined triangle to the right indicates closed item, no children
363         fl_loop(X,Y+7,X+5,Y+12,X+10,Y+7);
364       } else {
365         // an outlined triangle to the bottom indicates open item, no children
366         fl_loop(X+2,Y+2,X+7,Y+7,X+2,Y+12);
367       }
368     } else {
369       if (l->open_!=(l==pushedtitle)) {
370         // a filled triangle to the right indicates closed item, with children
371         fl_polygon(X,Y+7,X+5,Y+12,X+10,Y+7);
372       } else {
373         // a filled triangle to the bottom indicates open item, with children
374         fl_polygon(X+2,Y+2,X+7,Y+7,X+2,Y+12);
375       }
376     }
377     X = X + 13 + 18;
378   }
379 
380   // Width=18: Draw the icon associated with the type.
381   Fl_Pixmap *pm = pixmap[l->pixmapID()];
382   if (pm) pm->draw(X-18, Y);
383 
384   // Add tags on top of the icon for locked and protected types.
385   switch (l->is_public()) {
386     case 0: lock_pixmap.draw(X - 17, Y); break;
387     case 2: protected_pixmap.draw(X - 17, Y); break;
388   }
389 
390   // Indent=12 per level: Now write the text that comes after the graphics representation
391   Y += comment_incr;
392   if (l->is_widget() || l->is_class()) {
393     const char* c = subclassname(l);
394     if (!strncmp(c,"Fl_",3)) c += 3;
395     fl_font(textfont(), textsize());
396     fl_draw(c, X, Y+13);
397     X += int(fl_width(c)+fl_width('n'));
398     c = l->name();
399     if (c) {
400       fl_font(textfont()|FL_BOLD, textsize());
401       fl_draw(c, X, Y+13);
402     } else if ((c = l->label())) {
403       copy_trunc(buf, c, 20, 1); // quoted string
404       fl_draw(buf, X, Y+13);
405     }
406   } else {
407     copy_trunc(buf, l->title(), 55, 0);
408     fl_font(textfont() | (l->is_code_block() && (l->level==0 || l->parent->is_class())?0:FL_BOLD), textsize());
409     fl_draw(buf, X, Y+13);
410   }
411 
412   // draw a thin line below the item if this item is not selected
413   // (if it is selected this additional line would look bad)
414   if (!l->new_selected) {
415     fl_color(fl_lighter(FL_GRAY));
416     fl_line(x1,Y+16,x1+w1,Y+16);
417   }
418 }
419 
item_width(void * v) const420 int Widget_Browser::item_width(void *v) const {
421 
422   char buf[340]; // edit buffer: large enough to hold 80 UTF-8 chars + nul
423 
424   Fl_Type *l = (Fl_Type *)v;
425 
426   if (!l->visible) return 0;
427 
428   int W = 3 + 13 + 18 + l->level * 12;
429 
430   if (l->is_widget() || l->is_class()) {
431     const char* c = l->type_name();
432     if (!strncmp(c,"Fl_",3)) c += 3;
433     fl_font(textfont(), textsize());
434     W += int(fl_width(c) + fl_width('n'));
435     c = l->name();
436     if (c) {
437       fl_font(textfont()|FL_BOLD, textsize());
438       W += int(fl_width(c));
439     } else if (l->label()) {
440       copy_trunc(buf, l->label(), 20, 1); // quoted string
441       W += int(fl_width(buf));
442     }
443   } else {
444     copy_trunc(buf, l->title(), 55, 0);
445     fl_font(textfont() | (l->is_code_block() && (l->level==0 || l->parent->is_class())?0:FL_BOLD), textsize());
446     W += int(fl_width(buf));
447   }
448 
449   return W;
450 }
451 
redraw_browser()452 void redraw_browser() {
453   widget_browser->redraw();
454 }
455 
callback()456 void Widget_Browser::callback() {
457   selection_changed((Fl_Type*)selection());
458 }
459 
460 
461 /**
462   Override the event handling for this browser.
463 
464   The vertical mouse position corresponds to an entry in the type tree.
465   The horizontal position has the following hot zones:
466   - 0-3 is the widget frame and ignored
467   - the next hot zone starts 12*indent pixels further to the right
468   - the next 13 pixels refer to the arrow that indicates children for the item
469   - 18 pixels follow for the icon
470   - the remaining part is filled with text
471 
472   \param[in] e the incoming event type
473   \return 0 if the event is not supported, and 1 if the event was "used up"
474 */
handle(int e)475 int Widget_Browser::handle(int e) {
476   static Fl_Type *title;
477   Fl_Type *l;
478   int X,Y,W,H; bbox(X,Y,W,H);
479   switch (e) {
480   case FL_PUSH:
481     if (!Fl::event_inside(X,Y,W,H)) break;
482     l = (Fl_Type*)find_item(Fl::event_y());
483     if (l) {
484       X += 3 + 12*l->level - hposition();
485       if (l->is_parent() && Fl::event_x()>X && Fl::event_x()<X+13) {
486 	title = pushedtitle = l;
487 	redraw_line(l);
488 	return 1;
489       }
490     }
491     break;
492   case FL_DRAG:
493     if (!title) break;
494     l = (Fl_Type*)find_item(Fl::event_y());
495     if (l) {
496       X += 3 + 12*l->level - hposition();
497       if (l->is_parent() && Fl::event_x()>X && Fl::event_x()<X+13) ;
498       else l = 0;
499     }
500     if (l != pushedtitle) {
501       if (pushedtitle) redraw_line(pushedtitle);
502       if (l) redraw_line(l);
503       pushedtitle = l;
504     }
505     return 1;
506   case FL_RELEASE:
507     if (!title) {
508       l = (Fl_Type*)find_item(Fl::event_y());
509       if (l && l->new_selected && (Fl::event_clicks() || Fl::event_state(FL_CTRL)))
510 	l->open();
511       break;
512     }
513     l = pushedtitle;
514     title = pushedtitle = 0;
515     if (l) {
516       if (l->open_) {
517 	l->open_ = 0;
518 	for (Fl_Type*k = l->next; k&&k->level>l->level; k = k->next)
519 	  k->visible = 0;
520       } else {
521 	l->open_ = 1;
522 	for (Fl_Type*k=l->next; k&&k->level>l->level;) {
523 	  k->visible = 1;
524 	  if (k->is_parent() && !k->open_) {
525 	    Fl_Type *j;
526 	    for (j = k->next; j && j->level>k->level; j = j->next) {/*empty*/}
527 	    k = j;
528 	  } else
529 	    k = k->next;
530 	}
531       }
532       redraw();
533     }
534     return 1;
535   }
536   return Fl_Browser_::handle(e);
537 }
538 
Fl_Type()539 Fl_Type::Fl_Type() {
540   factory = 0;
541   parent = 0;
542   next = prev = 0;
543   selected = new_selected = 0;
544   visible = 0;
545   name_ = 0;
546   label_ = 0;
547   user_data_ = 0;
548   user_data_type_ = 0;
549   callback_ = 0;
550   comment_ = 0;
551   rtti = 0;
552   level = 0;
553   code_position = header_position = -1;
554   code_position_end = header_position_end = -1;
555 }
556 
fixvisible(Fl_Type * p)557 static void fixvisible(Fl_Type *p) {
558   Fl_Type *t = p;
559   for (;;) {
560     if (t->parent) t->visible = t->parent->visible && t->parent->open_;
561     else t->visible = 1;
562     t = t->next;
563     if (!t || t->level <= p->level) break;
564   }
565 }
566 
567 // turn a click at x,y on this into the actual picked object:
click_test(int,int)568 Fl_Type* Fl_Type::click_test(int,int) {return 0;}
add_child(Fl_Type *,Fl_Type *)569 void Fl_Type::add_child(Fl_Type*, Fl_Type*) {}
move_child(Fl_Type *,Fl_Type *)570 void Fl_Type::move_child(Fl_Type*, Fl_Type*) {}
remove_child(Fl_Type *)571 void Fl_Type::remove_child(Fl_Type*) {}
572 
573 // add a list of widgets as a new child of p:
add(Fl_Type * p)574 void Fl_Type::add(Fl_Type *p) {
575   if (p && parent == p) return;
576   undo_checkpoint();
577   parent = p;
578   Fl_Type *end = this;
579   while (end->next) end = end->next;
580   Fl_Type *q;
581   int newlevel;
582   if (p) {
583     for (q = p->next; q && q->level > p->level; q = q->next) {/*empty*/}
584     newlevel = p->level+1;
585   } else {
586     q = 0;
587     newlevel = 0;
588   }
589   for (Fl_Type *t = this->next; t; t = t->next) t->level += (newlevel-level);
590   level = newlevel;
591   if (q) {
592     prev = q->prev;
593     prev->next = this;
594     q->prev = end;
595     end->next = q;
596   } else if (first) {
597     prev = last;
598     prev->next = this;
599     end->next = 0;
600     last = end;
601   } else {
602     first = this;
603     last = end;
604     prev = end->next = 0;
605   }
606   if (p) p->add_child(this,0);
607   open_ = 1;
608   fixvisible(this);
609   set_modflag(1);
610   widget_browser->redraw();
611 }
612 
613 // add to a parent before another widget:
insert(Fl_Type * g)614 void Fl_Type::insert(Fl_Type *g) {
615   Fl_Type *end = this;
616   while (end->next) end = end->next;
617   parent = g->parent;
618   int newlevel = g->level;
619   visible = g->visible;
620   for (Fl_Type *t = this->next; t; t = t->next) t->level += newlevel-level;
621   level = newlevel;
622   prev = g->prev;
623   if (prev) prev->next = this; else first = this;
624   end->next = g;
625   g->prev = end;
626   fixvisible(this);
627   if (parent) parent->add_child(this, g);
628   widget_browser->redraw();
629 }
630 
631 // Return message number for I18N...
632 int
msgnum()633 Fl_Type::msgnum() {
634   int		count;
635   Fl_Type	*p;
636 
637   for (count = 0, p = this; p;) {
638     if (p->label()) count ++;
639     if (p != this && p->is_widget() && ((Fl_Widget_Type *)p)->tooltip()) count ++;
640 
641     if (p->prev) p = p->prev;
642     else p = p->parent;
643   }
644 
645   return count;
646 }
647 
648 
649 // delete from parent:
remove()650 Fl_Type *Fl_Type::remove() {
651   Fl_Type *end = this;
652   for (;;) {
653     if (!end->next || end->next->level <= level) break;
654     end = end->next;
655   }
656   if (prev) prev->next = end->next;
657   else first = end->next;
658   if (end->next) end->next->prev = prev;
659   else last = prev;
660   Fl_Type *r = end->next;
661   prev = end->next = 0;
662   if (parent) parent->remove_child(this);
663   parent = 0;
664   widget_browser->redraw();
665   selection_changed(0);
666   return r;
667 }
668 
669 // update a string member:
storestring(const char * n,const char * & p,int nostrip)670 int storestring(const char *n, const char * & p, int nostrip) {
671   if (n == p) return 0;
672   undo_checkpoint();
673   int length = 0;
674   if (n) { // see if blank, strip leading & trailing blanks
675     if (!nostrip) while (isspace((int)(unsigned char)*n)) n++;
676     const char *e = n + strlen(n);
677     if (!nostrip) while (e > n && isspace((int)(unsigned char)*(e-1))) e--;
678     length = e-n;
679     if (!length) n = 0;
680   }
681   if (n == p) return 0;
682   if (n && p && !strncmp(n,p,length) && !p[length]) return 0;
683   if (p) free((void *)p);
684   if (!n || !*n) {
685     p = 0;
686   } else {
687     char *q = (char *)malloc(length+1);
688     strlcpy(q,n,length+1);
689     p = q;
690   }
691   set_modflag(1);
692   return 1;
693 }
694 
name(const char * n)695 void Fl_Type::name(const char *n) {
696   int nostrip = is_comment();
697   if (storestring(n,name_,nostrip)) {
698     if (visible) widget_browser->redraw();
699   }
700 }
701 
label(const char * n)702 void Fl_Type::label(const char *n) {
703   if (storestring(n,label_,1)) {
704     setlabel(label_);
705     if (visible && !name_) widget_browser->redraw();
706   }
707 }
708 
callback(const char * n)709 void Fl_Type::callback(const char *n) {
710   storestring(n,callback_);
711 }
712 
user_data(const char * n)713 void Fl_Type::user_data(const char *n) {
714   storestring(n,user_data_);
715 }
716 
user_data_type(const char * n)717 void Fl_Type::user_data_type(const char *n) {
718   storestring(n,user_data_type_);
719 }
720 
comment(const char * n)721 void Fl_Type::comment(const char *n) {
722   if (storestring(n,comment_,1)) {
723     if (visible) widget_browser->redraw();
724   }
725 }
726 
open()727 void Fl_Type::open() {
728   printf("Open of '%s' is not yet implemented\n",type_name());
729 }
730 
setlabel(const char *)731 void Fl_Type::setlabel(const char *) {}
732 
~Fl_Type()733 Fl_Type::~Fl_Type() {
734   // warning: destructor only works for widgets that have been add()ed.
735   if (widget_browser) widget_browser->deleting(this);
736   if (prev) prev->next = next; else first = next;
737   if (next) next->prev = prev; else last = prev;
738   if (current == this) current = 0;
739   if (parent) parent->remove_child(this);
740   if (name_) free((void*)name_);
741   if (label_) free((void*)label_);
742   if (callback_) free((void*)callback_);
743   if (user_data_) free((void*)user_data_);
744   if (user_data_type_) free((void*)user_data_type_);
745   if (comment_) free((void*)comment_);
746 }
747 
is_parent() const748 int Fl_Type::is_parent() const {return 0;}
is_widget() const749 int Fl_Type::is_widget() const {return 0;}
is_valuator() const750 int Fl_Type::is_valuator() const {return 0;}
is_spinner() const751 int Fl_Type::is_spinner() const {return 0;}
is_button() const752 int Fl_Type::is_button() const {return 0;}
is_input() const753 int Fl_Type::is_input() const {return 0;}
is_value_input() const754 int Fl_Type::is_value_input() const {return 0;}
is_text_display() const755 int Fl_Type::is_text_display() const {return 0;}
is_menu_item() const756 int Fl_Type::is_menu_item() const {return 0;}
is_menu_button() const757 int Fl_Type::is_menu_button() const {return 0;}
is_group() const758 int Fl_Type::is_group() const {return 0;}
is_window() const759 int Fl_Type::is_window() const {return 0;}
is_code() const760 int Fl_Type::is_code() const {return 0;}
is_code_block() const761 int Fl_Type::is_code_block() const {return 0;}
is_decl_block() const762 int Fl_Type::is_decl_block() const {return 0;}
is_comment() const763 int Fl_Type::is_comment() const {return 0;}
is_class() const764 int Fl_Type::is_class() const {return 0;}
is_public() const765 int Fl_Type::is_public() const {return 1;}
766 
is_public() const767 int Fl_Code_Type::is_public()const { return -1; }
is_public() const768 int Fl_CodeBlock_Type::is_public()const { return -1; }
769 
770 
771 ////////////////////////////////////////////////////////////////
772 
773 Fl_Type *in_this_only; // set if menu popped-up in window
774 
select_all_cb(Fl_Widget *,void *)775 void select_all_cb(Fl_Widget *,void *) {
776   Fl_Type *p = Fl_Type::current ? Fl_Type::current->parent : 0;
777   if (in_this_only) {
778     Fl_Type *t = p;
779     for (; t && t != in_this_only; t = t->parent) {/*empty*/}
780     if (t != in_this_only) p = in_this_only;
781   }
782   for (;;) {
783     if (p) {
784       int foundany = 0;
785       for (Fl_Type *t = p->next; t && t->level>p->level; t = t->next) {
786 	if (!t->new_selected) {widget_browser->select(t,1,0); foundany = 1;}
787       }
788       if (foundany) break;
789       p = p->parent;
790     } else {
791       for (Fl_Type *t = Fl_Type::first; t; t = t->next)
792 	widget_browser->select(t,1,0);
793       break;
794     }
795   }
796   selection_changed(p);
797 }
798 
select_none_cb(Fl_Widget *,void *)799 void select_none_cb(Fl_Widget *,void *) {
800   Fl_Type *p = Fl_Type::current ? Fl_Type::current->parent : 0;
801   if (in_this_only) {
802     Fl_Type *t = p;
803     for (; t && t != in_this_only; t = t->parent) {/*empty*/}
804     if (t != in_this_only) p = in_this_only;
805   }
806   for (;;) {
807     if (p) {
808       int foundany = 0;
809       for (Fl_Type *t = p->next; t && t->level>p->level; t = t->next) {
810 	if (t->new_selected) {widget_browser->select(t,0,0); foundany = 1;}
811       }
812       if (foundany) break;
813       p = p->parent;
814     } else {
815       for (Fl_Type *t = Fl_Type::first; t; t = t->next)
816 	widget_browser->select(t,0,0);
817       break;
818     }
819   }
820   selection_changed(p);
821 }
822 
delete_children(Fl_Type * p)823 static void delete_children(Fl_Type *p) {
824   Fl_Type *f;
825   for (f = p; f && f->next && f->next->level > p->level; f = f->next) {/*empty*/}
826   for (; f != p; ) {
827     Fl_Type *g = f->prev;
828     delete f;
829     f = g;
830   }
831 }
832 
delete_all(int selected_only)833 void delete_all(int selected_only) {
834   for (Fl_Type *f = Fl_Type::first; f;) {
835     if (f->selected || !selected_only) {
836       delete_children(f);
837       Fl_Type *g = f->next;
838       delete f;
839       f = g;
840     } else f = f->next;
841   }
842   if(!selected_only) {
843 		include_H_from_C=1;
844 		use_FL_COMMAND=0;
845 	}
846 
847   selection_changed(0);
848 }
849 
850 // move f (and it's children) into list before g:
851 // returns pointer to whatever is after f & children
move_before(Fl_Type * g)852 void Fl_Type::move_before(Fl_Type* g) {
853   if (level != g->level) printf("move_before levels don't match! %d %d\n",
854 				level, g->level);
855   Fl_Type* n;
856   for (n = next; n && n->level > level; n = n->next) {/*empty*/}
857   if (n == g) return;
858   Fl_Type *l = n ? n->prev : Fl_Type::last;
859   prev->next = n;
860   if (n) n->prev = prev; else Fl_Type::last = prev;
861   prev = g->prev;
862   l->next = g;
863   if (prev) prev->next = this; else Fl_Type::first = this;
864   g->prev = l;
865   if (parent && is_widget()) parent->move_child(this,g);
866   widget_browser->inserting(g, this);
867   widget_browser->display(this);
868   widget_browser->redraw();
869 }
870 
871 
872 // move selected widgets in their parent's list:
earlier_cb(Fl_Widget *,void *)873 void earlier_cb(Fl_Widget*,void*) {
874   Fl_Type *f;
875   int mod = 0;
876   for (f = Fl_Type::first; f; ) {
877     Fl_Type* nxt = f->next;
878     if (f->selected) {
879       Fl_Type* g;
880       for (g = f->prev; g && g->level > f->level; g = g->prev) {/*empty*/}
881       if (g && g->level == f->level && !g->selected) {
882         f->move_before(g);
883         mod = 1;
884       }
885     }
886     f = nxt;
887   }
888   if (mod) set_modflag(1);
889 }
890 
later_cb(Fl_Widget *,void *)891 void later_cb(Fl_Widget*,void*) {
892   Fl_Type *f;
893   int mod = 0;
894   for (f = Fl_Type::last; f; ) {
895     Fl_Type* prv = f->prev;
896     if (f->selected) {
897       Fl_Type* g;
898       for (g = f->next; g && g->level > f->level; g = g->next) {/*empty*/}
899       if (g && g->level == f->level && !g->selected) {
900         g->move_before(f);
901         mod = 1;
902       }
903     }
904     f = prv;
905   }
906   if (mod) set_modflag(1);
907 }
908 
909 ////////////////////////////////////////////////////////////////
910 
911 // write a widget and all it's children:
write()912 void Fl_Type::write() {
913     write_indent(level);
914     write_word(type_name());
915 
916     if (is_class()) {
917       const char * p = 	((Fl_Class_Type*)this)->prefix();
918       if (p &&	strlen(p))
919         write_word(p);
920     }
921 
922     write_word(name());
923     write_open(level);
924     write_properties();
925     write_close(level);
926     if (!is_parent()) return;
927     // now do children:
928     write_open(level);
929     Fl_Type *child;
930     for (child = next; child && child->level > level; child = child->next)
931 	if (child->level == level+1) child->write();
932     write_close(level);
933 }
934 
write_properties()935 void Fl_Type::write_properties() {
936   // repeat this for each attribute:
937   if (label()) {
938     write_indent(level+1);
939     write_word("label");
940     write_word(label());
941   }
942   if (user_data()) {
943     write_indent(level+1);
944     write_word("user_data");
945     write_word(user_data());
946   }
947   if (user_data_type()) {
948     write_word("user_data_type");
949     write_word(user_data_type());
950   }
951   if (callback()) {
952     write_indent(level+1);
953     write_word("callback");
954     write_word(callback());
955   }
956   if (comment()) {
957     write_indent(level+1);
958     write_word("comment");
959     write_word(comment());
960   }
961   if (is_parent() && open_) write_word("open");
962   if (selected) write_word("selected");
963 }
964 
read_property(const char * c)965 void Fl_Type::read_property(const char *c) {
966   if (!strcmp(c,"label"))
967     label(read_word());
968   else if (!strcmp(c,"user_data"))
969     user_data(read_word());
970   else if (!strcmp(c,"user_data_type"))
971     user_data_type(read_word());
972   else if (!strcmp(c,"callback"))
973     callback(read_word());
974   else if (!strcmp(c,"comment"))
975     comment(read_word());
976   else if (!strcmp(c,"open"))
977     open_ = 1;
978   else if (!strcmp(c,"selected"))
979     select(this,1);
980   else
981     read_error("Unknown property \"%s\"", c);
982 }
983 
read_fdesign(const char *,const char *)984 int Fl_Type::read_fdesign(const char*, const char*) {return 0;}
985 
986 /**
987   Return 1 if the list contains a function with the given signature at the top level.
988  */
has_toplevel_function(const char * rtype,const char * sig)989 int has_toplevel_function(const char *rtype, const char *sig) {
990   Fl_Type *child;
991   for (child = Fl_Type::first; child; child = child->next) {
992     if (!child->is_in_class() && strcmp(child->type_name(), "Function")==0) {
993       const Fl_Function_Type *fn = (const Fl_Function_Type*)child;
994       if (fn->has_signature(rtype, sig))
995         return 1;
996     }
997   }
998   return 0;
999 }
1000 
1001 /**
1002   Write a comment into the header file.
1003 */
write_comment_h(const char * pre)1004 void Fl_Type::write_comment_h(const char *pre)
1005 {
1006   if (comment() && *comment()) {
1007     write_h("%s/**\n", pre);
1008     const char *s = comment();
1009     write_h("%s ", pre);
1010     while(*s) {
1011       if (*s=='\n') {
1012         if (s[1]) {
1013           write_h("\n%s ", pre);
1014         }
1015       } else {
1016         write_h("%c", *s); // FIXME this is much too slow!
1017       }
1018       s++;
1019     }
1020     write_h("\n%s*/\n", pre);
1021   }
1022 }
1023 
1024 /**
1025   Write a comment into the source file.
1026 */
write_comment_c(const char * pre)1027 void Fl_Type::write_comment_c(const char *pre)
1028 {
1029   if (comment() && *comment()) {
1030     write_c("%s/**\n", pre);
1031     const char *s = comment();
1032     write_c("%s ", pre);
1033     while(*s) {
1034       if (*s=='\n') {
1035         if (s[1]) {
1036           write_c("\n%s ", pre);
1037         }
1038       } else {
1039         write_c("%c", *s); // FIXME this is much too slow!
1040       }
1041       s++;
1042     }
1043     write_c("\n%s*/\n", pre);
1044   }
1045 }
1046 
1047 /**
1048   Write a comment into the source file.
1049 */
write_comment_inline_c(const char * pre)1050 void Fl_Type::write_comment_inline_c(const char *pre)
1051 {
1052   if (comment() && *comment()) {
1053     const char *s = comment();
1054     if (strchr(s, '\n')==0L) {
1055       // single line comment
1056       if (pre) write_c("%s", pre);
1057       write_c("// %s\n", s);
1058       if (!pre) write_c("%s  ", indent());
1059     } else {
1060       write_c("%s/*\n", pre?pre:"");
1061       if (pre) write_c("%s ", pre); else write_c("%s   ", indent());
1062       while(*s) {
1063         if (*s=='\n') {
1064           if (s[1]) {
1065             if (pre) write_c("\n%s ", pre); else write_c("\n%s   ", indent());
1066           }
1067         } else {
1068           write_c("%c", *s); // FIXME this is much too slow!
1069         }
1070         s++;
1071       }
1072       if (pre) write_c("\n%s */\n", pre); else write_c("\n%s   */\n", indent());
1073       if (!pre) write_c("%s  ", indent());
1074     }
1075   }
1076 }
1077 
1078 /**
1079   Make sure that the given item is visible in the browser by opening
1080   all parent groups and moving the item into the visible space.
1081 */
reveal_in_browser(Fl_Type * t)1082 void reveal_in_browser(Fl_Type *t) {
1083   Fl_Type *p = t->parent;
1084   if (p) {
1085     for (;;) {
1086       if (!p->open_)
1087         p->open_ = 1;
1088       if (!p->parent) break;
1089       p = p->parent;
1090     }
1091     fixvisible(p);
1092   }
1093   widget_browser->display(t);
1094   redraw_browser();
1095 }
1096 
1097 /**
1098   Build widgets and dataset needed in live mode.
1099   \return a widget pointer that the live mode initiator can 'show()'
1100   \see leave_live_mode()
1101 */
enter_live_mode(int)1102 Fl_Widget *Fl_Type::enter_live_mode(int) {
1103   return 0L;
1104 }
1105 
1106 /**
1107   Release all resources created when entering live mode.
1108   \see enter_live_mode()
1109 */
leave_live_mode()1110 void Fl_Type::leave_live_mode() {
1111 }
1112 
1113 /**
1114   Copy all needed properties for this type into the live object.
1115 */
copy_properties()1116 void Fl_Type::copy_properties() {
1117 }
1118 
1119 /**
1120   Check whether callback \p cbname is declared anywhere else by the user.
1121 
1122   \b Warning: this just checks that the name is declared somewhere,
1123   but it should probably also check that the name corresponds to a
1124   plain function or a member function within the same class and that
1125   the parameter types match.
1126  */
user_defined(const char * cbname) const1127 int Fl_Type::user_defined(const char* cbname) const {
1128   for (Fl_Type* p = Fl_Type::first; p ; p = p->next)
1129     if (strcmp(p->type_name(), "Function") == 0 && p->name() != 0)
1130       if (strncmp(p->name(), cbname, strlen(cbname)) == 0)
1131         if (p->name()[strlen(cbname)] == '(')
1132           return 1;
1133   return 0;
1134 }
1135 
1136 
1137 //
1138 // End of "$Id$".
1139 //
1140