Back to index

texmacs  1.0.7.15
canvas_widget.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : canvas_widget.cpp
00004 * DESCRIPTION: A canvas widget with horizontal and vertical scrollbars.
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 "rectangles.hpp"
00013 #include "window.hpp"
00014 #include "Widkit/basic_widget.hpp"
00015 #include "Widkit/Event/attribute_event.hpp"
00016 #include "Widkit/scroll_widget.hpp"
00017 #include "Widkit/layout.hpp"
00018 
00019 SI get_dx (gravity grav, SI w);
00020 SI get_dy (gravity grav, SI h);
00021 
00022 /******************************************************************************
00023 * Canvas widgets
00024 ******************************************************************************/
00025 
00026 class canvas_widget_rep: public basic_widget_rep {
00027   bool request_focus; // request focus upon clicking in canvas
00028   SI ex1, ey1, ex2, ey2;
00029   SI last_w, last_h;
00030   bool show_scroll_bars;
00031   wk_widget hor; bool hor_active;
00032   wk_widget ver; bool ver_active;
00033 
00034 public:
00035   canvas_widget_rep (wk_widget child, gravity grav, bool rf);
00036   operator tree ();
00037   void set_extents (SI Ex1, SI Ey1, SI Ex2, SI Ey2);
00038 
00039   bool handle_canvas_mouse (mouse_event ev);
00040   void handle_get_size (get_size_event ev);
00041   void handle_get_widget (get_widget_event ev);
00042   void handle_set_widget (set_widget_event ev);
00043   void handle_position (position_event ev);
00044   void handle_repaint (repaint_event ev);
00045   void handle_set_integer (set_integer_event ev);
00046   void handle_set_coord4 (set_coord4_event ev);
00047   void handle_set_string (set_string_event ev);
00048   bool handle (event ev);
00049 };
00050 
00051 /******************************************************************************
00052 * Creation of canvas widgets
00053 ******************************************************************************/
00054 
00055 canvas_widget_rep::canvas_widget_rep (wk_widget child, gravity grav, bool rf):
00056   basic_widget_rep (1), request_focus (rf), show_scroll_bars (true)
00057 {
00058   a[0] = tm_new<scrollable_widget_rep> (child, grav);
00059   hor  = tm_new<hor_scrollbar_widget_rep> (a[0]);
00060   ver  = tm_new<ver_scrollbar_widget_rep> (a[0]);
00061   a[0] << set_hor_bar (NULL); hor_active= false;
00062   a[0] << set_ver_bar (NULL); ver_active= false;
00063   ex1= ey1= ex2= ey2= last_w= last_h= 0;
00064 }
00065 
00066 canvas_widget_rep::operator tree () {
00067   return tree (TUPLE, "canvas", (tree) a[0]);
00068 }
00069 
00070 void
00071 canvas_widget_rep::set_extents (SI Ex1, SI Ey1, SI Ex2, SI Ey2) {
00072   abs_outer_round (Ex1, Ey1, Ex2, Ey2);
00073   SI ew= Ex2- Ex1, eh= Ey2- Ey1;
00074   bool old_hor_active= hor_active, old_ver_active= ver_active;
00075   if ((ew<=(w-2*PIXEL)) && (eh<=(h-2*PIXEL))) {
00076     hor_active= false; ver_active= false; }
00077   else { hor_active= ew > (w-20*PIXEL); ver_active= eh > (h-20*PIXEL); }
00078 
00079   gravity grav= a[0]->grav;
00080   SI ww= w- (show_scroll_bars? (ver_active? 20*PIXEL: 2*PIXEL): 0);
00081   SI wh= h- (show_scroll_bars? (hor_active? 20*PIXEL: 2*PIXEL): 0);
00082   if (Ex2- Ex1 < ww) {
00083     SI cxr= get_dx (grav, ww);
00084     SI cxc= Ex1+ get_dx (grav, Ex2- Ex1);
00085     Ex1= cxc- cxr;
00086     Ex2= cxc- cxr+ ww;
00087   }
00088   if (Ey2- Ey1 < wh) {
00089     SI cyr= get_dy (grav, wh);
00090     SI cyc= Ey2+ get_dy (grav, Ey2- Ey1);
00091     Ey1= cyc- cyr- wh;
00092     Ey2= cyc- cyr;
00093   }
00094 
00095   bool bars_changed=
00096     (old_hor_active != hor_active) || (old_ver_active != ver_active);
00097   bool visibility_changed=
00098     ((!show_scroll_bars) && (N(a)>1)) ||
00099     (show_scroll_bars && (N(a)==1) && (hor_active || ver_active));
00100   bool extents_changed=
00101     (Ex1 != ex1) || (Ey1 != ey1) || (Ex2 != ex2) || (Ey2 != ey2);
00102   ex1= Ex1; ey1= Ey1; ex2= Ex2; ey2= Ey2;
00103 
00104   if (bars_changed || visibility_changed) {
00105     if (hor_active) a[0] << set_hor_bar (hor);
00106     else a[0] << set_hor_bar (NULL);
00107     if (ver_active) a[0] << set_ver_bar (ver);
00108     else a[0] << set_ver_bar (NULL);
00109     a->resize(1);
00110     if (show_scroll_bars && hor_active) a << hor;
00111     if (show_scroll_bars && ver_active) a << ver;
00112     if (attached ()) {
00113       if (hor_active) hor << emit_attach_window (win);
00114       if (ver_active) ver << emit_attach_window (win);
00115       this << emit_reposition ();
00116     }
00117   }
00118 
00119   if (bars_changed || extents_changed) {
00120     a[0] << ::set_extents (ex1, ey1, ex2, ey2);
00121     if (attached ()) this << emit_invalidate_all ();
00122   }
00123 }
00124 
00125 /******************************************************************************
00126 * Event handling
00127 ******************************************************************************/
00128 
00129 bool
00130 canvas_widget_rep::handle_canvas_mouse (mouse_event ev) {
00131   if (ev->type == "press-left" && request_focus)
00132     win->set_keyboard_focus (this);
00133   return basic_widget_rep::handle (ev);
00134 }
00135 
00136 void
00137 canvas_widget_rep::handle_get_size (get_size_event ev) {
00138   if (ev->mode==-1) {
00139     ev->w= 32*PIXEL;
00140     ev->h= 32*PIXEL;
00141   }
00142   if (ev->mode== 1) gui_maximal_extents (ev->w, ev->h);
00143 }
00144 
00145 void
00146 canvas_widget_rep::handle_get_widget (get_widget_event ev) {
00147   if (ev->which == "scrollable") ev->w= a[0]->a[0];
00148   else basic_widget_rep::handle_get_widget (ev);
00149 }
00150 
00151 void
00152 canvas_widget_rep::handle_set_widget (set_widget_event ev) {
00153   if (ev->which == "scrollable") a[0]->a[0]= ev->w;
00154   else basic_widget_rep::handle_set_widget (ev);
00155 }
00156 
00157 void
00158 canvas_widget_rep::handle_position (position_event ev) { (void) ev;
00159   if ((w != last_w) || (h != last_h)) {
00160     last_w= w; last_h= h;
00161     set_extents (ex1, ey1, ex2, ey2);
00162     if (attached ()) this << emit_invalidate_all ();
00163   }
00164 
00165   if (!show_scroll_bars)
00166     a[0] << emit_position (0, 0, w, h);
00167   else if (hor_active && ver_active) {
00168     a[0] << emit_position (PIXEL, -PIXEL, w-20*PIXEL, h-20*PIXEL);
00169     a[1] << emit_position (0, 16*PIXEL-h, w-18*PIXEL, 16*PIXEL);
00170     a[2] << emit_position (w-16*PIXEL, 0, 16*PIXEL, h-18*PIXEL);
00171   }
00172   else if (hor_active && (!ver_active)) {
00173     a[0] << emit_position (PIXEL, -PIXEL, w-2*PIXEL, h-20*PIXEL);
00174     a[1] << emit_position (0, 16*PIXEL-h, w, 16*PIXEL);
00175   }
00176   else if ((!hor_active) && ver_active) {
00177     a[0] << emit_position (PIXEL, -PIXEL, w-20*PIXEL, h-2*PIXEL);
00178     a[1] << emit_position (w-16*PIXEL, 0, 16*PIXEL, h);
00179   }
00180   else a[0] << emit_position (PIXEL, -PIXEL, w-2*PIXEL, h-2*PIXEL);
00181 }
00182 
00183 extern void indent ();
00184 
00185 void
00186 canvas_widget_rep::handle_repaint (repaint_event ev) { (void) ev;
00187   renderer ren= win->get_renderer ();
00188   if (!show_scroll_bars);
00189   else if (hor_active && ver_active) {
00190     layout_default (ren, w- 16*PIXEL, -h, w, -h+ 16*PIXEL);
00191     layout_default (ren, 0, -h+ 16*PIXEL, w, -h+ 18*PIXEL);
00192     layout_default (ren, w- 18*PIXEL, -h, w- 16*PIXEL, 0);
00193     layout_lower (ren, 0, -h+ 18*PIXEL, w- 18*PIXEL, 0);
00194   }
00195   else if (hor_active && (!ver_active)) {
00196     layout_default (ren, 0, -h+ 16*PIXEL, w, -h+ 18*PIXEL);
00197     layout_dark_outline (ren, 0, -h+ 15*PIXEL, w, 0);
00198     ren->set_line_style (PIXEL);
00199     ren->set_color (layout_light (ren));
00200     ren->line (PIXEL, -h+ 18*PIXEL, w-2*PIXEL, -h+ 18*PIXEL);
00201   }
00202   else if ((!hor_active) && ver_active) {
00203     layout_default (ren, w- 18*PIXEL, -h, w- 16*PIXEL, 0);
00204     layout_dark_outline (ren, 0, -h, w- 15*PIXEL, 0);
00205     ren->set_line_style (PIXEL);
00206     ren->set_color (layout_light (ren));
00207     ren->line (w- 19*PIXEL, -h+PIXEL, w- 19*PIXEL, -2*PIXEL);
00208   }
00209   else layout_dark_outline (ren, 0, -h, w, 0);
00210 }
00211 
00212 void
00213 canvas_widget_rep::handle_set_integer (set_integer_event ev) {
00214   if (ev->which == "scrollbars") {
00215     if (((bool) ev->i) != show_scroll_bars) {
00216       show_scroll_bars= (bool) ev->i;
00217       set_extents (ex1, ey1, ex2, ey2);
00218       if (attached ()) this << emit_invalidate_all ();
00219     }
00220   }
00221   else a[0]->a[0] << ev;
00222 }
00223 
00224 void
00225 canvas_widget_rep::handle_set_coord4 (set_coord4_event ev) {
00226   if (ev->which == "extents") set_extents (ev->c1, ev->c2, ev->c3, ev->c4);
00227   else a[0] << ev;
00228 }
00229 
00230 void
00231 canvas_widget_rep::handle_set_string (set_string_event ev) {
00232   if (ev->which == "background") a[0] << ev;
00233   else a[0]->a[0] << ev;
00234 }
00235 
00236 bool
00237 canvas_widget_rep::handle (event ev) {
00238   switch (ev->type) {
00239   case GET_SIZE_EVENT:
00240   case GET_WIDGET_EVENT:
00241   case SET_WIDGET_EVENT:
00242   case ATTACH_WINDOW_EVENT:
00243   case POSITION_EVENT:
00244   case UPDATE_EVENT:
00245   case INVALIDATE_EVENT:
00246     return basic_widget_rep::handle (ev);
00247   case MOUSE_EVENT: {
00248     mouse_event e (ev);
00249     return handle_canvas_mouse (e);
00250   }
00251   case REPAINT_EVENT:
00252   case FIND_CHILD_EVENT:
00253     return basic_widget_rep::handle (ev);
00254   case SET_INTEGER_EVENT: {
00255     set_integer_event e (ev);
00256     handle_set_integer (e);
00257     return true;
00258   }
00259   case SET_COORD4_EVENT: {
00260     set_coord4_event e (ev);
00261     handle_set_coord4 (e);
00262     return true;
00263   }
00264   case SET_STRING_EVENT: {
00265     set_string_event e (ev);
00266     handle_set_string (e);
00267     return true;
00268   }
00269   case GET_COORD4_EVENT:
00270   case SET_COORD2_EVENT:
00271   case GET_COORD2_EVENT:
00272     a[0] << ev;
00273     return true;
00274   default:
00275     a[0]->a[0] << ev;
00276     return true;
00277   }
00278 }
00279 
00280 /******************************************************************************
00281 * Resize widgets
00282 ******************************************************************************/
00283 
00284 class resize_widget_rep: public basic_widget_rep {
00285   int style;
00286   string minw, minh, defw, defh, maxw, maxh;
00287 public:
00288   resize_widget_rep (wk_widget w, int style, string w1, string h1,
00289                      string w2, string h2, string w3, string j3);
00290   operator tree ();
00291   void handle_get_size (get_size_event ev);
00292   void handle_repaint (repaint_event ev);
00293 };
00294 
00295 resize_widget_rep::resize_widget_rep (wk_widget w, int style2,
00296                                       string w1, string h1,
00297                                       string w2, string h2,
00298                                       string w3, string h3):
00299   basic_widget_rep (1), style (style2), minw (w1), minh (h1),
00300   defw (w2), defh (h2), maxw (w3), maxh (h3) { a[0]= w; }
00301 
00302 resize_widget_rep::operator tree () {
00303   return tree (TUPLE, "resize", (tree) a[0], defw, defh);
00304 }
00305 
00306 void
00307 resize_widget_rep::handle_get_size (get_size_event ev) {
00308   string ww, hh;
00309   if (ev->mode == -1) { ww= minw; hh= minh; }
00310   else if (ev->mode == 1) { ww= maxw; hh= maxh; }
00311   else { ww= defw; hh= defh; }
00312   if (ww != "") ev->w= decode_length (ww, a[0], style);
00313   if (hh != "") ev->h= decode_length (hh, a[0], style);
00314   abs_round (ev->w, ev->h);
00315 }
00316 
00317 void
00318 resize_widget_rep::handle_repaint (repaint_event ev) {
00319   renderer ren= win->get_renderer ();
00320   rectangles r1= rectangle (ev->x1, ev->y1, ev->x2, ev->y2);
00321   rectangles r2= rectangle (0, -h, w, 0);
00322   rectangles rs= r1 - r2;
00323   for (int i=0; i<N(rs); i++)
00324     layout_default (ren, rs[i]->x1, rs[i]->y1, rs[i]->x2, rs[i]->y2);
00325   //layout_default (ren, ev->x1, ev->y1, ev->x2, ev->y2);
00326   basic_widget_rep::handle_repaint (ev);
00327 }
00328 
00329 wk_widget
00330 resize_widget (wk_widget w, int style, string w1, string h1,
00331                string w2, string h2, string w3, string h3) {
00332   //cout << "min: " << w1 << ", " << h1 << "\n";
00333   //cout << "def: " << w2 << ", " << h2 << "\n";
00334   //cout << "max: " << w3 << ", " << h3 << "\n";
00335   return tm_new<resize_widget_rep> (w, style, w1, h1, w2, h2, w3, h3);
00336 }
00337 
00338 /******************************************************************************
00339 * Wrap scroll widgets
00340 ******************************************************************************/
00341 
00342 class wrap_scroll_widget_rep: public basic_widget_rep {
00343 public:
00344   wrap_scroll_widget_rep (wk_widget w);
00345   operator tree ();
00346   void handle_repaint (repaint_event ev);
00347 };
00348 
00349 wrap_scroll_widget_rep::wrap_scroll_widget_rep (wk_widget w):
00350   basic_widget_rep (1) { a[0]= w; }
00351 
00352 wrap_scroll_widget_rep::operator tree () {
00353   return tree (TUPLE, "wrap_scroll", (tree) a[0]);
00354 }
00355 
00356 void
00357 wrap_scroll_widget_rep::handle_repaint (repaint_event ev) {
00358   renderer ren= win->get_renderer ();
00359   layout_default (ren, ev->x1, ev->y1, ev->x2, ev->y2);
00360   a[0] << emit_position (0, 0, w, h);
00361   basic_widget_rep::handle_repaint (ev);
00362 }
00363 
00364 wk_widget
00365 wrap_scroll_widget (wk_widget w) {
00366   return tm_new<wrap_scroll_widget_rep> (w);
00367 }
00368 
00369 /******************************************************************************
00370 * exported routines
00371 ******************************************************************************/
00372 
00373 event
00374 set_scrollable (wk_widget w) {
00375   return set_widget ("scrollable", w);
00376 }
00377 
00378 wk_widget
00379 canvas_widget (wk_widget w, gravity grav, bool request_focus) {
00380   return tm_new<canvas_widget_rep> (w, grav, request_focus);
00381 }
00382 
00383 wk_widget
00384 user_canvas_widget (wk_widget wid, int style) {
00385   wk_widget cv= canvas_widget (wrap_scroll_widget (wid));
00386   SI widw, widh;
00387   gui_maximal_extents (widw, widh);
00388   wid << get_size (widw, widh, -1);
00389   abs_round (widw, widh);
00390   cv << set_coord4 ("extents", 0, -widh, widw, 0);
00391   return cv;
00392 }
00393 
00394 wk_widget
00395 vsplit_widget (wk_widget t, wk_widget b) {
00396   (void) t; (void) b;
00397   FAILED ("not yet implemented");
00398 }