Back to index

texmacs  1.0.7.15
popup_button.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : popup_button.cpp
00004 * DESCRIPTION: Buttons which trigger a popup window.
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "timer.hpp"
00013 #include "window.hpp"
00014 #include "promise.hpp"
00015 #include "Widkit/Button/button_widget.hpp"
00016 #include "message.hpp"
00017 
00018 #ifdef OS_WIN32
00019 #define MAP_DELAY 250
00020 #else
00021 #define MAP_DELAY 100
00022 #endif
00023 
00024 /******************************************************************************
00025 * Popup buttons
00026 ******************************************************************************/
00027 
00028 class popup_button_rep: public button_widget_rep {
00029   promise<wk_widget> prom;
00030   wk_widget          popup_w;
00031   window  popup;
00032   gravity where;
00033   time_t  entered_at;
00034   bool    require_map;
00035   bool    stick;
00036 
00037 private:
00038   void map_popup ();
00039   void unmap_popup ();
00040   void consistent (string s);
00041 public:
00042   popup_button_rep (wk_widget w, wk_widget pw,
00043                   gravity where, int style);
00044   popup_button_rep (wk_widget w, promise<wk_widget> prom,
00045                   gravity where);
00046   void handle_attach_window (attach_window_event ev);
00047   void handle_mouse (mouse_event ev);
00048   bool handle (event ev);
00049 };
00050 
00051 gravity opposite (gravity grav);
00052 
00053 /******************************************************************************
00054 * Routines for popup buttons
00055 ******************************************************************************/
00056 
00057 popup_button_rep::popup_button_rep (
00058   wk_widget w, wk_widget pw, gravity wh, int style):
00059     button_widget_rep (w, wh==east, style),
00060     prom (), popup_w (popup_widget (pw, opposite (wh))), popup (NULL),
00061     where (wh), require_map (false), stick (false)
00062 {
00063   this->has_pull_down= (where == south || where == south_east);
00064   if (where != east && where != south && where != south_east)
00065     WK_FAILED ("direction not implemented");
00066 }
00067 
00068 popup_button_rep::popup_button_rep (
00069   wk_widget w, promise<wk_widget> prom2, gravity where2):
00070     button_widget_rep (w, where2==east),
00071     prom (prom2), popup_w (), popup (NULL),
00072     where (where2), require_map (false), stick (false)
00073 {
00074   this->has_pull_down= (where == south || where == south_east);
00075   if ((where!=east) && (where!=south) && (where!=south_east))
00076     WK_FAILED ("direction not implemented");
00077 }
00078 
00079 void
00080 popup_button_rep::consistent (string s) {
00081   // status= true
00082   //   iff (inside button and left or right button pressed) or stick
00083   //   iff require_map=true or mouse grab activated on button
00084   //   iff require_map=true or popup window is mapped
00085 
00086   bool flag;
00087   if (status) flag=
00088               (require_map && (popup != NULL)) ||
00089               ((!require_map) && (popup == NULL));
00090   else flag= (!require_map) && (popup != NULL);
00091   if (flag) {
00092     cerr << "status     = " << status << "\n";
00093     cerr << "require map= " << require_map << "\n";
00094     cerr << "popup      = " << (popup != NULL) << "\n";
00095     WK_FAILED ("inconsistency in " * s);
00096   }
00097 }
00098 
00099 void
00100 popup_button_rep::map_popup () {
00101   require_map= false;
00102   stick      = false;
00103 
00104   if (!is_nil (prom)) {
00105     // time_t start_1= texmacs_time ();
00106     popup_w= popup_widget (prom (), opposite (where));
00107     // cout << "Mapping required " << (texmacs_time ()-start_1) << " ms\n";
00108   }
00109 
00110   // time_t start_2= texmacs_time ();
00111   SI x, y, w=0, h=0;
00112   win->get_position (x, y);
00113   popup_w << get_size (w, h);
00114 
00115   switch (where) {
00116   case east:
00117     x += x2()-12*PIXEL;
00118     y += y2()+3*PIXEL;
00119     break;
00120   case south_east:
00121     x += x1()-3*PIXEL;
00122     y += y1();
00123     break;
00124   case south:
00125     x += ((x1()+x2())>>1)- (w>>1)- 3*PIXEL;
00126     y += y1();
00127     break;
00128   default:
00129     break;
00130   }
00131   // cout << "Positioning required " << (texmacs_time ()-start_2) << " ms\n";
00132 
00133   // time_t start_3= texmacs_time ();
00134   wk_widget win_wid= popup_window_widget (popup_w, "Popup");
00135   set_position (abstract (win_wid), x, y);
00136   popup= win_wid -> win;
00137   // popup= popup_window (abstract (popup_w), x, y);
00138   // cout << "Window creation required " << (texmacs_time ()-start_3) << " ms\n";
00139   // time_t start_4= texmacs_time ();
00140   popup->set_visibility (true);
00141   // cout << "Mapping required " << (texmacs_time ()-start_4) << " ms\n";
00142 
00143   this << emit_invalidate_all ();
00144   wk_grab_pointer (this);
00145 }
00146 
00147 void
00148 popup_button_rep::unmap_popup () {
00149   if (popup == NULL) WK_FAILED ("unexpected situation");
00150   popup->set_visibility (false);
00151   tm_delete (popup);
00152   popup= NULL;
00153   if (!is_nil (prom)) popup_w= wk_widget ();
00154 
00155   this << emit_invalidate_all ();
00156   if (!wk_has_pointer_grab (this))
00157     WK_FAILED ("I do not have the pointer grab");
00158   wk_ungrab_pointer (this);
00159 }
00160 
00161 void
00162 popup_button_rep::handle_attach_window (attach_window_event ev) {
00163   if ((ev->win==NULL) && status) {
00164     consistent ("handle_attach_window (1)");
00165     status= false;
00166     if (require_map) require_map= false;
00167     else unmap_popup ();
00168     stick= false;    
00169     consistent ("handle_attach_window (2)");
00170   }
00171   basic_widget_rep::handle_attach_window (ev);
00172 }
00173 
00174 void
00175 popup_button_rep::handle_mouse (mouse_event ev) {
00176   string type= ev->type;
00177   SI x= ev->x, y= ev->y;
00178 
00179   consistent ("handle_mouse (start)");
00180 
00181   bool old_inside= inside;
00182 
00183   if (type == "leave") {
00184     inside= false;
00185     if (require_map) {
00186       status= false;
00187       require_map= false;
00188     }
00189   }
00190 
00191   /*************************** button is inactive ****************************/
00192   else if (!status) {
00193     consistent ("handle_mouse (1)");
00194     inside= (y>=0) && (y<h) && (x>=0) && (x<w);
00195     status= inside && (ev->pressed ("left") || ev->pressed ("right"));
00196     if (status) {
00197       entered_at= texmacs_time ();
00198       require_map= true;
00199     }
00200   }
00201 
00202   /**************************** button is active *****************************/
00203   else {
00204     bool inside_popup=
00205       ((where == east) && (x > w-12*PIXEL)) ||
00206       ((where == south) && (y<0)) ||
00207       ((where == south_east) && (y<0));
00208     inside=
00209       (y>=0) && (y<h) && (x>=0) && (x<w);
00210     status=
00211       (inside || ((!stick) && inside_popup)) &&
00212       (ev->pressed ("left") || ev->pressed ("right"));
00213 
00214     // activate
00215     if (status) {
00216       if (inside_popup) {
00217        if (require_map) map_popup ();
00218        if (status) {
00219          consistent ("handle_mouse (2)");
00220          popup_w << set_integer ("stick", 0);
00221          wk_grab_pointer (popup_w);
00222        }
00223       }
00224     }
00225 
00226     // stick or disactivate
00227     else {
00228       if (inside /* && false */) {
00229        status= true;
00230        if (require_map) { map_popup (); stick= true; }
00231        if (status) {
00232          consistent ("handle_mouse (3)");
00233          popup_w << set_integer ("stick", 1);
00234          wk_grab_pointer (popup_w);
00235        }
00236       }
00237       else {
00238        if (require_map) require_map= false;
00239        else unmap_popup ();
00240       }
00241     }
00242   }
00243 
00244   if (inside != old_inside && attached ())
00245     this << emit_invalidate_all ();
00246 
00247   consistent ("handle_mouse (*)");
00248 
00249   /**************************** wait to be mapped ****************************/
00250   if (require_map) {
00251     time_t now;
00252     do {
00253       now= texmacs_time ();
00254       if (check_event (MENU_EVENT)) return;
00255     } while ((now-entered_at) < MAP_DELAY);
00256     map_popup ();
00257   }
00258 
00259   consistent ("handle_mouse (end)");
00260 }
00261 
00262 bool
00263 popup_button_rep::handle (event ev) {
00264   switch (ev->type) {
00265   case GET_WIDGET_EVENT:
00266   case SET_WIDGET_EVENT:
00267   case CLEAN_EVENT:
00268   case INSERT_EVENT:
00269   case REMOVE_EVENT:
00270     if (!is_nil (popup_w)) popup_w << ev;
00271     return true;
00272   case GET_COORD2_EVENT:
00273   case SET_COORD2_EVENT:
00274     return button_widget_rep::handle (ev);
00275   default:
00276     return basic_widget_rep::handle (ev);
00277   }
00278 }
00279 
00280 gravity
00281 opposite (gravity grav) {
00282   switch (grav) {
00283   case north_west: return south_east;
00284   case north     : return south;
00285   case north_east: return south_west;
00286   case west      : return east;
00287   case center    : return center;
00288   case east      : return west;
00289   case south_west: return north_east;
00290   case south     : return north;
00291   case south_east: return north_west;
00292   }
00293   FAILED ("unknown gravity");
00294   return center; // Because of bug in certain versions of g++
00295 }
00296 
00297 /******************************************************************************
00298 * Interface
00299 ******************************************************************************/
00300 
00301 wk_widget
00302 pulldown_button (wk_widget w, wk_widget pw, int style) {
00303   return tm_new<popup_button_rep> (w, pw, south_east, style);
00304 }
00305 
00306 wk_widget
00307 pullright_button (wk_widget w, wk_widget pw, int style) {
00308   return tm_new<popup_button_rep> (w, pw, east, style);
00309 }
00310 
00311 wk_widget
00312 pulldown_button (wk_widget w, promise<wk_widget> prom) {
00313   return tm_new<popup_button_rep> (w, prom, south_east);
00314 }
00315 
00316 wk_widget
00317 pullright_button (wk_widget w, promise<wk_widget> prom) {
00318   return tm_new<popup_button_rep> (w, prom, east);
00319 }