Back to index

texmacs  1.0.7.15
split_widget.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : split_widget.cpp
00004 * DESCRIPTION: widgets which are separated into two parts and
00005 *              whose separating border can be adjusted using the mouse
00006 * COPYRIGHT  : (C) 2012  Joris van der Hoeven
00007 *******************************************************************************
00008 * This software falls under the GNU general public license version 3 or later.
00009 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00010 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00011 ******************************************************************************/
00012 
00013 #include "rectangles.hpp"
00014 #include "window.hpp"
00015 #include "Widkit/composite_widget.hpp"
00016 #include "Widkit/layout.hpp"
00017 
00018 void abs_round (SI& l);
00019 
00020 /******************************************************************************
00021 * Horizontal splits
00022 ******************************************************************************/
00023 
00024 class hsplit_widget_rep: public composite_widget_rep {
00025   SI bw;
00026   bool has_grip;
00027   SI curw1, curw2;
00028 public:
00029   hsplit_widget_rep (array<wk_widget> a, array<string> names);
00030   operator tree ();
00031   void handle_get_size (get_size_event ev);
00032   void handle_position (position_event ev);
00033   void handle_find_child (find_child_event ev);
00034   void handle_repaint (repaint_event ev);
00035   void handle_mouse (mouse_event ev);
00036 };
00037 
00038 hsplit_widget_rep::hsplit_widget_rep (array<wk_widget> a, array<string> n):
00039   composite_widget_rep (a, n), bw (8*PIXEL), has_grip (false),
00040   curw1 (-1), curw2 (-1) {
00041     ASSERT (N(a) == 2, "invalid number of children"); }
00042 
00043 hsplit_widget_rep::operator tree () {
00044   return tree (TUPLE, "horizontal split", (tree) a[0], (tree) a[1]);
00045 }
00046 
00047 void
00048 hsplit_widget_rep::handle_get_size (get_size_event ev) {
00049   SI w1= (ev->w-bw)/2, h1= ev->h, w2= (ev->w-bw)/2, h2= ev->h;
00050   a[0] << get_size (w1, h1, ev->mode);
00051   a[1] << get_size (w2, h2, ev->mode);
00052   ev->w= w1 + w2 + bw;
00053   ev->h= max (max (h1, h2), 24*PIXEL);
00054 }
00055 
00056 void
00057 hsplit_widget_rep::handle_position (position_event ev) {
00058   if (curw1 < 0 && curw2 < 0) {
00059     SI ew= w - bw;
00060     SI w1= ew, w2= ew, h1= h, h2= h;
00061     a[0] << get_size (w1, h1, 0);
00062     a[1] << get_size (w2, h2, 0);
00063     if (ew >= w1 + w2) {
00064       SI dw= ew - (w1 + w2);
00065       curw1= w1 + dw/2;
00066       curw2= w2 + dw/2;
00067     }
00068     else {
00069       SI dw= (w1 + w2) - ew;
00070       curw1= w1 - dw/2;
00071       curw2= w2 - dw/2;
00072     }
00073   }
00074   else {
00075     SI dw= w - (curw1 + curw2);
00076     curw1 += dw/2;
00077     curw2 += dw/2;
00078   }
00079 
00080   SI minw1= w-bw, minh1= h, minw2= w-bw, minh2= h;
00081   SI maxw1= w-bw, maxh1= h, maxw2= w-bw, maxh2= h;
00082   a[0] << get_size (minw1, minh1, -1);
00083   a[1] << get_size (minw2, minh2, -1);
00084   a[0] << get_size (maxw1, maxh1, 1);
00085   a[1] << get_size (maxw2, maxh2, 1);
00086   SI adjust= 0;
00087   if      (curw1 < minw1 && curw2 >= minw2)
00088     adjust=  min (minw1 - curw1, curw2 - minw2);
00089   else if (curw2 < minw2 && curw1 >= minw1)
00090     adjust= -min (minw2 - curw2, curw1 - minw1);
00091   else if (curw1 > maxw1 && curw2 <= maxw2)
00092     adjust= -min (curw1 - maxw1, maxw2 - curw2);
00093   else if (curw2 > maxw2 && curw1 <= maxw1)
00094     adjust=  min (curw2 - maxw2, maxw1 - curw1);
00095   curw1 += adjust;
00096   curw2 -= adjust;
00097 
00098   abs_round (curw1);
00099   abs_round (curw2);
00100   if (a[0]->ox != ox || a[0]->oy != oy || a[0]->w != curw1 || a[0]->h != h)
00101     a[0] << emit_position (0, 0, curw1, h);
00102   a[1] << emit_position (curw1 + bw, 0, curw1 + curw2 + bw, h);
00103 }
00104 
00105 void
00106 hsplit_widget_rep::handle_find_child (find_child_event ev) {
00107   int& i= ev->which;
00108   for (i=0; i<N(a); i++)
00109     if ((ev->x >= a[i]->x1()-ox) && (ev->x < a[i]->x2()-ox)) return;
00110   i= -1;
00111 }
00112 
00113 void
00114 hsplit_widget_rep::handle_repaint (repaint_event ev) {
00115   renderer ren= win->get_renderer ();
00116   rectangles r1= rectangle (ev->x1, ev->y1, ev->x2, ev->y2);
00117   rectangles r2= rectangle (0, -h, w, 0);
00118   rectangles rs= r1 - r2;
00119   for (int i=0; i<N(rs); i++)
00120     layout_default (ren, rs[i]->x1, rs[i]->y1, rs[i]->x2, rs[i]->y2);
00121   SI lx= (a[0]->x2()-ox);
00122   SI rx= (a[1]->x1()-ox);
00123   SI xx= (lx+rx)/2;
00124   SI yy= -h/2;
00125   layout_default (ren, lx, ev->y1, rx, ev->y2);
00126   layout_lower (ren, xx - 2*PIXEL, yy - 6*PIXEL, xx + PIXEL, yy + 6*PIXEL);
00127   basic_widget_rep::handle_repaint (ev);
00128 }
00129 
00130 void
00131 hsplit_widget_rep::handle_mouse (mouse_event ev) {
00132   bool mid= (ev->x >= (a[0]->x2()-ox)) && (ev->x < (a[1]->x1()-ox));
00133   if (has_grip) {
00134     if ((!mid && ev->type == "move") || ev->type == "release-left") {
00135       SI minw1= w-bw, minh1= h, minw2= w-bw, minh2= h;
00136       SI maxw1= w-bw, maxh1= h, maxw2= w-bw, maxh2= h;
00137       a[0] << get_size (minw1, minh1, -1);
00138       a[1] << get_size (minw2, minh2, -1);
00139       a[0] << get_size (maxw1, maxh1, 1);
00140       a[1] << get_size (maxw2, maxh2, 1);
00141       SI w1= ev->x - bw/2;
00142       SI w2= w - bw - w1;
00143       abs_round (w1);
00144       abs_round (w2);
00145       if (w1 >= minw1 && w1 <= maxw1 && w2 >= minw2 && w2 <= maxw2) {
00146         curw1= w1;
00147         curw2= w2;
00148         a[0] << emit_position (0, 0, w1, h);
00149         a[1] << emit_position (w1 + bw, 0, w1 + w2 + bw, h);
00150         this << emit_invalidate_all ();
00151       }
00152     }
00153     if (ev->type == "release-left") {
00154       has_grip= false;
00155       wk_ungrab_pointer (this);
00156     }
00157   }
00158   else if (!mid)
00159     basic_widget_rep::handle_mouse (ev);
00160   else if (ev->type == "press-left") {
00161     has_grip= true;
00162     wk_grab_pointer (this);
00163   }
00164 }
00165 
00166 /******************************************************************************
00167 * Interface
00168 ******************************************************************************/
00169 
00170 wk_widget
00171 hsplit_widget (wk_widget l, wk_widget r) {
00172   array<wk_widget> a (2);
00173   a[0]= l; a[1]= r;
00174   array<string> names (2);
00175   names[0]= "left"; names[1]= "right";
00176   return tm_new<hsplit_widget_rep> (a, names);
00177 }