Back to index

texmacs  1.0.7.15
scrollbar_widget.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : scrollbar_widget.cpp
00004 * DESCRIPTION: 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 "Widkit/attribute_widget.hpp"
00013 #include "Widkit/scroll_widget.hpp"
00014 #include "Widkit/layout.hpp"
00015 
00016 /******************************************************************************
00017 * Routines for abstract scrollbars
00018 ******************************************************************************/
00019 
00020 scrollbar_rep::scrollbar_rep (wk_widget ref2):
00021   scroll_widget_rep (0, south_west), ref (ref2.rep),
00022   sc_min(0), sc_max(0), sc_pos(0), before(0), after(0),
00023   factor (0.5), gripped (false), scrolling (false), increment (0) {}
00024 
00025 void
00026 scrollbar_rep::handle_set_coord1 (set_coord1_event ev) {
00027   if (ev->which == "scroll position") {
00028     sc_pos = ev->c1;
00029     sc_pos = min (sc_pos, sc_max);
00030     sc_pos = max (sc_pos, sc_min);
00031     abs_round (sc_pos);  
00032     this << emit_scroll (sc_pos, before, after);
00033     
00034     if (before+ after > sc_max- sc_min) {
00035       SI total= before+after;
00036       DI ext  = sc_max- sc_min; if (total==0) total=1;
00037       before  = (SI) ((before*ext)/total);
00038       after   = ((SI) ext)- before;
00039     }
00040     
00041     if (sc_pos- before < sc_min) before = sc_pos - sc_min;
00042     if (sc_pos+ after  > sc_max) after  = sc_max - sc_pos;
00043     
00044     if (attached ()) this << emit_invalidate_all ();
00045     return;
00046   }
00047   attribute_widget_rep::handle_set_coord1 (ev);
00048 }
00049 
00050 void
00051 scrollbar_rep::handle_set_coord2 (set_coord2_event ev) {
00052   /*
00053   cout << "Scrollbar extents  " << (ev->c1/PIXEL) << ", "
00054        << (ev->c2/PIXEL) << "\n";
00055   cout << "Scrollbar position " << (sc_pos/PIXEL) << "\n";
00056   */
00057   if (ev->which == "extents") {
00058     sc_min= ev->c1;
00059     sc_max= ev->c2;
00060     this << emit_bar_scroll_to (sc_pos);
00061     return;
00062   }
00063   attribute_widget_rep::handle_set_coord2 (ev);
00064 }
00065 
00066 /******************************************************************************
00067 * Routines for horizontal scrollbars
00068 ******************************************************************************/
00069 
00070 hor_scrollbar_widget_rep::hor_scrollbar_widget_rep (wk_widget ref):
00071   scrollbar_rep (ref) {}
00072 
00073 hor_scrollbar_widget_rep::operator tree () {
00074   return "horizontal scrollbar";
00075 }
00076 
00077 void
00078 hor_scrollbar_widget_rep::handle_get_size (get_size_event ev) {
00079   if (ev->mode== 0) ev->h= 16*PIXEL;
00080   if (ev->mode==-1) {
00081     ev->w= 48*PIXEL;
00082     ev->h= 16*PIXEL;
00083   }
00084   if (ev->mode== 1) {
00085     gui_maximal_extents (ev->w, ev->h);
00086     ev->h= 16*PIXEL;
00087   }
00088 }
00089 
00090 void
00091 hor_scrollbar_widget_rep::decode_position (SI& x1, SI& x2) {
00092   SI total = sc_max- sc_min; if (total==0) total=1;
00093   SI extra = (((h/PIXEL)*3)/4)*PIXEL + 3*PIXEL;
00094   SI min_w = min (w-2*extra, 12*PIXEL);
00095   DI real_w= w- 2*extra - min_w;
00096   SI bef   = (SI) ((before*real_w)/total);
00097   SI aft   = (SI) ((after*real_w)/total);
00098   SI p;
00099 
00100   if (bef+aft==0) aft=1;
00101   while (bef+aft< 4*PIXEL) {
00102     bef= aft= 2*PIXEL;
00103     p = (SI) (((sc_pos- sc_min)*real_w)/total);
00104     if (p<2*PIXEL) { bef=p; aft= 4*PIXEL-bef; }
00105     if (p>(real_w- 2*PIXEL)) { aft=real_w-p; bef= 4*PIXEL-aft; }
00106   }
00107   
00108   p = (SI) (((sc_pos- sc_min)*real_w)/total);
00109   x1= max (0, p-bef)+ extra;
00110   x2= min ((SI) real_w, p+aft)+ extra + min_w;
00111 }
00112 
00113 SI
00114 hor_scrollbar_widget_rep::encode_position (SI x) {
00115   DI total  = sc_max- sc_min; if (total==0) total=1;
00116   SI extra  = (((h/PIXEL)*3)/4)*PIXEL + 3*PIXEL;
00117   SI min_w  = min (w-2*extra, 12*PIXEL);
00118   SI real_w = w- 2*extra - min_w;
00119   SI dec_x  = (SI) (((x - extra - (min_w>>1)) * total) / real_w);
00120   return dec_x+ sc_min;
00121 }
00122 
00123 void
00124 hor_scrollbar_widget_rep::handle_repaint (repaint_event ev) { (void) ev;
00125   renderer ren= win->get_renderer ();
00126   SI X1, X2;
00127   decode_position (X1, X2);
00128   layout_dark (ren, 0, 0, w, h);
00129   layout_lower (ren, 0, 0, w, h); 
00130   layout_default (ren, X1, PIXEL, X2, h-PIXEL);
00131   layout_higher  (ren, X1, PIXEL, X2, h-PIXEL);
00132 
00133   SI aw= (((h/PIXEL)*3)/4)*PIXEL;
00134   SI ah= h-4*PIXEL;
00135   layout_left_arrow (ren, 2*PIXEL, 2*PIXEL, aw, ah);
00136   layout_right_arrow (ren, w- 2*PIXEL- aw, 2*PIXEL, aw, ah);
00137 }
00138 
00139 void
00140 hor_scrollbar_widget_rep::handle_mouse (mouse_event ev) {
00141   string type= ev->type;
00142   SI     X   = ev->x;
00143   SI     aw  = (((h/PIXEL)*3)/4)*PIXEL + 3*PIXEL;
00144   SI     X1, X2;
00145   decode_position (X1, X2);
00146 
00147   if (type == "press-left") {
00148     SI ww; ref << get_width (ww);
00149     if (X < aw) {
00150       scrolling= true;
00151       increment= -5*PIXEL;
00152       this << emit_bar_scroll_to (sc_pos + increment);
00153       wk_grab_pointer (this);
00154       win->delayed_message (this, "scroll", 100);
00155     }
00156     else if (X >= (w-aw)) {
00157       scrolling= true;
00158       increment= 5*PIXEL;
00159       this << emit_bar_scroll_to (sc_pos + increment);
00160       wk_grab_pointer (this);
00161       win->delayed_message (this, "scroll", 100);
00162     }
00163     else if (X<X1) this << emit_bar_scroll_to (sc_pos- ww);
00164     else if (X>X2) this << emit_bar_scroll_to (sc_pos+ ww);
00165     else {
00166       gripped= true;
00167       wk_grab_pointer (this);
00168       factor= ((double) (X-X1))/((double) (X2-X1));
00169     }
00170   }
00171 
00172   if (type == "press-middle") {
00173     SI x= encode_position (X);
00174     this << emit_bar_scroll_to (x- ((after-before)>>1));
00175     wk_grab_pointer (this);
00176     factor= 0.5;
00177   }
00178 
00179   if (type == "press-right") {
00180     if (X<X1) this << emit_bar_scroll_to (sc_pos- 25*PIXEL);
00181     if (X>X2) this << emit_bar_scroll_to (sc_pos+ 25*PIXEL);
00182   }
00183 
00184   if ((type == "move") &&
00185       ((gripped && ev->pressed ("left")) || ev->pressed ("middle"))) {
00186     if (check_event (DRAG_EVENT)) return;
00187     SI x = encode_position (X);
00188     SI dx= (SI) ((after+before)*factor);
00189     this << emit_bar_scroll_to (x+ before- dx);
00190   }
00191 
00192   if (((type == "release-left") || (type == "release-middle")) &&
00193       (!ev->pressed ("left")) && (!ev->pressed ("middle"))) {
00194     gripped= scrolling= false;
00195     wk_ungrab_pointer (this);
00196   }
00197 }
00198 
00199 void
00200 hor_scrollbar_widget_rep::handle_alarm (alarm_event ev) {
00201   if (scrolling && (ev->message == "scroll")) {
00202     this << emit_bar_scroll_to (sc_pos + increment);
00203     win->delayed_message (this, "scroll", 10);
00204   }
00205 }
00206 
00207 void
00208 hor_scrollbar_widget_rep::handle_scroll (scroll_event ev) {
00209   if (ev->which != "this") WK_FAILED ("invalid scroll");
00210   ref << emit_hor_scroll (ev->c1, ev->c2, ev->c3);
00211 }
00212 
00213 /******************************************************************************
00214 * Routines for vertical scrollbars
00215 ******************************************************************************/
00216 
00217 ver_scrollbar_widget_rep::ver_scrollbar_widget_rep (wk_widget ref):
00218   scrollbar_rep (ref) {}
00219 
00220 ver_scrollbar_widget_rep::operator tree () {
00221   return "vertical scrollbar";
00222 }
00223 
00224 void
00225 ver_scrollbar_widget_rep::handle_get_size (get_size_event ev) {
00226   if (ev->mode== 0) ev->w= 16*PIXEL;
00227   if (ev->mode==-1) {
00228     ev->w= 16*PIXEL;
00229     ev->h= 8*PIXEL;
00230   }
00231   if (ev->mode== 1) {
00232     gui_maximal_extents (ev->w, ev->h);
00233     ev->w= 16*PIXEL;
00234   }
00235 }
00236 
00237 void
00238 ver_scrollbar_widget_rep::decode_position (SI& y1, SI& y2) {
00239   SI total = sc_max- sc_min; if (total==0) total=1;
00240   SI extra = (((w/PIXEL)*3)/4)*PIXEL + 3*PIXEL;
00241   SI min_h = min (h-2*extra, 12*PIXEL);
00242   DI real_h= h- 2*extra - min_h;
00243   SI bef   = (SI) ((before*real_h)/total);
00244   SI aft   = (SI) ((after*real_h)/total);
00245   SI p;
00246 
00247   if (bef+aft==0) aft=1;
00248   while (bef+aft< 4*PIXEL) {
00249     bef= aft= 2*PIXEL;
00250     p = (SI) (((sc_pos- sc_min)*real_h)/total);
00251     if (p<2*PIXEL) { bef=p; aft= 4*PIXEL-bef; }
00252     if (p>(real_h- 2*PIXEL)) { aft=real_h-p; bef= 4*PIXEL-aft; }
00253   }
00254   
00255   p = (SI) (((sc_pos- sc_min)*real_h)/total);
00256   y1= max (0, p-bef)+ extra;
00257   y2= min ((SI) real_h, p+aft) + extra + min_h;
00258 }
00259 
00260 SI
00261 ver_scrollbar_widget_rep::encode_position (SI y) {
00262   DI total  = sc_max- sc_min; if (total==0) total=1;
00263   SI extra  = (((w/PIXEL)*3)/4)*PIXEL + 3*PIXEL;
00264   SI min_h  = min (h-2*extra, 12*PIXEL);
00265   SI real_h = h - 2*extra - min_h;
00266   SI dec_y  = (SI) (((y - extra - (min_h>>1)) * total) / real_h);
00267   return dec_y+ sc_min;
00268 }
00269 
00270 void
00271 ver_scrollbar_widget_rep::handle_repaint (repaint_event ev) { (void) ev;
00272   renderer ren= win->get_renderer ();
00273   SI Y1, Y2;
00274   decode_position (Y1, Y2);
00275   layout_dark (ren, 0, 0, w, h);
00276   layout_lower (ren, 0, 0, w, h); 
00277   layout_default (ren, PIXEL, Y1, w- PIXEL, Y2);
00278   layout_higher (ren, PIXEL, Y1, w- PIXEL, Y2);
00279 
00280   SI aw= w-4*PIXEL;
00281   SI ah= (((w/PIXEL)*3)/4)*PIXEL;
00282   layout_up_arrow (ren, 2*PIXEL, h- 2*PIXEL- ah, aw, ah);
00283   layout_down_arrow (ren, 2*PIXEL, 2*PIXEL, aw, ah);
00284 }
00285 
00286 void
00287 ver_scrollbar_widget_rep::handle_mouse (mouse_event ev) {
00288   string type= ev->type;
00289   SI     Y   = ev->y;
00290   SI     ah  = (((w/PIXEL)*3)/4)*PIXEL + 3*PIXEL;
00291   SI     Y1, Y2;
00292   decode_position (Y1, Y2);
00293 
00294   if (type == "press-left") {
00295     SI hh; ref << get_height (hh);
00296     if (Y < ah) {
00297       scrolling= true;
00298       increment= -5*PIXEL;
00299       this << emit_bar_scroll_to (sc_pos + increment);
00300       wk_grab_pointer (this);
00301       win->delayed_message (this, "scroll", 100);
00302     }
00303     else if (Y >= (h-ah)) {
00304       scrolling= true;
00305       increment= 5*PIXEL;
00306       this << emit_bar_scroll_to (sc_pos + increment);
00307       wk_grab_pointer (this);
00308       win->delayed_message (this, "scroll", 100);
00309     }
00310     else if (Y<Y1) this << emit_bar_scroll_to (sc_pos- hh);
00311     else if (Y>Y2) this << emit_bar_scroll_to (sc_pos+ hh);
00312     else {
00313       gripped= true;
00314       wk_grab_pointer (this);
00315       factor= ((double) (Y-Y1))/((double) (Y2-Y1));
00316     }
00317   }
00318 
00319   if (type == "press-middle") {
00320     SI y= encode_position (Y);
00321     this << emit_bar_scroll_to (y- ((after-before)>>1));
00322     wk_grab_pointer (this);
00323     factor= 0.5;
00324   }
00325 
00326   if (type == "press-right") {
00327     if (Y < Y1) this << emit_bar_scroll_to (sc_pos- 25*PIXEL);
00328     if (Y > Y2) this << emit_bar_scroll_to (sc_pos+ 25*PIXEL);
00329   }
00330 
00331   if ((type == "move") &&
00332       ((gripped && ev->pressed ("left")) || ev->pressed ("middle"))) {
00333     if (check_event (DRAG_EVENT)) return;
00334     SI y = encode_position (Y);
00335     SI dy= (SI) ((after+before)*factor);
00336     this << emit_bar_scroll_to (y+ before- dy);
00337   }
00338 
00339   if (((type == "release-left") || (type == "release-middle")) &&
00340       (!ev->pressed ("left")) && (!ev->pressed ("middle"))) {
00341     gripped= scrolling= false;
00342     wk_ungrab_pointer (this);
00343   }
00344 }
00345 
00346 void
00347 ver_scrollbar_widget_rep::handle_alarm (alarm_event ev) {
00348   if (scrolling && (ev->message == "scroll")) {
00349     this << emit_bar_scroll_to (sc_pos + increment);
00350     win->delayed_message (this, "scroll", 10);
00351   }
00352 }
00353 
00354 void
00355 ver_scrollbar_widget_rep::handle_scroll (scroll_event ev) {
00356   if (ev->which != "this") WK_FAILED ("invalid scroll");
00357   ref << emit_ver_scroll (ev->c1, ev->c2, ev->c3);
00358 }