Back to index

texmacs  1.0.7.15
edit_graphics.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : edit_graphics.cpp
00004 * DESCRIPTION: graphics between the editor and the window manager
00005 * COPYRIGHT  : (C) 2003  Joris van der Hoeven and Henri Lesourd
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 "Interface/edit_graphics.hpp"
00013 #include "server.hpp"
00014 #include "scheme.hpp"
00015 #include "Graphics/curve.hpp"
00016 #include "Boxes/graphics.hpp"
00017 #include "Bridge/impl_typesetter.hpp"
00018 #include "drd_std.hpp"
00019 
00020 extern tree the_et;
00021 
00022 /******************************************************************************
00023 * Constructors and destructors
00024 ******************************************************************************/
00025 
00026 edit_graphics_rep::edit_graphics_rep () {
00027   gr_x= gr_y= 0.0;
00028   graphical_object= tree();
00029 }
00030 
00031 edit_graphics_rep::~edit_graphics_rep () {}
00032 
00033 /******************************************************************************
00034 * Extra subroutines for graphical selections
00035 ******************************************************************************/
00036 
00037 gr_selection
00038 snap_to_guide (point p, gr_selections sels, double eps) {
00039   if (N(sels) == 0) {
00040     gr_selection snap;
00041     snap->type= "free";
00042     snap->p= p;
00043     snap->dist= 0;
00044     return snap;
00045   }
00046 
00047   sort (sels);
00048   gr_selection best;
00049   best->type= "none";
00050   for (int i=0; i<N(sels); i++)
00051     if (sels[i]->type == "grid-point")
00052       best= sels[i];
00053     else if (is_nil (sels[i]->c))
00054       return sels[i];
00055 
00056   for (int i=0; i<N(sels); i++)
00057     for (int j=i+1; j<N(sels); j++) {
00058       if (!is_nil (sels[i]->c) &&
00059          !is_nil (sels[j]->c) &&
00060          (sels[i]->type != "grid-curve-point" ||
00061           sels[j]->type != "grid-curve-point"))
00062        {
00063          array<point> ins= intersection (sels[i]->c, sels[j]->c, p, eps);
00064          for (int k=0; k<N(ins); k++)
00065            if (best->type == "none" || norm (ins[k] - p) < best->dist) {
00066              gr_selection sel;
00067              sel->type= sels[i]->type * "&" * sels[j]->type;
00068              sel->p   = ins[k];
00069              sel->dist= norm (ins[k] - p);
00070              sel->cp  = append (sels[i]->cp, sels[j]->cp);
00071              sel->pts = append (sels[i]->pts, sels[j]->pts);
00072              best= sel;
00073            }
00074        }
00075     }
00076   
00077   if (best->type != "none") return best;
00078   return sels[0];
00079 }
00080 
00081 /******************************************************************************
00082 * Main edit_graphics routines
00083 ******************************************************************************/
00084 
00085 path
00086 edit_graphics_rep::graphics_path () {
00087   path gp= search_upwards (GRAPHICS);
00088   if (is_nil (gp)) return tp;
00089   return gp * 0;
00090 }
00091 
00092 bool
00093 edit_graphics_rep::inside_graphics (bool b) {
00094   path p   = path_up (tp);
00095   bool flag= false;
00096   tree st  = et;
00097   while (!is_nil (p)) {
00098     if (is_func (st, GRAPHICS)) flag= true;
00099     if (b && is_graphical_text (st)) flag= false;
00100     if (is_atomic (st) || p->item < 0 || p->item >= N(st)) break;
00101     st= st[p->item];
00102     p = p->next;
00103   }
00104   return flag || (L(st) == GRAPHICS);
00105 }
00106 
00107 bool
00108 edit_graphics_rep::inside_active_graphics (bool b) {
00109   return inside_graphics (b) && get_env_string (PREAMBLE) == "false";
00110 }
00111 
00112 bool
00113 edit_graphics_rep::over_graphics (SI x, SI y) {
00114   frame f= find_frame ();
00115   if (!is_nil (f)) {
00116     point lim1, lim2;
00117     find_limits (lim1, lim2);
00118     point p = adjust (f [point (x, y)]);
00119     // cout << type << " at " << p << " [" << lim1 << ", " << lim2 << "]\n";
00120     if (N(lim1) == 2)
00121       if ((p[0]<lim1[0]) || (p[0]>lim2[0]) || (p[1]<lim1[1]) || (p[1]>lim2[1]))
00122         return as_bool (call ("graphics-busy?"));
00123     return true;
00124   }
00125   return false;
00126 }
00127 
00128 tree
00129 edit_graphics_rep::get_graphics () {
00130   path p   = path_up (tp);
00131   tree st  = et;
00132   tree res = tree ();
00133   while (!is_nil (p)) {
00134     if (is_func (st, GRAPHICS)) res= st;
00135     st= st[p->item];
00136     p = p->next;
00137   }
00138   return res;
00139 }
00140 
00141 double
00142 edit_graphics_rep::get_x () {
00143   return gr_x;
00144 }
00145 
00146 double
00147 edit_graphics_rep::get_y () {
00148   return gr_y;
00149 }
00150 
00151 frame
00152 edit_graphics_rep::find_frame (bool last) {
00153   path gp= graphics_path ();
00154   bool bp_found;
00155   path bp= eb->find_box_path (gp, bp_found);
00156   if (bp_found) return eb->find_frame (path_up (bp), last);
00157   else return frame ();
00158 }
00159 
00160 grid
00161 edit_graphics_rep::find_grid () {
00162   path gp= graphics_path ();
00163   bool bp_found;
00164   path bp= eb->find_box_path (gp, bp_found);
00165   if (bp_found) return eb->find_grid (path_up (bp));
00166   else return grid ();
00167 }
00168 
00169 void
00170 edit_graphics_rep::find_limits (point& lim1, point& lim2) {
00171   path gp= graphics_path ();
00172   lim1= point (); lim2= point ();
00173   bool bp_found;
00174   path bp= eb->find_box_path (gp, bp_found);
00175   if (bp_found) eb->find_limits (path_up (bp), lim1, lim2);
00176 }
00177 
00178 bool
00179 edit_graphics_rep::find_graphical_region (SI& x1, SI& y1, SI& x2, SI& y2) {
00180   point lim1, lim2;
00181   find_limits (lim1, lim2);
00182   if (lim1 == point ()) return false;
00183   frame f= find_frame ();
00184   if (is_nil (f)) return false;
00185   point p1= f (point (lim1[0], lim1[1]));
00186   point p2= f (point (lim2[0], lim2[1]));
00187   x1= (SI) p1[0]; y1= (SI) p1[1];
00188   x2= (SI) p2[0]; y2= (SI) p2[1];
00189   return true;
00190 }
00191 
00192 point
00193 edit_graphics_rep::adjust (point p) {
00194   frame f= find_frame ();
00195   grid g= find_grid ();
00196   if (!is_nil (g) && !is_nil (gr0) && g != gr0) {
00197     graphical_select (p[0], p[1]);
00198     g= gr0;
00199   }
00200   if (is_nil (g)) return p;
00201   point res;
00202   gr_selections sels= copy (gs);
00203   frame f2= find_frame (true);
00204   if (is_nil (f2)) return p;
00205   point fp= f2 (p);
00206   if ((tree) g != "empty_grid") {
00207     point q= g->find_point_around (p, 10*get_pixel_size (), f);
00208     point fq= f2 (q);
00209     if (norm (fq - fp) < 10*get_pixel_size ()) {
00210       gr_selection sel;
00211       sel->type= "grid-point";
00212       sel->p   = fq;
00213       sel->dist= norm (fq - fp);
00214       sels << sel;
00215     }
00216     array<grid_curve> gc=
00217       g->get_curves_around (p, 10*get_pixel_size (), f);
00218     for (int i=0; i<N(gc); i++) {
00219       point fc= closest (f2 (gc[i]->c), fp);
00220       if (norm (fc - fp) < 10*get_pixel_size ()) {
00221         gr_selection sel;
00222         sel->type= "grid-curve-point";
00223         sel->p   = fc;
00224         sel->dist= norm (fc - fp);
00225         sel->c   = f2 (gc[i]->c);
00226         sels << sel;
00227       }
00228     }
00229   }
00230   double eps= get_pixel_size () / 10.0;
00231   gr_selection snap= snap_to_guide (fp, sels, eps);
00232   //cout << "Snap " << fp << " to " << snap << ", " << snap->p << "\n";
00233   point snapped= f2[snap->p];
00234   if (N(snapped) == 2) return snapped;
00235   return p;
00236   // FIXME: why can snapped be an invalid point?
00237 }
00238 
00239 tree
00240 edit_graphics_rep::find_point (point p) {
00241   return tree (_POINT, as_string (p[0]), as_string (p[1]));
00242 }
00243 
00244 tree
00245 edit_graphics_rep::graphical_select (double x, double y) { 
00246   frame f= find_frame ();
00247   if (is_nil (f)) return tuple ();
00248   gr_selections sels;
00249   point p0 = point (x, y);
00250   point p = f (p0);
00251   sels= eb->graphical_select ((SI)p[0], (SI)p[1], 10*get_pixel_size ());
00252   gs= sels;
00253   gr0= empty_grid ();
00254   grid g= find_grid ();
00255   frame f2= find_frame (true);
00256   if (!is_nil (g) && !is_nil (f2)) gr0= g;
00257   return as_tree (sels);
00258 }
00259 
00260 tree
00261 edit_graphics_rep::graphical_select (
00262   double x1, double y1, double x2, double y2)
00263 { 
00264   frame f= find_frame ();
00265   if (is_nil (f)) return tuple ();
00266   gr_selections sels;
00267   point p1 = f (point (x1, y1)), p2= f (point (x2, y2));
00268   sels= eb->graphical_select ((SI)p1[0], (SI)p1[1], (SI)p2[0], (SI)p2[1]);
00269   return as_tree (sels);
00270 }
00271 
00272 tree
00273 edit_graphics_rep::get_graphical_object () {
00274   return graphical_object;
00275 }
00276 
00277 void
00278 edit_graphics_rep::set_graphical_object (tree t) {
00279   go_box= box ();
00280   graphical_object= t;
00281   if (N (graphical_object) == 0) return;
00282   edit_env env= get_typesetter ()->env;
00283   //tree old_fr= env->local_begin (GR_FRAME, (tree) find_frame ());  
00284   frame f_env= env->fr;
00285   env->fr= find_frame ();
00286   if (!is_nil (env->fr)) {
00287     int i,n=0;
00288     go_box= typeset_as_concat (env, t, path (0));
00289     for (i=0; i<N(go_box); i++)
00290       if (go_box[i]!="") n++;
00291     if (n) {
00292       array<box> bx(n);
00293       n=0;
00294       for (i=0; i<N(go_box); i++) if (go_box[i]!="") {
00295        array<box> bx2(1);
00296        array<SI> spc2(1);
00297        bx2[0]= go_box[i];
00298        spc2[0]=0;
00299        bx[n]= concat_box (path (0), bx2, spc2);
00300        n++;
00301       }
00302       go_box= composite_box (path (0), bx);
00303     }
00304   }
00305   env->fr= f_env;
00306   //env->local_end (GR_FRAME, old_fr);
00307 }
00308 
00309 void
00310 edit_graphics_rep::invalidate_graphical_object () {
00311   SI gx1, gy1, gx2, gy2;
00312   if (find_graphical_region (gx1, gy1, gx2, gy2) && !is_nil (go_box)) {
00313     int i;
00314     rectangles rs;
00315     rectangle gr (gx1, gy1, gx2, gy2);
00316     for (i=0; i<go_box->subnr(); i++) {
00317       box b= go_box->subbox (i);
00318       rs= rectangles (rectangle (b->x3, b->y3, b->x4, b->y4), rs);
00319     }
00320     rs= rs & rectangles (gr);
00321     invalidate (rs);
00322   }
00323 }
00324 
00325 void
00326 edit_graphics_rep::draw_graphical_object (renderer ren) {
00327   if (is_nil (go_box)) set_graphical_object (graphical_object);
00328   if (is_nil (go_box)) return;
00329   SI ox1, oy1, ox2, oy2;
00330   ren->get_clipping (ox1, oy1, ox2, oy2);
00331   SI gx1, gy1, gx2, gy2;
00332   if (find_graphical_region (gx1, gy1, gx2, gy2))
00333     ren->extra_clipping (gx1, gy1, gx2, gy2);
00334   int i;
00335   for (i=0; i<go_box->subnr(); i++) {
00336     box b= go_box->subbox (i);
00337     if ((tree)b=="point" || (tree)b=="curve")
00338       b->display (ren);
00339     else {
00340       rectangles rs;
00341       b->redraw (ren, path (), rs);
00342     }
00343   }
00344   ren->set_clipping (ox1, oy1, ox2, oy2);
00345 }
00346 
00347 void
00348 edit_graphics_rep::back_in_text_at (tree t, path p, bool forward) {
00349   int i= last_item (p);
00350   if ((i == 0) && is_empty (t[0])) {
00351     p= path_up (p);
00352     if (is_func (subtree (et, path_up (p)), WITH)) p= path_up (p);
00353     tree st= subtree (et, path_up (p));
00354     if (is_func (st, GRAPHICS)) {
00355       if (N(st) == 1) assign (p, "");
00356       else {
00357         remove (p, 1);
00358         go_to_border (path_up (p) * 0, true);
00359       }
00360     }
00361   }
00362 }
00363 
00364 bool
00365 edit_graphics_rep::mouse_graphics (string type, SI x, SI y, int m, time_t t) {
00366   //cout << type << ", " << x << ", " << y << ", " << m << ", " << t << "\n";
00367   //cout << "et= " << et << "\n";
00368   //cout << "tp= " << tp << "\n";
00369   //cout << "gp= " << graphics_path () << "\n";
00370   (void) t;
00371   // apply_changes (); // FIXME: remove after review of synchronization
00372   frame f= find_frame ();
00373   if (!is_nil (f)) {
00374     if (!over_graphics (x, y))
00375       return false;
00376     if (type == "move" || type == "dragging-left")
00377       if (check_event (MOTION_EVENT))
00378        return true;
00379     point p = f [point (x, y)];
00380     graphical_select (p[0], p[1]); // init the caching for adjust().
00381     p= adjust (p);
00382     gr_x= p[0];
00383     gr_y= p[1];
00384     string sx= as_string (p[0]);
00385     string sy= as_string (p[1]);
00386     invalidate_graphical_object ();
00387     call ("set-keyboard-modifiers", object (m));
00388     if (type == "move")
00389       call ("graphics-move", sx, sy);
00390     else if (type == "release-left" || type == "double-left")
00391       call ("graphics-release-left", sx, sy);
00392     else if (type == "release-middle")
00393       call ("graphics-release-middle", sx, sy);
00394     else if (type == "release-right" || type == "double-right")
00395       call ("graphics-release-right", sx, sy);
00396     else if (type == "start-drag-left")
00397       call ("graphics-start-drag-left", sx, sy);
00398     else if (type == "dragging-left")
00399       call ("graphics-dragging-left", sx, sy);
00400     else if (type == "end-drag-left")
00401       call ("graphics-end-drag-left", sx, sy);
00402     else if (type == "start-drag-right")
00403       call ("graphics-start-drag-right", sx, sy);
00404     else if (type == "dragging-right")
00405       call ("graphics-dragging-right", sx, sy);
00406     else if (type == "end-drag-right")
00407       call ("graphics-end-drag-right", sx, sy);
00408     invalidate_graphical_object ();
00409     notify_change (THE_CURSOR);
00410     return true;
00411   }
00412   //cout << "No frame " << tp << ", " << subtree (et, path_up (tp)) << "\n";
00413   return false;
00414 }