fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_Window_Type.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_Window_Type.cxx 8089 2010-12-20 22:19:24Z matt $"
00003 //
00004 // Window type code for the Fast Light Tool Kit (FLTK).
00005 //
00006 // The widget describing an Fl_Window.  This is also all the code
00007 // for interacting with the overlay, which allows the user to
00008 // select, move, and resize the children widgets.
00009 //
00010 // Copyright 1998-2010 by Bill Spitzak and others.
00011 //
00012 // This library is free software; you can redistribute it and/or
00013 // modify it under the terms of the GNU Library General Public
00014 // License as published by the Free Software Foundation; either
00015 // version 2 of the License, or (at your option) any later version.
00016 //
00017 // This library is distributed in the hope that it will be useful,
00018 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020 // Library General Public License for more details.
00021 //
00022 // You should have received a copy of the GNU Library General Public
00023 // License along with this library; if not, write to the Free Software
00024 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00025 // USA.
00026 //
00027 // Please report all bugs and problems on the following page:
00028 //
00029 //     http://www.fltk.org/str.php
00030 //
00031 
00032 #include <FL/Fl.H>
00033 #include <FL/Fl_Overlay_Window.H>
00034 #include <FL/fl_message.H>
00035 #include <FL/fl_draw.H>
00036 #include <FL/x.H>
00037 #include <FL/Fl_Menu_Item.H>
00038 #include <FL/Fl_Round_Button.H>
00039 #include "Fl_Widget_Type.h"
00040 #include "undo.h"
00041 #include <math.h>
00042 #include <stdlib.h>
00043 #include "alignment_panel.h"
00044 #include <stdio.h>
00045 
00046 extern int gridx;
00047 extern int gridy;
00048 extern int snap;
00049 extern int show_guides;
00050 
00051 int include_H_from_C = 1;
00052 int use_FL_COMMAND = 0;
00053 extern int i18n_type;
00054 extern const char* i18n_include;
00055 extern const char* i18n_function;
00056 extern const char* i18n_file;
00057 extern const char* i18n_set;
00058 
00059 extern Fl_Preferences   fluid_prefs;
00060 
00061 inline int fl_min(int a, int b) { return (a < b ? a : b); } 
00062 
00063 #include "widget_panel.h"
00064 
00065 // Update the XYWH values in the widget panel...
00066 static void update_xywh() {
00067   if (current_widget && current_widget->is_widget()) {
00068     widget_x_input->value(((Fl_Widget_Type *)current_widget)->o->x());
00069     widget_y_input->value(((Fl_Widget_Type *)current_widget)->o->y());
00070     widget_w_input->value(((Fl_Widget_Type *)current_widget)->o->w());
00071     widget_h_input->value(((Fl_Widget_Type *)current_widget)->o->h());
00072   }
00073 }
00074 
00075 void guides_cb(Fl_Check_Button *i, long) {
00076   show_guides = i->value();
00077   fluid_prefs.set("show_guides", show_guides);
00078 
00079   for (Fl_Type *p = Fl_Type::first; p; p = p->next) {
00080     if (p->is_window()) {
00081       Fl_Window_Type *w = (Fl_Window_Type *)p;
00082       ((Fl_Overlay_Window *)(w->o))->redraw_overlay();
00083     }
00084   }
00085 }
00086 
00087 void grid_cb(Fl_Int_Input *i, long v) {
00088   int n = atoi(i->value());
00089   if (n < 0) n = 0;
00090   switch (v) {
00091     case 1:
00092       gridx = n;
00093       fluid_prefs.set("gridx", n);
00094       break;
00095     case 2:
00096       gridy = n;
00097       fluid_prefs.set("gridy", n);
00098       break;
00099     case 3:
00100       snap = n;
00101       fluid_prefs.set("snap", n);
00102       break;
00103   }
00104 
00105   // Next go through all of the windows in the project and set the
00106   // stepping for resizes...
00107   Fl_Type *p;
00108   Fl_Window_Type *w;
00109 
00110   for (p = Fl_Type::first; p; p = p->next) {
00111     if (p->is_window()) {
00112       w = (Fl_Window_Type *)p;
00113       ((Fl_Window *)(w->o))->size_range(gridx, gridy,
00114                                         Fl::w(), Fl::h(),
00115                                         gridx, gridy, 0);
00116     }
00117   }
00118 }
00119 
00120 // Set default widget sizes...
00121 void default_widget_size_cb(Fl_Round_Button *b, long size) {
00122   // Update the "normal" text size of new widgets...
00123   b->setonly();
00124   Fl_Widget_Type::default_size = size;
00125   fluid_prefs.set("widget_size", Fl_Widget_Type::default_size);
00126 }
00127 
00128 
00129 void i18n_type_cb(Fl_Choice *c, void *) {
00130   undo_checkpoint();
00131 
00132   switch (i18n_type = c->value()) {
00133   case 0 : /* None */
00134       i18n_include_input->hide();
00135       i18n_file_input->hide();
00136       i18n_set_input->hide();
00137       i18n_function_input->hide();
00138       break;
00139   case 1 : /* GNU gettext */
00140       i18n_include_input->value("<libintl.h>");
00141       i18n_include = i18n_include_input->value();
00142       i18n_function_input->value("gettext");
00143       i18n_function = i18n_function_input->value();
00144       i18n_include_input->show();
00145       i18n_file_input->hide();
00146       i18n_set_input->hide();
00147       i18n_function_input->show();
00148       break;
00149   case 2 : /* POSIX cat */
00150       i18n_include_input->value("<nl_types.h>");
00151       i18n_file_input->value("");
00152       i18n_file = i18n_file_input->value();
00153       i18n_set_input->value("1");
00154       i18n_set = i18n_set_input->value();
00155       i18n_include_input->show();
00156       i18n_include = i18n_include_input->value();
00157       i18n_file_input->show();
00158       i18n_set_input->show();
00159       i18n_function_input->hide();
00160       break;
00161   }
00162 
00163   set_modflag(1);
00164 }
00165 
00166 void i18n_text_cb(Fl_Input *i, void *) {
00167   undo_checkpoint();
00168   
00169   if (i == i18n_function_input)
00170     i18n_function = i->value();
00171   else if (i == i18n_file_input)
00172     i18n_file = i->value();
00173   else if (i == i18n_include_input)
00174     i18n_include = i->value();
00175   
00176   set_modflag(1);
00177 }
00178 
00179 void i18n_int_cb(Fl_Int_Input *i, void *) {
00180   undo_checkpoint();
00181   
00182   if (i == i18n_set_input)
00183     i18n_set = i->value();
00184   
00185   set_modflag(1);
00186 }
00187 
00188 extern const char* header_file_name;
00189 extern const char* code_file_name;
00190 
00191 void show_project_cb(Fl_Widget *, void *) {
00192   if(project_window==0) make_project_window();
00193   include_H_from_C_button->value(include_H_from_C);
00194   use_FL_COMMAND_button->value(use_FL_COMMAND);
00195   header_file_input->value(header_file_name);
00196   code_file_input->value(code_file_name);
00197   i18n_type_chooser->value(i18n_type);
00198   i18n_function_input->value(i18n_function);
00199   i18n_file_input->value(i18n_file);
00200   i18n_set_input->value(i18n_set);
00201   i18n_include_input->value(i18n_include);
00202   switch (i18n_type) {
00203   case 0 : /* None */
00204       i18n_include_input->hide();
00205       i18n_file_input->hide();
00206       i18n_set_input->hide();
00207       i18n_function_input->hide();
00208       break;
00209   case 1 : /* GNU gettext */
00210       i18n_include_input->show();
00211       i18n_file_input->hide();
00212       i18n_set_input->hide();
00213       i18n_function_input->show();
00214       break;
00215   case 2 : /* POSIX cat */
00216       i18n_include_input->show();
00217       i18n_file_input->show();
00218       i18n_set_input->show();
00219       i18n_function_input->hide();
00220       break;
00221   }
00222   project_window->hotspot(project_window);
00223   project_window->show();
00224 }
00225 
00226 void show_grid_cb(Fl_Widget *, void *) {
00227   char buf[128];
00228   sprintf(buf,"%d",gridx); horizontal_input->value(buf);
00229   sprintf(buf,"%d",gridy); vertical_input->value(buf);
00230   sprintf(buf,"%d",snap); snap_input->value(buf);
00231   guides_toggle->value(show_guides);
00232   int s = Fl_Widget_Type::default_size;
00233   if (s<=8) def_widget_size[0]->setonly();
00234   else if (s<=11) def_widget_size[1]->setonly();
00235   else if (s<=14) def_widget_size[2]->setonly();
00236   else if (s<=18) def_widget_size[3]->setonly();
00237   else if (s<=24) def_widget_size[4]->setonly();
00238   else if (s<=32) def_widget_size[5]->setonly();
00239   grid_window->hotspot(grid_window);
00240   grid_window->show();
00241 }
00242 
00243 void show_settings_cb(Fl_Widget *, void *) {
00244   settings_window->hotspot(settings_window);
00245   settings_window->show();
00246 }
00247 
00248 void show_global_settings_cb(Fl_Widget *, void *) {
00249   global_settings_window->hotspot(global_settings_window);
00250   show_global_settings_window();
00251 }
00252 
00253 void header_input_cb(Fl_Input* i, void*) {
00254   if (header_file_name && strcmp(header_file_name, i->value()))
00255     set_modflag(1);
00256   header_file_name = i->value();
00257 }
00258 void code_input_cb(Fl_Input* i, void*) {
00259   if (code_file_name && strcmp(code_file_name, i->value()))
00260     set_modflag(1);
00261   code_file_name = i->value();
00262 }
00263 
00264 void include_H_from_C_button_cb(Fl_Check_Button* b, void*) {
00265   if (include_H_from_C != b->value()) {
00266     set_modflag(1);
00267     include_H_from_C = b->value();
00268   }
00269 }
00270 
00271 void use_FL_COMMAND_button_cb(Fl_Check_Button* b, void*) {
00272   if (use_FL_COMMAND != b->value()) {
00273     set_modflag(1);
00274     use_FL_COMMAND = b->value();
00275   }
00276 }
00277 
00279 
00280 Fl_Menu_Item window_type_menu[] = {
00281   {"Single",0,0,(void*)FL_WINDOW},
00282   {"Double",0,0,(void*)(FL_WINDOW+1)},
00283   {0}};
00284 
00285 static int overlays_invisible;
00286 
00287 // The following Fl_Widget is used to simulate the windows.  It has
00288 // an overlay for the fluid ui, and special-cases the FL_NO_BOX.
00289 
00290 class Overlay_Window : public Fl_Overlay_Window {
00291   void draw();
00292   void draw_overlay();
00293 public:
00294   Fl_Window_Type *window;
00295   int handle(int);
00296   Overlay_Window(int W,int H) : Fl_Overlay_Window(W,H) {Fl_Group::current(0);}
00297   void resize(int,int,int,int);
00298   uchar *read_image(int &ww, int &hh);
00299 };
00300 void Overlay_Window::draw() {
00301   const int CHECKSIZE = 8;
00302   // see if box is clear or a frame or rounded:
00303   if ((damage()&FL_DAMAGE_ALL) &&
00304       (!box() || (box()>=4&&!(box()&2)) || box()>=_FL_ROUNDED_BOX)) {
00305     // if so, draw checkerboard so user can see what areas are clear:
00306     for (int Y = 0; Y < h(); Y += CHECKSIZE) 
00307       for (int X = 0; X < w(); X += CHECKSIZE) {
00308         fl_color(((Y/(2*CHECKSIZE))&1) != ((X/(2*CHECKSIZE))&1) ?
00309                  FL_WHITE : FL_BLACK);
00310         fl_rectf(X,Y,CHECKSIZE,CHECKSIZE);
00311       }
00312   }
00313   Fl_Overlay_Window::draw();
00314 }
00315 
00316 extern Fl_Window *main_window;
00317 
00318 // Read an image of the overlay window
00319 uchar *Overlay_Window::read_image(int &ww, int &hh) {
00320   // Create an off-screen buffer for the window...
00321   //main_window->make_current();
00322   make_current();
00323 
00324   ww = w();
00325   hh = h();
00326 
00327   Fl_Offscreen offscreen = fl_create_offscreen(ww, hh);
00328   uchar *pixels;
00329 
00330   // Redraw the window into the offscreen buffer...
00331   fl_begin_offscreen(offscreen);
00332 
00333   if (!shown()) image(Fl::scheme_bg_);
00334 
00335   redraw();
00336   draw();
00337 
00338   // Read the screen image...
00339   pixels = fl_read_image(0, 0, 0, ww, hh);
00340 
00341   fl_end_offscreen();
00342 
00343   // Cleanup and return...
00344   fl_delete_offscreen(offscreen);
00345   main_window->make_current();
00346   return pixels;
00347 }
00348 
00349 void Overlay_Window::draw_overlay() {
00350   window->draw_overlay();
00351 }
00352 int Overlay_Window::handle(int e) {
00353   int ret =  window->handle(e);
00354   if (ret==0) {
00355     switch (e) {
00356       case FL_SHOW:
00357       case FL_HIDE:
00358         ret = Fl_Overlay_Window::handle(e);
00359     }
00360   }
00361   return ret;
00362 }
00363 
00364 Fl_Type *Fl_Window_Type::make() {
00365   Fl_Type *p = Fl_Type::current;
00366   while (p && !p->is_code_block()) p = p->parent;
00367   if (!p) {
00368     fl_message("Please select a function");
00369     return 0;
00370   }
00371   Fl_Window_Type *myo = new Fl_Window_Type();
00372   if (!this->o) {// template widget
00373     this->o = new Fl_Window(100,100);
00374     Fl_Group::current(0);
00375   }
00376   // Set the size ranges for this window; in order to avoid opening the
00377   // X display we use an arbitrary maximum size...
00378   ((Fl_Window *)(this->o))->size_range(gridx, gridy,
00379                                        3072, 2048,
00380                                        gridx, gridy, 0);
00381   myo->factory = this;
00382   myo->drag = 0;
00383   myo->numselected = 0;
00384   Overlay_Window *w = new Overlay_Window(100,100);
00385   w->window = myo;
00386   myo->o = w;
00387   myo->add(p);
00388   myo->modal = 0;
00389   myo->non_modal = 0;
00390   return myo;
00391 }
00392 
00393 void Fl_Window_Type::add_child(Fl_Type* cc, Fl_Type* before) {
00394   if (!cc->is_widget()) return;
00395   Fl_Widget_Type* c = (Fl_Widget_Type*)cc;
00396   Fl_Widget* b = before ? ((Fl_Widget_Type*)before)->o : 0;
00397   ((Fl_Window*)o)->insert(*(c->o), b);
00398   o->redraw();
00399 }
00400 
00401 void Fl_Window_Type::remove_child(Fl_Type* cc) {
00402   Fl_Widget_Type* c = (Fl_Widget_Type*)cc;
00403   ((Fl_Window*)o)->remove(c->o);
00404   o->redraw();
00405 }
00406 
00407 void Fl_Window_Type::move_child(Fl_Type* cc, Fl_Type* before) {
00408   Fl_Widget_Type* c = (Fl_Widget_Type*)cc;
00409   ((Fl_Window*)o)->remove(c->o);
00410   Fl_Widget* b = before ? ((Fl_Widget_Type*)before)->o : 0;
00411   ((Fl_Window*)o)->insert(*(c->o), b);
00412   o->redraw();
00413 }
00414 
00416 
00417 // Double-click on window widget shows the window, or if already shown,
00418 // it shows the control panel.
00419 void Fl_Window_Type::open() {
00420   Overlay_Window *w = (Overlay_Window *)o;
00421   if (w->shown()) {
00422     w->show();
00423     Fl_Widget_Type::open();
00424   } else {
00425     Fl_Widget *p = w->resizable();
00426     if (!p) w->resizable(w);
00427     w->show();
00428     w->resizable(p);
00429   }
00430 
00431   w->image(Fl::scheme_bg_);
00432   w->size_range(gridx, gridy, Fl::w(), Fl::h(), gridx, gridy, 0);
00433 }
00434 
00435 // Read an image of the window
00436 uchar *Fl_Window_Type::read_image(int &ww, int &hh) {
00437   Overlay_Window *w = (Overlay_Window *)o;
00438 
00439   // Read the screen image...
00440   return (w->read_image(ww, hh));
00441 }
00442 
00443 
00444 // control panel items:
00445 
00446 void modal_cb(Fl_Light_Button* i, void* v) {
00447   if (v == LOAD) {
00448     if (!current_widget->is_window()) {i->hide(); return;}
00449     i->show();
00450     i->value(((Fl_Window_Type *)current_widget)->modal);
00451   } else {
00452     ((Fl_Window_Type *)current_widget)->modal = i->value();
00453     set_modflag(1);
00454   }
00455 }
00456 
00457 void non_modal_cb(Fl_Light_Button* i, void* v) {
00458   if (v == LOAD) {
00459     if (!current_widget->is_window()) {i->hide(); return;}
00460     i->show();
00461     i->value(((Fl_Window_Type *)current_widget)->non_modal);
00462   } else {
00463     ((Fl_Window_Type *)current_widget)->non_modal = i->value();
00464     set_modflag(1);
00465   }
00466 }
00467 
00468 void border_cb(Fl_Light_Button* i, void* v) {
00469   if (v == LOAD) {
00470     if (!current_widget->is_window()) {i->hide(); return;}
00471     i->show();
00472     i->value(((Fl_Window*)(current_widget->o))->border());
00473   } else {
00474     ((Fl_Window*)(current_widget->o))->border(i->value());
00475     set_modflag(1);
00476   }
00477 }
00478 
00479 void xclass_cb(Fl_Input* i, void* v) {
00480   if (v == LOAD) {
00481     if (!current_widget->is_window()) {
00482       i->hide(); 
00483       i->parent()->hide(); // hides the "X Class:" label as well
00484       return;
00485     }
00486     i->show();
00487     i->parent()->show();
00488     i->value(((Fl_Widget_Type *)current_widget)->xclass);
00489   } else {
00490     int mod = 0;
00491     for (Fl_Type *o = Fl_Type::first; o; o = o->next) {
00492       if (o->selected && o->is_widget()) {
00493         mod = 1;
00494         Fl_Widget_Type* w = (Fl_Widget_Type*)o;
00495         if (w->is_window() || w->is_button())
00496           storestring(i->value(),w->xclass);
00497         if (w->is_window()) ((Fl_Window*)(w->o))->xclass(w->xclass);
00498         else if (w->is_menu_item()) w->redraw();
00499       }
00500     }
00501     if (mod) set_modflag(1);
00502   }
00503 }
00504 
00506 
00507 void Fl_Window_Type::setlabel(const char *n) {
00508   if (o) ((Fl_Window *)o)->label(n);
00509 }
00510 
00511 // make() is called on this widget when user picks window off New menu:
00512 Fl_Window_Type Fl_Window_type;
00513 
00514 // Resize from window manager...
00515 void Overlay_Window::resize(int X,int Y,int W,int H) {
00516   Fl_Widget* t = resizable(); resizable(0);
00517 
00518   // do not set the mod flag if the window was not resized. In FLUID, all
00519   // windows are opened without a given x/y position, so modifying x/y
00520   // should not mark the project as dirty
00521   if (W!=w() || H!=h())
00522     set_modflag(1);
00523 
00524   Fl_Overlay_Window::resize(X,Y,W,H);
00525   resizable(t);
00526   update_xywh();
00527 }
00528 
00529 // calculate actual move by moving mouse position (mx,my) to
00530 // nearest multiple of gridsize, and snap to original position
00531 void Fl_Window_Type::newdx() {
00532   int mydx, mydy;
00533   if (Fl::event_state(FL_ALT) || !snap) {
00534     mydx = mx-x1;
00535     mydy = my-y1;
00536 
00537     if (abs(mydx) < 2 && abs(mydy) < 2) mydx = mydy = 0;
00538   } else {
00539     int dx0 = mx-x1;
00540     int ix = (drag&RIGHT) ? br : bx;
00541     mydx = gridx ? ((ix+dx0+gridx/2)/gridx)*gridx - ix : dx0;
00542     if (dx0 > snap) {
00543       if (mydx < 0) mydx = 0;
00544     } else if (dx0 < -snap) {
00545       if (mydx > 0) mydx = 0;
00546     } else 
00547       mydx = 0;
00548     int dy0 = my-y1;
00549     int iy = (drag&BOTTOM) ? by : bt;
00550     mydy = gridy ? ((iy+dy0+gridy/2)/gridy)*gridy - iy : dy0;
00551     if (dy0 > snap) {
00552       if (mydy < 0) mydy = 0;
00553     } else if (dy0 < -snap) {
00554       if (mydy > 0) mydy = 0;
00555     } else 
00556       mydy = 0;
00557   }
00558 
00559   if (!(drag & (DRAG | BOX | LEFT | RIGHT))) {
00560     mydx = 0;
00561     dx = 0;
00562   }
00563 
00564   if (!(drag & (DRAG | BOX | TOP | BOTTOM))) {
00565     mydy = 0;
00566     dy = 0;
00567   }
00568 
00569   if (dx != mydx || dy != mydy) {
00570     dx = mydx; dy = mydy;
00571     ((Overlay_Window *)o)->redraw_overlay();
00572   }
00573 }
00574 
00575 // Move a widget according to dx and dy calculated above
00576 void Fl_Window_Type::newposition(Fl_Widget_Type *myo,int &X,int &Y,int &R,int &T) {
00577   X = myo->o->x();
00578   Y = myo->o->y();
00579   R = X+myo->o->w();
00580   T = Y+myo->o->h();
00581   if (!drag) return;
00582   if (drag&DRAG) {
00583     X += dx;
00584     Y += dy;
00585     R += dx;
00586     T += dy;
00587   } else {
00588     if (drag&LEFT) {
00589       if (X==bx) {
00590         X += dx; 
00591       } else {
00592         if (X<bx+dx) X = bx+dx;
00593       }
00594     }
00595     if (drag&TOP) {
00596       if (Y==by) {
00597         Y += dy;
00598       } else {
00599         if (Y<by+dy) Y = by+dy;
00600       }
00601     }
00602     if (drag&RIGHT) {
00603       if (R==br) {
00604         R += dx; 
00605       } else {
00606         if (R>br+dx) R = br+dx;
00607       }
00608     }
00609     if (drag&BOTTOM) {
00610       if (T==bt) {
00611         T += dy; 
00612       } else {
00613         if (T>bt+dx) T = bt+dx;
00614       }
00615     }
00616   }
00617   if (R<X) {int n = X; X = R; R = n;}
00618   if (T<Y) {int n = Y; Y = T; T = n;}
00619 }
00620 
00621 // draw a vertical arrow pointing toward y2
00622 static void draw_v_arrow(int x, int y1, int y2) {
00623   int dy = (y1>y2) ? -1 : 1 ;
00624   fl_yxline(x, y1, y2);
00625   fl_xyline(x-4, y2, x+4);
00626   fl_line(x-2, y2-dy*5, x, y2-dy);
00627   fl_line(x+2, y2-dy*5, x, y2-dy);
00628 }
00629 
00630 static void draw_h_arrow(int x1, int y, int x2) {
00631   int dx = (x1>x2) ? -1 : 1 ;
00632   fl_xyline(x1, y, x2);
00633   fl_yxline(x2, y-4, y+4);
00634   fl_line(x2-dx*5, y-2, x2-dx, y);
00635   fl_line(x2-dx*5, y+2, x2-dx, y);
00636 }
00637 
00638 static void draw_top_brace(const Fl_Widget *w) {
00639   fl_yxline(w->x(), w->y()-2, w->y()+6);
00640   fl_yxline(w->x()+w->w()-1, w->y()-2, w->y()+6);
00641   fl_xyline(w->x()-2, w->y(), w->x()+w->w()+1);
00642 }
00643 
00644 static void draw_left_brace(const Fl_Widget *w) {
00645   fl_xyline(w->x()-2, w->y(), w->x()+6);
00646   fl_xyline(w->x()-2, w->y()+w->h()-1, w->x()+6);
00647   fl_yxline(w->x(), w->y()-2, w->y()+w->h()+1);
00648 }
00649 
00650 static void draw_right_brace(const Fl_Widget *w) {
00651   int xx = w->x() + w->w() - 1;
00652   fl_xyline(xx-6, w->y(), xx+2);
00653   fl_xyline(xx-6, w->y()+w->h()-1, xx+2);
00654   fl_yxline(xx, w->y()-2, w->y()+w->h()+1);
00655 }
00656 
00657 static void draw_bottom_brace(const Fl_Widget *w) {
00658   int yy = w->y() + w->h() - 1;
00659   fl_yxline(w->x(), yy-6, yy+2);
00660   fl_yxline(w->x()+w->w()-1, yy-6, yy+2);
00661   fl_xyline(w->x()-2, yy, w->x()+w->w()+1);
00662 }
00663 
00664 static void draw_height(int x, int y, int b, Fl_Align a) {
00665   char buf[16];
00666   int h = b - y;
00667   sprintf(buf, "%d", h);
00668   fl_font(FL_HELVETICA, 9);
00669   int lw = (int)fl_width(buf);
00670   int lx;
00671 
00672   b --;
00673   if (h < 30) {
00674     // Move height to the side...
00675     if (a == FL_ALIGN_LEFT) lx = x - lw - 2;
00676     else lx = x + 2;
00677 
00678     fl_yxline(x, y, b);
00679   } else {
00680     // Put height inside the arrows...
00681     lx = x - lw / 2;
00682 
00683     fl_yxline(x, y, y + (h - 11) / 2);
00684     fl_yxline(x, y + (h + 11) / 2, b);
00685   }
00686 
00687   // Draw the height...
00688   fl_draw(buf, lx, y + (h + 9) / 2);
00689 
00690   // Draw the arrowheads...
00691   fl_line(x-2, y+5, x, y+1, x+2, y+5);
00692   fl_line(x-2, b-5, x, b-1, x+2, b-5);
00693 
00694   // Draw the end lines...
00695   fl_xyline(x - 4, y, x + 4);
00696   fl_xyline(x - 4, b, x + 4);
00697 }
00698 
00699 static void draw_width(int x, int y, int r, Fl_Align a) {
00700   char buf[16];
00701   int w = r-x;
00702   sprintf(buf, "%d", w);
00703   fl_font(FL_HELVETICA, 9);
00704   int lw = (int)fl_width(buf);
00705   int ly = y + 4;
00706 
00707   r --;
00708 
00709   if (lw > (w - 20)) {
00710     // Move width above/below the arrows...
00711     if (a == FL_ALIGN_TOP) ly -= 10;
00712     else ly += 10;
00713 
00714     fl_xyline(x, y, r);
00715   } else {
00716     // Put width inside the arrows...
00717     fl_xyline(x, y, x + (w - lw - 2) / 2);
00718     fl_xyline(x + (w + lw + 2) / 2, y, r);
00719   }
00720 
00721   // Draw the width...
00722   fl_draw(buf, x + (w - lw) / 2, ly);
00723 
00724   // Draw the arrowheads...
00725   fl_line(x+5, y-2, x+1, y, x+5, y+2);
00726   fl_line(r-5, y-2, r-1, y, r-5, y+2);
00727 
00728   // Draw the end lines...
00729   fl_yxline(x, y - 4, y + 4);
00730   fl_yxline(r, y - 4, y + 4);
00731 }
00732 
00733 void Fl_Window_Type::draw_overlay() {
00734   if (recalc) {
00735     bx = o->w(); by = o->h(); br = 0; bt = 0;
00736     numselected = 0;
00737     for (Fl_Type *q=next; q && q->level>level; q=q->next)
00738       if (q->selected && q->is_widget() && !q->is_menu_item()) {
00739         numselected++;
00740         Fl_Widget_Type* myo = (Fl_Widget_Type*)q;
00741         if (myo->o->x() < bx) bx = myo->o->x();
00742         if (myo->o->y() < by) by = myo->o->y();
00743         if (myo->o->x()+myo->o->w() > br) br = myo->o->x()+myo->o->w();
00744         if (myo->o->y()+myo->o->h() > bt) bt = myo->o->y()+myo->o->h();
00745       }
00746     recalc = 0;
00747     sx = bx; sy = by; sr = br; st = bt;
00748   }
00749   fl_color(FL_RED);
00750   if (drag==BOX && (x1 != mx || y1 != my)) {
00751     int x = x1; int r = mx; if (x > r) {x = mx; r = x1;}
00752     int y = y1; int b = my; if (y > b) {y = my; b = y1;}
00753     fl_rect(x,y,r-x,b-y);
00754   }
00755   if (overlays_invisible && !drag) return;
00756   if (selected) fl_rect(0,0,o->w(),o->h());
00757   if (!numselected) return;
00758   int mybx,myby,mybr,mybt;
00759   int mysx,mysy,mysr,myst;
00760   mybx = mysx = o->w(); myby = mysy = o->h(); mybr = mysr = 0; mybt = myst = 0;
00761   Fl_Type *selection = 0L; // used to store the one selected widget (if n==1)
00762   for (Fl_Type *q=next; q && q->level>level; q = q->next)
00763     if (q->selected && q->is_widget() && !q->is_menu_item()) {
00764       selection = q;
00765       Fl_Widget_Type* myo = (Fl_Widget_Type*)q;
00766       int x,y,r,t;
00767       newposition(myo,x,y,r,t);
00768       if (!show_guides || !drag || numselected != 1) fl_rect(x,y,r-x,t-y);
00769       if (x < mysx) mysx = x;
00770       if (y < mysy) mysy = y;
00771       if (r > mysr) mysr = r;
00772       if (t > myst) myst = t;
00773       if (!(myo->o->align() & FL_ALIGN_INSIDE)) {
00774         // Adjust left/right/top/bottom for top/bottom labels...
00775         int ww, hh;
00776         ww = (myo->o->align() & FL_ALIGN_WRAP) ? myo->o->w() : 0;
00777         hh = myo->o->labelsize();
00778         myo->o->measure_label(ww, hh);
00779         if (myo->o->align() & FL_ALIGN_TOP) y -= hh;
00780         else if (myo->o->align() & FL_ALIGN_BOTTOM) t += hh;
00781         else if (myo->o->align() & FL_ALIGN_LEFT) x -= ww + 4;
00782         else if (myo->o->align() & FL_ALIGN_RIGHT) r += ww + 4;
00783       }
00784       if (x < mybx) mybx = x;
00785       if (y < myby) myby = y;
00786       if (r > mybr) mybr = r;
00787       if (t > mybt) mybt = t;
00788     }
00789   if (selected) return;
00790 
00791   if (show_guides && drag) {
00792     // draw overlays for UI Guideline distances
00793     // - check for distance to the window edge
00794     //    * FLTK suggests 10 pixels from the edge
00795     int d;
00796     int xsp, ysp;
00797     int mybx_bak = mybx, myby_bak = myby, mybr_bak = mybr, mybt_bak = mybt;
00798     Fl_Widget_Type *mysel = (Fl_Widget_Type *)selection;
00799 
00800 
00801     ideal_spacing(xsp, ysp);
00802 
00803     if (drag) {
00804       // Check top spacing...
00805       if (abs(d = myby - ysp) < 3) {
00806         dy -= d;
00807         if (drag & DRAG) mybt -= d;
00808         myby -= d;
00809         draw_v_arrow(mybx+5, myby, 0);
00810       }
00811 
00812       // Check bottom spacing...
00813       if (abs(d = o->h() - mybt - ysp) < 3) {
00814         dy += d;
00815         if (drag & DRAG) myby += d;
00816         mybt += d;
00817         draw_v_arrow(mybx+5, mybt, o->h());
00818       }
00819 
00820       // Check left spacing...
00821       if (abs(d = mybx - xsp) < 3) {
00822         dx -= d;
00823         if (drag & DRAG) mybr -= d;
00824         mybx -= d;
00825         draw_h_arrow(mybx, myby+5, 0);
00826       }
00827 
00828       // Check right spacing...
00829       if (abs(d = o->w() - mybr - xsp) < 3) {
00830         dx += d;
00831         if (drag & DRAG) mybx += d;
00832         mybr += d;
00833         draw_h_arrow(mybr, myby+5, o->w());
00834       }
00835     }
00836 
00837     if (numselected==1 && selection && !(drag & DRAG)) {
00838       // Check ideal sizes
00839       int x,y,r,t;
00840       newposition(mysel,x,y,r,t);
00841       int w = r-x;
00842       int h = t-y;
00843       int iw = w, ih = h;
00844 
00845       mysel->ideal_size(iw, ih);
00846 
00847       if (drag & (TOP | BOTTOM)) {
00848         // Check height
00849         if (abs(d = ih - h) < 5) {
00850           // Resize height
00851           if (drag & TOP) {
00852             myby -= d;
00853             y -= d;
00854             dy -= d;
00855           } else {
00856             mybt += d;
00857             t += d;
00858             dy += d;
00859           }
00860         }
00861 
00862         // Draw height guide
00863         draw_height(x < 50 ? x+10 : x-10, y, t,
00864                     x < 50 ? FL_ALIGN_RIGHT : FL_ALIGN_LEFT);
00865       }
00866 
00867       if (drag & (LEFT | RIGHT)) {
00868         // Check width
00869         if (abs(d = iw - w) < 5) {
00870           // Resize width
00871           if (drag & LEFT) {
00872             mybx -= d;
00873             x -= d;
00874             dx -= d;
00875           } else {
00876             mybr += d;
00877             r += d;
00878             dx += d;
00879           }
00880         }
00881 
00882         // Draw width guide
00883         draw_width(x, y < 50 ? y+10 : y-10, r,
00884                    y < 50 ? FL_ALIGN_BOTTOM : FL_ALIGN_TOP);
00885       }
00886     }
00887 
00888     // Check spacing and alignment between individual widgets
00889     if (drag && selection->is_widget()) {
00890       for (Fl_Type *q=next; q && q->level>level; q = q->next)
00891         if (q != selection && q->is_widget()) {
00892           Fl_Widget_Type *qw = (Fl_Widget_Type*)q;
00893           // Only check visible widgets...
00894           if (!qw->o->visible_r()) continue;
00895 
00896           // Get bounding box of widget...
00897           int qx = qw->o->x();
00898           int qr = qw->o->x() + qw->o->w();
00899           int qy = qw->o->y();
00900           int qt = qw->o->y() + qw->o->h();
00901 
00902           if (!(qw->o->align() & FL_ALIGN_INSIDE)) {
00903             // Adjust top/bottom for top/bottom labels...
00904             int ww, hh;
00905             ww = qw->o->w();
00906             hh = qw->o->labelsize();
00907             qw->o->measure_label(ww, hh);
00908             if (qw->o->align() & FL_ALIGN_TOP) qy -= hh;
00909             if (qw->o->align() & FL_ALIGN_BOTTOM) qt += hh;
00910           }
00911 
00912           // Do horizontal alignment when the widget is within 25
00913           // pixels vertically...
00914           if (fl_min(abs(qy - mysel->o->y() - mysel->o->h()),
00915                      abs(mysel->o->y() - qt)) < 25) {
00916             // Align to left of other widget...
00917             if ((drag & (LEFT | DRAG)) && abs(d = mybx - qx) < 3) {
00918               dx += d;
00919               mybx += d;
00920               if (drag & DRAG) mybr += d;
00921 
00922               draw_left_brace(qw->o);
00923             }
00924 
00925             // Align to right of other widget...
00926             if ((drag & (RIGHT | DRAG)) &&
00927                 abs(d = qr - mybr) < 3) {
00928               dx += d;
00929               if (drag & DRAG) mybx += d;
00930               mybr += d;
00931 
00932               draw_right_brace(qw->o);
00933             }
00934           }
00935 
00936           // Align to top of other widget...
00937           if ((drag & (TOP | DRAG)) && abs(d = myby - qy) < 3) {
00938             dy += d;
00939             myby += d;
00940             if (drag & DRAG) mybt += d;
00941 
00942             draw_top_brace(qw->o);
00943           }
00944 
00945           // Align to bottom of other widget...
00946           if ((drag & (BOTTOM | DRAG)) && abs(d = qt - mybt) < 3) {
00947             dy += d;
00948             if (drag & DRAG) myby += d;
00949             mybt += d;
00950 
00951             draw_bottom_brace(qw->o);
00952           }
00953 
00954           // Check spacing between widgets
00955           if (mysel->is_group()) mysel->ideal_spacing(xsp, ysp);
00956           else qw->ideal_spacing(xsp, ysp);
00957 
00958           if ((qt)>=myby && qy<=mybt) {
00959             if (drag & (LEFT | DRAG)) {
00960               // Compare left of selected to left of current
00961               if (abs(d = qx - mybx - xsp) >= 3)
00962                 d = qx - mybx + xsp;
00963 
00964               if (abs(d) < 3) {
00965                 dx += d;
00966                 mybx += d;
00967                 if (drag & DRAG) mybr += d;
00968 
00969                 // Draw left arrow
00970                 draw_h_arrow(mybx, (myby+mybt)/2, qx);
00971               }
00972 
00973               // Compare left of selected to right of current
00974               if (abs(d = qr - mybx - xsp) >= 3)
00975                 d = qr - mybx + xsp;
00976 
00977               if (abs(d) < 3) {
00978                 dx += d;
00979                 mybx += d;
00980                 if (drag & DRAG) mybr += d;
00981 
00982                 // Draw left arrow
00983                 draw_h_arrow(mybx, (myby+mybt)/2, qr);
00984               }
00985             }
00986 
00987             if (drag & (RIGHT | DRAG)) {
00988               // Compare right of selected to left of current
00989               if (abs(d = qx - mybr - xsp) >= 3)
00990                 d = qx - mybr + xsp;
00991 
00992               if (abs(d) < 3) {
00993                 dx += d;
00994                 if (drag & DRAG) mybx += d;
00995                 mybr += d;
00996 
00997                 // Draw right arrow
00998                 draw_h_arrow(mybr, (myby+mybt)/2, qx);
00999               }
01000 
01001               // Compare right of selected to right of current
01002               if (abs(d = qr - mybr + xsp) >= 3)
01003                 d = qr - mybr - xsp;
01004 
01005               if (abs(d) < 3) {
01006                 dx += d;
01007                 if (drag & DRAG) mybx += d;
01008                 mybr += d;
01009 
01010                 // Draw right arrow
01011                 draw_h_arrow(mybr, (myby+mybt)/2, qr);
01012               }
01013             }
01014           }
01015 
01016           if (qr>=mybx && qx<=mybr) {
01017             // Compare top of selected to top of current
01018             if (drag & (TOP | DRAG)) {
01019               if (abs(d = qy - myby - ysp) >= 3)
01020                 d = qy - myby + ysp;
01021 
01022               if (abs(d) < 3) {
01023                 dy += d;
01024                 myby += d;
01025                 if (drag & DRAG) mybt += d;
01026 
01027                 // Draw up arrow...
01028                 draw_v_arrow((mybx+mybr)/2, myby, qy);
01029               }
01030 
01031               // Compare top of selected to bottom of current
01032               if (abs(d = qt - myby - ysp) >= 3)
01033                 d = qt - myby + ysp;
01034 
01035               if (abs(d) < 3) {
01036                 dy += d;
01037                 myby += d;
01038                 if (drag & DRAG) mybt += d;
01039 
01040                 // Draw up arrow...
01041                 draw_v_arrow((mybx+mybr)/2, myby, qt);
01042               }
01043             }
01044 
01045             // Compare bottom of selected to top of current
01046             if (drag & (BOTTOM | DRAG)) {
01047               if (abs(d = qy - mybt - ysp) >= 3)
01048                 d = qy - mybt + ysp;
01049 
01050               if (abs(d) < 3) {
01051                 dy += d;
01052                 if (drag & DRAG) myby += d;
01053                 mybt += d;
01054 
01055                 // Draw down arrow...
01056                 draw_v_arrow((mybx+mybr)/2, mybt, qy);
01057               }
01058 
01059               // Compare bottom of selected to bottom of current
01060               if (abs(d = qt - mybt - ysp) >= 3)
01061                 d = qt - mybt + ysp;
01062 
01063               if (abs(d) < 3) {
01064                 dy += d;
01065                 if (drag & DRAG) myby += d;
01066                 mybt += d;
01067 
01068                 // Draw down arrow...
01069                 draw_v_arrow((mybx+mybr)/2, mybt, qt);
01070               }
01071             }
01072           }
01073         }
01074     }
01075     mysx += mybx-mybx_bak; mysr += mybr-mybr_bak;
01076     mysy += myby-myby_bak; myst += mybt-mybt_bak;
01077   }
01078   // align the snapping selection box with the box we draw.
01079   sx = mysx; sy = mysy; sr = mysr; st = myst;
01080 
01081   // Draw selection box + resize handles...
01082   // draw box including all labels
01083   fl_line_style(FL_DOT);
01084   fl_rect(mybx,myby,mybr-mybx,mybt-myby);
01085   fl_line_style(FL_SOLID);
01086   // draw box excluding labels
01087   fl_rect(mysx,mysy,mysr-mysx,myst-mysy);
01088   fl_rectf(mysx,mysy,5,5);
01089   fl_rectf(mysr-5,mysy,5,5);
01090   fl_rectf(mysr-5,myst-5,5,5);
01091   fl_rectf(mysx,myst-5,5,5);
01092 }
01093 
01094 extern Fl_Menu_Item Main_Menu[];
01095 
01096 // Calculate new bounding box of selected widgets:
01097 void Fl_Window_Type::fix_overlay() {
01098   Main_Menu[40].label("Hide O&verlays");
01099   overlays_invisible = 0;
01100   recalc = 1;
01101   ((Overlay_Window *)(this->o))->redraw_overlay();
01102 }
01103 
01104 // check if we must redraw any parent of tabs/wizard type
01105 void check_redraw_corresponding_parent(Fl_Type *s) {
01106     Fl_Widget_Type * prev_parent = 0;
01107     if( !s || !s->selected || !s->is_widget()) return;
01108     for (Fl_Type *i=s; i && i->parent; i=i->parent) {
01109         if (i->is_group() && prev_parent && 
01110             (!strcmp(i->type_name(), "Fl_Tabs") || 
01111              !strcmp(i->type_name(), "Fl_Wizard"))) {
01112              ((Fl_Tabs*)((Fl_Widget_Type*)i)->o)->value(prev_parent->o);
01113              return;
01114         }
01115         if (i->is_group() && s->is_widget()) 
01116             prev_parent = (Fl_Widget_Type*)i;
01117     }
01118 }
01119  
01120 // do that for every window (when selected set changes):
01121 void redraw_overlays() {
01122   for (Fl_Type *o=Fl_Type::first; o; o=o->next)
01123     if (o->is_window()) ((Fl_Window_Type*)o)->fix_overlay();
01124 }
01125 
01126 void toggle_overlays(Fl_Widget *,void *) {
01127   overlays_invisible = !overlays_invisible;
01128 
01129   if (overlays_invisible) Main_Menu[40].label("Show O&verlays");
01130   else Main_Menu[40].label("Hide O&verlays");
01131 
01132   for (Fl_Type *o=Fl_Type::first; o; o=o->next)
01133     if (o->is_window()) {
01134       Fl_Widget_Type* w = (Fl_Widget_Type*)o;
01135       ((Overlay_Window*)(w->o))->redraw_overlay();
01136     }
01137 }
01138 
01139 extern void select(Fl_Type *,int);
01140 extern void select_only(Fl_Type *);
01141 extern void deselect();
01142 extern Fl_Type* in_this_only;
01143 extern void fix_group_size(Fl_Type *t);
01144 
01145 extern Fl_Menu_Item Main_Menu[];
01146 extern Fl_Menu_Item New_Menu[];
01147 
01148 // move the selected children according to current dx,dy,drag state:
01149 void Fl_Window_Type::moveallchildren()
01150 {
01151   undo_checkpoint();
01152   Fl_Type *i;
01153   for (i=next; i && i->level>level;) {
01154     if (i->selected && i->is_widget() && !i->is_menu_item()) {
01155       Fl_Widget_Type* myo = (Fl_Widget_Type*)i;
01156       int x,y,r,t;
01157       newposition(myo,x,y,r,t);
01158       myo->o->resize(x,y,r-x,t-y);
01159       // move all the children, whether selected or not:
01160       Fl_Type* p;
01161       for (p = myo->next; p && p->level>myo->level; p = p->next)
01162         if (p->is_widget() && !p->is_menu_item()) {
01163           Fl_Widget_Type* myo2 = (Fl_Widget_Type*)p;
01164           int X,Y,R,T;
01165           newposition(myo2,X,Y,R,T);
01166           myo2->o->resize(X,Y,R-X,T-Y);
01167         }
01168       i = p;
01169     } else {
01170       i = i->next;
01171     }
01172   }
01173   for (i=next; i && i->level>level; i=i->next) 
01174     fix_group_size(i);
01175   o->redraw();
01176   recalc = 1;
01177   ((Overlay_Window *)(this->o))->redraw_overlay();
01178   set_modflag(1);
01179   dx = dy = 0;
01180 
01181   update_xywh();
01182 }
01183 
01184 int Fl_Window_Type::handle(int event) {
01185   static Fl_Type* selection;
01186   switch (event) {
01187   case FL_PUSH:
01188     x1 = mx = Fl::event_x();
01189     y1 = my = Fl::event_y();
01190     drag = dx = dy = 0;
01191     // test for popup menu:
01192     if (Fl::event_button() >= 3) {
01193       in_this_only = this; // modifies how some menu items work.
01194       static const Fl_Menu_Item* myprev;
01195       const Fl_Menu_Item* m = New_Menu->popup(mx,my,"New",myprev);
01196       if (m && m->callback()) {myprev = m; m->do_callback(this->o);}
01197       in_this_only = 0;
01198       return 1;
01199     }
01200     // find the innermost item clicked on:
01201     selection = this;
01202     {for (Fl_Type* i=next; i && i->level>level; i=i->next)
01203       if (i->is_widget() && !i->is_menu_item()) {
01204       Fl_Widget_Type* myo = (Fl_Widget_Type*)i;
01205       for (Fl_Widget *o1 = myo->o; o1; o1 = o1->parent())
01206         if (!o1->visible()) goto CONTINUE2;
01207       if (Fl::event_inside(myo->o)) {
01208         selection = myo;
01209         if (Fl::event_clicks()==1)
01210           reveal_in_browser(myo);
01211       }
01212     CONTINUE2:;
01213     }}
01214     // see if user grabs edges of selected region:
01215     if (numselected && !(Fl::event_state(FL_SHIFT)) &&
01216         mx<=br+snap && mx>=bx-snap && my<=bt+snap && my>=by-snap) {
01217       int snap1 = snap>5 ? snap : 5;
01218       int w1 = (br-bx)/4; if (w1 > snap1) w1 = snap1;
01219       if (mx>=br-w1) drag |= RIGHT;
01220       else if (mx<bx+w1) drag |= LEFT;
01221       w1 = (bt-by)/4; if (w1 > snap1) w1 = snap1;
01222       if (my<=by+w1) drag |= TOP;
01223       else if (my>bt-w1) drag |= BOTTOM;
01224       if (!drag) drag = DRAG;
01225     }
01226     // do object-specific selection of other objects:
01227     {Fl_Type* t = selection->click_test(mx, my);
01228     if (t) {
01229       //if (t == selection) return 1; // indicates mouse eaten w/o change
01230       if (Fl::event_state(FL_SHIFT)) {
01231         Fl::event_is_click(0);
01232         select(t, !t->selected);
01233       } else {
01234         deselect();
01235         select(t, 1);
01236         if (t->is_menu_item()) t->open();
01237       }
01238       selection = t;
01239       drag = 0;
01240     } else {
01241       if (!drag) drag = BOX; // if all else fails, start a new selection region
01242     }}
01243     return 1;
01244 
01245   case FL_DRAG:
01246     if (!drag) return 0;
01247     mx = Fl::event_x();
01248     my = Fl::event_y();
01249     newdx();
01250     return 1;
01251 
01252   case FL_RELEASE:
01253     if (!drag) return 0;
01254     mx = Fl::event_x();
01255     my = Fl::event_y();
01256     if (drag != BOX && (dx || dy || !Fl::event_is_click())) {
01257       if (dx || dy) moveallchildren();
01258     } else if ((Fl::event_clicks() || Fl::event_state(FL_CTRL))) {
01259       Fl_Widget_Type::open();
01260     } else {
01261       if (mx<x1) {int t = x1; x1 = mx; mx = t;}
01262       if (my<y1) {int t = y1; y1 = my; my = t;}
01263       int n = 0;
01264       int toggle = Fl::event_state(FL_SHIFT);
01265       // clear selection on everything:
01266       if (!toggle) deselect(); else Fl::event_is_click(0);
01267       // select everything in box:
01268       for (Fl_Type*i=next; i&&i->level>level; i=i->next)
01269         if (i->is_widget() && !i->is_menu_item()) {
01270         Fl_Widget_Type* myo = (Fl_Widget_Type*)i;
01271         for (Fl_Widget *o1 = myo->o; o1; o1 = o1->parent())
01272           if (!o1->visible()) goto CONTINUE;
01273         if (Fl::event_inside(myo->o)) selection = myo;
01274         if (myo->o->x()>=x1 && myo->o->y()>y1 &&
01275             myo->o->x()+myo->o->w()<mx && myo->o->y()+myo->o->h()<my) {
01276           n++;
01277           select(myo, toggle ? !myo->selected : 1);
01278         }
01279       CONTINUE:;
01280       }
01281       // if nothing in box, select what was clicked on:
01282       if (!n) {
01283         select(selection, toggle ? !selection->selected : 1);
01284       }
01285     }
01286     drag = 0;
01287     ((Overlay_Window *)o)->redraw_overlay();
01288     return 1;
01289 
01290   case FL_KEYBOARD: {
01291 
01292     int backtab = 0;
01293     switch (Fl::event_key()) {
01294 
01295     case FL_Escape:
01296       ((Fl_Window*)o)->hide();
01297       return 1;
01298 
01299     case FL_Tab: {
01300       if (Fl::event_state(FL_SHIFT)) backtab = 1;
01301       // find current child:
01302       Fl_Type *i = Fl_Type::current;
01303       while (i && (!i->is_widget() || i->is_menu_item())) i = i->parent;
01304       if (!i) return 0;
01305       Fl_Type *p = i->parent;
01306       while (p && p != this) p = p->parent;
01307       if (!p || !p->is_widget()) {
01308         i = next; if (!i || i->level <= level) return 0;
01309       }
01310       p = i;
01311       for (;;) {
01312         i = backtab ? i->prev : i->next;
01313         if (!i || i->level <= level) {i = p; break;}
01314         if (i->is_widget() && !i->is_menu_item()) break;
01315       }
01316       deselect(); select(i,1);
01317       return 1;}
01318 
01319     case FL_Left:  dx = -1; dy = 0; goto ARROW;
01320     case FL_Right: dx = +1; dy = 0; goto ARROW;
01321     case FL_Up:    dx = 0; dy = -1; goto ARROW;
01322     case FL_Down:  dx = 0; dy = +1; goto ARROW;
01323     ARROW:
01324       // for some reason BOTTOM/TOP are swapped... should be fixed...
01325       drag = (Fl::event_state(FL_SHIFT)) ? (RIGHT|TOP) : DRAG;
01326       if (Fl::event_state(FL_CTRL)) {dx *= gridx; dy *= gridy;}
01327       moveallchildren();
01328       drag = 0;
01329       return 1;
01330 
01331     case 'o':
01332       toggle_overlays(0, 0);
01333       break;
01334 
01335     default:
01336       return 0;
01337     }}
01338 
01339   case FL_SHORTCUT: {
01340     in_this_only = this; // modifies how some menu items work.
01341     const Fl_Menu_Item* m = Main_Menu->test_shortcut();
01342     if (m && m->callback()) m->do_callback(this->o);
01343     in_this_only = 0;
01344     return (m != 0);}
01345 
01346   default:
01347     return 0;
01348   }
01349 }
01350 
01352 
01353 #include <stdio.h>
01354 #include "../src/flstring.h"
01355 
01356 void Fl_Window_Type::write_code1() {
01357   Fl_Widget_Type::write_code1();
01358 }
01359 
01360 void Fl_Window_Type::write_code2() {
01361   const char *var = is_class() ? "this" : name() ? name() : "o";
01362   write_extra_code();
01363   if (modal) write_c("%s%s->set_modal();\n", indent(), var);
01364   else if (non_modal) write_c("%s%s->set_non_modal();\n", indent(), var);
01365   if (!((Fl_Window*)o)->border()) {
01366     write_c("%s%s->clear_border();\n", indent(), var);
01367   }
01368   if (xclass) {
01369     write_c("%s%s->xclass(", indent(), var);
01370     write_cstring(xclass);
01371     write_c(");\n");
01372   }
01373   if (sr_max_w || sr_max_h) {
01374     write_c("%s%s->size_range(%d, %d, %d, %d);\n", indent(), var,
01375             sr_min_w, sr_min_h, sr_max_w, sr_max_h);
01376   } else if (sr_min_w || sr_min_h) {
01377     write_c("%s%s->size_range(%d, %d);\n", indent(), var, sr_min_w, sr_min_h);
01378   }
01379   write_c("%s%s->end();\n", indent(), var);
01380   if (((Fl_Window*)o)->resizable() == o)
01381     write_c("%s%s->resizable(%s);\n", indent(), var, var);
01382   write_block_close();
01383 }
01384 
01385 void Fl_Window_Type::write_properties() {
01386   Fl_Widget_Type::write_properties();
01387   if (modal) write_string("modal");
01388   else if (non_modal) write_string("non_modal");
01389   if (!((Fl_Window*)o)->border()) write_string("noborder");
01390   if (xclass) {write_string("xclass"); write_word(xclass);}
01391   if (sr_min_w || sr_min_h || sr_max_w || sr_max_h)
01392     write_string("size_range {%d %d %d %d}", sr_min_w, sr_min_h, sr_max_w, sr_max_h);
01393   if (o->visible()) write_string("visible");
01394 }
01395 
01396 extern int pasteoffset;
01397 void Fl_Window_Type::read_property(const char *c) {
01398   if (!strcmp(c,"modal")) {
01399     modal = 1;
01400   } else if (!strcmp(c,"non_modal")) {
01401     non_modal = 1;
01402   } else if (!strcmp(c, "visible")) {
01403     if (Fl::first_window()) open(); // only if we are using user interface
01404   } else if (!strcmp(c,"noborder")) {
01405     ((Fl_Window*)o)->border(0);
01406   } else if (!strcmp(c,"xclass")) {
01407     storestring(read_word(),xclass);
01408     ((Fl_Window*)o)->xclass(xclass);
01409   } else if (!strcmp(c,"size_range")) {
01410     int mw, mh, MW, MH;
01411     if (sscanf(read_word(),"%d %d %d %d",&mw,&mh,&MW,&MH) == 4) {
01412       sr_min_w = mw; sr_min_h = mh; sr_max_w = MW; sr_max_h = MH;
01413     }
01414   } else if (!strcmp(c,"xywh")) {
01415     Fl_Widget_Type::read_property(c);
01416     pasteoffset = 0; // make it not apply to contents
01417   } else {
01418     Fl_Widget_Type::read_property(c);
01419   }
01420 }
01421 
01422 int Fl_Window_Type::read_fdesign(const char* propname, const char* value) {
01423   int x;
01424   o->box(FL_NO_BOX); // because fdesign always puts an Fl_Box next
01425   if (!strcmp(propname,"Width")) {
01426     if (sscanf(value,"%d",&x) == 1) o->size(x,o->h());
01427   } else if (!strcmp(propname,"Height")) {
01428     if (sscanf(value,"%d",&x) == 1) o->size(o->w(),x);
01429   } else if (!strcmp(propname,"NumberofWidgets")) {
01430     return 1; // we can figure out count from file
01431   } else if (!strcmp(propname,"border")) {
01432     if (sscanf(value,"%d",&x) == 1) ((Fl_Window*)o)->border(x);
01433   } else if (!strcmp(propname,"title")) {
01434     label(value);
01435   } else {
01436     return Fl_Widget_Type::read_fdesign(propname,value);
01437   }
01438   return 1;
01439 }
01440 
01442 
01443 Fl_Widget_Class_Type Fl_Widget_Class_type;
01444 Fl_Widget_Class_Type *current_widget_class = 0;
01445 
01446 Fl_Type *Fl_Widget_Class_Type::make() {
01447   Fl_Type *p = Fl_Type::current;
01448   while (p && (!p->is_decl_block() || (p->is_widget() && p->is_class()))) p = p->parent;
01449   Fl_Widget_Class_Type *myo = new Fl_Widget_Class_Type();
01450   myo->name("UserInterface");
01451 
01452   if (!this->o) {// template widget
01453     this->o = new Fl_Window(100,100);
01454     Fl_Group::current(0);
01455   }
01456   // Set the size ranges for this window; in order to avoid opening the
01457   // X display we use an arbitrary maximum size...
01458   ((Fl_Window *)(this->o))->size_range(gridx, gridy,
01459                                        3072, 2048,
01460                                        gridx, gridy, 0);
01461   myo->factory = this;
01462   myo->drag = 0;
01463   myo->numselected = 0;
01464   Overlay_Window *w = new Overlay_Window(100,100);
01465   w->window = myo;
01466   myo->o = w;
01467   myo->add(p);
01468   myo->modal = 0;
01469   myo->non_modal = 0;
01470   myo->wc_relative = 0;
01471 
01472   return myo;
01473 }
01474 
01475 void Fl_Widget_Class_Type::write_properties() {
01476   Fl_Window_Type::write_properties();
01477   if (wc_relative) write_string("position_relative");
01478 }
01479 
01480 void Fl_Widget_Class_Type::read_property(const char *c) {
01481   if (!strcmp(c,"position_relative")) {
01482     wc_relative = 1;
01483   } else {
01484     Fl_Window_Type::read_property(c);
01485   }
01486 }
01487 
01488 void Fl_Widget_Class_Type::write_code1() {
01489 #if 0
01490   Fl_Widget_Type::write_code1();
01491 #endif // 0
01492 
01493   current_widget_class = this;
01494   write_public_state = 1;
01495 
01496   const char *c = subclass();
01497   if (!c) c = "Fl_Group";
01498 
01499   write_h("\nclass %s : public %s {\n", name(), c);
01500   if (strstr(c, "Window")) {
01501     write_h("  void _%s();\n", name());
01502     write_h("public:\n");
01503     write_h("  %s(int X, int Y, int W, int H, const char *L = 0);\n", name());
01504     write_h("  %s(int W, int H, const char *L = 0);\n", name());
01505     write_h("  %s();\n", name());
01506 
01507     // a constructor with all four dimensions plus label
01508     write_c("%s::%s(int X, int Y, int W, int H, const char *L)\n", name(), name());
01509     write_c("  : %s(X, Y, W, H, L) {\n", c);
01510     write_c("  _%s();\n", name());
01511     write_c("}\n\n");
01512 
01513     // a constructor with just the size and label. The window manager will position the window
01514     write_c("%s::%s(int W, int H, const char *L)\n", name(), name());
01515     write_c("  : %s(0, 0, W, H, L) {\n", c);
01516     write_c("  clear_flag(16);\n");
01517     write_c("  _%s();\n", name());
01518     write_c("}\n\n");
01519     
01520     // a constructor that takes size and label from the Fluid database
01521     write_c("%s::%s()\n", name(), name());
01522     write_c("  : %s(0, 0, %d, %d, ", c, o->w(), o->h());
01523     const char *cstr = label();
01524     if (cstr) write_cstring(cstr);
01525     else write_c("0");
01526     write_c(") {\n");
01527     write_c("  clear_flag(16);\n");
01528     write_c("  _%s();\n", name());
01529     write_c("}\n\n");
01530     
01531     write_c("void %s::_%s() {\n", name(), name());
01532 //    write_c("  %s *w = this;\n", name());
01533   } else {
01534     write_h("public:\n");
01535     write_h("  %s(int X, int Y, int W, int H, const char *L = 0);\n", name());
01536 
01537     write_c("%s::%s(int X, int Y, int W, int H, const char *L)\n", name(), name());
01538     if (wc_relative)
01539       write_c("  : %s(0, 0, W, H, L) {\n", c);
01540     else
01541       write_c("  : %s(X, Y, W, H, L) {\n", c);
01542   }
01543 
01544 //  write_c("  %s *o = this;\n", name());
01545 
01546   write_widget_code();
01547 }
01548 
01549 void Fl_Widget_Class_Type::write_code2() {
01550   write_extra_code();
01551   if (wc_relative) write_c("%sposition(X, Y);\n", indent());
01552   if (modal) write_c("%sset_modal();\n", indent());
01553   else if (non_modal) write_c("%sset_non_modal();\n", indent());
01554   if (!((Fl_Window*)o)->border()) write_c("%sclear_border();\n", indent());
01555   if (xclass) {
01556     write_c("%sxclass(", indent());
01557     write_cstring(xclass);
01558     write_c(");\n");
01559   }
01560   write_c("%send();\n", indent());
01561   if (((Fl_Window*)o)->resizable() == o)
01562     write_c("%sresizable(this);\n", indent());
01563   write_c("}\n");
01564 }
01565 
01567 // live mode support
01568 
01569 Fl_Widget *Fl_Window_Type::enter_live_mode(int) {
01570   Fl_Window *win = new Fl_Window(o->x(), o->y(), o->w(), o->h());
01571   live_widget = win;
01572   if (live_widget) {
01573     copy_properties();
01574     Fl_Type *n;
01575     for (n = next; n && n->level > level; n = n->next) {
01576       if (n->level == level+1)
01577         n->enter_live_mode();
01578     }
01579     win->end();
01580   }
01581   return live_widget;
01582 }
01583 
01584 void Fl_Window_Type::leave_live_mode() {
01585 }
01586 
01590 void Fl_Window_Type::copy_properties() {
01591   Fl_Widget_Type::copy_properties();
01593 }
01594 
01595 
01596 //
01597 // End of "$Id: Fl_Window_Type.cxx 8089 2010-12-20 22:19:24Z matt $".
01598 //