1
2 /******************************************************************************
3 * MODULE : edit_interface.cpp
4 * DESCRIPTION: interface between the editor and the window manager
5 * COPYRIGHT : (C) 1999 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11
12 #include "Interface/edit_interface.hpp"
13 #include "file.hpp"
14 #include "convert.hpp"
15 #include "server.hpp"
16 #include "tm_window.hpp"
17 #include "Metafont/tex_files.hpp"
18 #include "data_cache.hpp"
19 #include "drd_mode.hpp"
20 #include "message.hpp"
21 #include "tree_traverse.hpp"
22 #include "boot.hpp"
23 #ifdef EXPERIMENTAL
24 #include "../../Style/Evaluate/evaluate_main.hpp"
25 #endif
26 #include "gui.hpp" // for gui_interrupted
27
28 extern void (*env_next_prog)(void);
29
30 /*static*/ string
MODE_LANGUAGE(string mode)31 MODE_LANGUAGE (string mode) {
32 if (mode == "text") return LANGUAGE;
33 else if (mode == "math") return MATH_LANGUAGE;
34 else if (mode == "prog") return PROG_LANGUAGE;
35 else if (mode == "src") return LANGUAGE;
36 std_error << "Invalid mode " << mode << ", assuming text mode instead\n";
37 return LANGUAGE;
38 }
39
40 /******************************************************************************
41 * Main edit_interface routines
42 ******************************************************************************/
43
edit_interface_rep()44 edit_interface_rep::edit_interface_rep ():
45 env_change (0),
46 last_change (texmacs_time()), last_update (last_change-1),
47 do_animate (false), next_animate (last_change-1),
48 full_screen (false), got_focus (false),
49 sh_s (""), sh_mark (0), pre_edit_s (""), pre_edit_mark (0),
50 popup_win (),
51 message_l (""), message_r (""), last_l (""), last_r (""),
52 zoomf (sv->get_default_zoom_factor ()),
53 magf (zoomf / std_shrinkf),
54 pixel ((SI) tm_round ((std_shrinkf * PIXEL) / zoomf)), copy_always (),
55 last_x (0), last_y (0), last_t (0),
56 table_selection (false), mouse_adjusting (false),
57 oc (0, 0), temp_invalid_cursor (false),
58 shadow (NULL), stored (NULL),
59 cur_sb (2), cur_wb (2)
60 {
61 input_mode= INPUT_NORMAL;
62 gui_root_extents (cur_wx, cur_wy);
63 }
64
~edit_interface_rep()65 edit_interface_rep::~edit_interface_rep () {
66 if (shadow != NULL) tm_delete (shadow);
67 if (stored != NULL) tm_delete (stored);
68 shadow = NULL;
69 stored = NULL;
70 }
71
operator tree()72 edit_interface_rep::operator tree () {
73 return tuple ("editor", as_string (get_name ()));
74 }
75
76 void
suspend()77 edit_interface_rep::suspend () {
78 if (got_focus) {
79 interrupt_shortcut ();
80 set_message ("", "", false);
81 }
82 got_focus= false;
83 notify_change (THE_FOCUS);
84 if (shadow != NULL) tm_delete (shadow);
85 if (stored != NULL) tm_delete (stored);
86 shadow = NULL;
87 stored = NULL;
88 }
89
90 void
resume()91 edit_interface_rep::resume () {
92 got_focus= true;
93 SERVER (menu_main ("(horizontal (link texmacs-menu))"));
94 SERVER (menu_icons (0, "(horizontal (link texmacs-main-icons))"));
95 SERVER (menu_icons (1, "(horizontal (link texmacs-mode-icons))"));
96 SERVER (menu_icons (2, "(horizontal (link texmacs-focus-icons))"));
97 SERVER (menu_icons (3, "(horizontal (link texmacs-extra-icons))"));
98 if (use_side_tools)
99 { SERVER (side_tools (0, "(vertical (link texmacs-side-tools))")); }
100 SERVER (bottom_tools (0, "(vertical (link texmacs-bottom-tools))"));
101 cur_sb= 2;
102 notify_change (THE_FOCUS + THE_EXTENTS);
103 path new_tp= make_cursor_accessible (tp, true);
104 if (new_tp != tp) {
105 notify_change (THE_CURSOR);
106 tp= new_tp;
107 }
108 }
109
110 void
keyboard_focus_on(string field)111 edit_interface_rep::keyboard_focus_on (string field) {
112 array<url> a= buffer_to_windows (buf->buf->name);
113 if (N(a) >= 1) {
114 tm_window win= concrete_window (a[0]);
115 send_keyboard_focus_on (win->wid, field);
116 }
117 }
118
119 /******************************************************************************
120 * Routines for dealing with shrinked coordinates
121 ******************************************************************************/
122
123 int
get_pixel_size()124 edit_interface_rep::get_pixel_size () {
125 return pixel;
126 }
127
128 void
set_zoom_factor(double zoom)129 edit_interface_rep::set_zoom_factor (double zoom) {
130 zoomf = zoom;
131 magf = zoomf / std_shrinkf;
132 pixel = (int) tm_round ((std_shrinkf * PIXEL) / zoomf);
133 }
134
135 void
invalidate(SI x1,SI y1,SI x2,SI y2)136 edit_interface_rep::invalidate (SI x1, SI y1, SI x2, SI y2) {
137 send_invalidate (this, (SI) floor (x1*magf), (SI) floor (y1*magf),
138 (SI) ceil (x2*magf), (SI) ceil (y2*magf));
139 }
140
141 void
invalidate(rectangles rs)142 edit_interface_rep::invalidate (rectangles rs) {
143 while (!is_nil (rs)) {
144 invalidate (rs->item->x1-pixel, rs->item->y1-pixel,
145 rs->item->x2+pixel, rs->item->y2+pixel);
146 rs= rs->next;
147 }
148 }
149
150 void
invalidate_all()151 edit_interface_rep::invalidate_all () {
152 send_invalidate_all (this);
153 }
154
155 void
update_visible()156 edit_interface_rep::update_visible () {
157 SERVER (get_visible (vx1, vy1, vx2, vy2));
158 vx1= (SI) (vx1 / magf); vy1= (SI) (vy1 / magf);
159 vx2= (SI) (vx2 / magf); vy2= (SI) (vy2 / magf);
160 }
161
162 SI
get_visible_width()163 edit_interface_rep::get_visible_width () {
164 update_visible ();
165 return vx2 - vx1;
166 }
167
168 SI
get_visible_height()169 edit_interface_rep::get_visible_height () {
170 update_visible ();
171 return vy2 - vy1;
172 }
173
174 #ifdef QTTEXMACS
175 #include <QApplication>
176 #include <QStyle>
177 static SI
scrollbar_width()178 scrollbar_width () {
179 return (qApp->style()->pixelMetric (QStyle::PM_ScrollBarExtent) + 2) * PIXEL;
180 }
181 #else
182 static SI
scrollbar_width()183 scrollbar_width () {
184 return 20 * PIXEL;
185 }
186 #endif
187
188 SI
get_window_width()189 edit_interface_rep::get_window_width () {
190 SI w, h;
191 widget me= ::get_canvas (widget (cvw));
192 ::get_size (me, w, h);
193 bool sb= (get_init_string (SCROLL_BARS) != "false");
194 if (full_screen) {
195 string medium= get_init_string (PAGE_MEDIUM);
196 if (medium == "automatic" || medium == "beamer") sb= false;
197 }
198 if (sb) w -= scrollbar_width ();
199 return w;
200 }
201
202 SI
get_window_height()203 edit_interface_rep::get_window_height () {
204 SI w, h;
205 widget me= ::get_canvas (widget (cvw));
206 ::get_size (me, w, h);
207 return h;
208 }
209
210 void
scroll_to(SI x,SI y)211 edit_interface_rep::scroll_to (SI x, SI y) {
212 stored_rects= rectangles ();
213 copy_always = rectangles ();
214 SERVER (scroll_to ((SI) (x * magf), ((SI) (y * magf))));
215 }
216
217 void
set_extents(SI x1,SI y1,SI x2,SI y2)218 edit_interface_rep::set_extents (SI x1, SI y1, SI x2, SI y2) {
219 stored_rects= rectangles ();
220 copy_always = rectangles ();
221 SERVER (set_extents ((SI) floor (x1*magf), (SI) floor (y1*magf),
222 (SI) ceil (x2*magf), (SI) ceil (y2*magf)));
223 }
224
225 /******************************************************************************
226 * Scroll so as to make the cursor and the selection visible
227 ******************************************************************************/
228
229 void
cursor_visible()230 edit_interface_rep::cursor_visible () {
231 path sp= find_innermost_scroll (eb, tp);
232 cursor cu= get_cursor ();
233 if (is_nil (sp)) {
234 update_visible ();
235 cu->y1 -= 2*pixel; cu->y2 += 2*pixel;
236 if ((cu->ox+ ((SI) (cu->y1 * cu->slope)) < vx1) ||
237 (cu->ox+ ((SI) (cu->y2 * cu->slope)) >= vx2) ||
238 (cu->oy+ cu->y1 < vy1) ||
239 (cu->oy+ cu->y2 >= vy2))
240 {
241 scroll_to (cu->ox, cu->oy);
242 send_invalidate_all (this);
243 }
244 }
245 else {
246 SI x, y, sx, sy;
247 rectangle outer, inner;
248 find_canvas_info (eb, sp, x, y, sx, sy, outer, inner);
249 if ((cu->ox+ ((SI) (cu->y1 * cu->slope)) < x + outer->x1) ||
250 (cu->ox+ ((SI) (cu->y2 * cu->slope)) > x + outer->x2))
251 {
252 SI tx= inner->x2 - inner->x1;
253 SI cx= outer->x2 - outer->x1;
254 if (tx > cx) {
255 SI outer_cx= cu->ox - x;
256 SI inner_cx= outer_cx - sx;
257 SI dx= inner_cx - inner->x1;
258 double p= 100.0 * ((double) (dx - (cx>>1))) / ((double) (tx-cx));
259 p= max (min (p, 100.0), 0.0);
260 tree old_xt= eb[path_up (sp)]->get_info ("scroll-x");
261 tree new_xt= as_string (p) * "%";
262 if (new_xt != old_xt && is_accessible (obtain_ip (old_xt))) {
263 object fun= symbol_object ("tree-set");
264 object cmd= list_object (fun, old_xt, new_xt);
265 exec_delayed (scheme_cmd (cmd));
266 temp_invalid_cursor= true;
267 }
268 }
269 }
270 if ((cu->oy+ cu->y1 < y + outer->y1) ||
271 (cu->oy+ cu->y2 > y + outer->y2))
272 {
273 SI ty= inner->y2 - inner->y1;
274 SI cy= outer->y2 - outer->y1;
275 if (ty > cy) {
276 SI outer_cy= cu->oy + ((cu->y1 + cu->y2) >> 1) - y;
277 SI inner_cy= outer_cy - sy;
278 SI dy= inner_cy - inner->y1;
279 double p= 100.0 * ((double) (dy - (cy>>1))) / ((double) (ty-cy));
280 p= max (min (p, 100.0), 0.0);
281 tree old_yt= eb[path_up (sp)]->get_info ("scroll-y");
282 tree new_yt= as_string (p) * "%";
283 if (new_yt != old_yt && is_accessible (obtain_ip (old_yt))) {
284 object fun= symbol_object ("tree-set");
285 object cmd= list_object (fun, old_yt, new_yt);
286 exec_delayed (scheme_cmd (cmd));
287 temp_invalid_cursor= true;
288 }
289 }
290 }
291 }
292 }
293
294 void
selection_visible()295 edit_interface_rep::selection_visible () {
296 update_visible ();
297 if ((vx2 - vx1 <= 80*pixel) || (vy2 - vy1 <= 80*pixel)) return;
298
299 SI extra= (cur_sb == 1? 20 * pixel: 0);
300 bool scroll_x= (end_x < vx1 + extra) || (end_x >= vx2 - extra);
301 bool scroll_y= (end_y < vy1 + extra) || (end_y >= vy2 - extra);
302 SI new_x= vx1;
303 if (scroll_x) new_x= end_x - ((vx2-vx1)>>1);
304 SI new_y= vy2;
305 if (scroll_y) new_y= end_y + ((vy2-vy1)>>1);
306
307 if (scroll_x || scroll_y) {
308 scroll_to (new_x, new_y);
309 send_invalidate_all (this);
310 SI old_vx1= vx1, old_vy1= vy1;
311 update_visible ();
312 end_x += vx1- old_vx1;
313 end_y += vy1- old_vy1;
314 }
315 }
316
317 /******************************************************************************
318 * Computation of environment rectangles
319 ******************************************************************************/
320
321 static bool
is_graphical(tree t)322 is_graphical (tree t) {
323 return
324 is_func (t, _POINT) ||
325 is_func (t, LINE) || is_func (t, CLINE) ||
326 is_func (t, ARC) || is_func (t, CARC) ||
327 is_func (t, SPLINE) || is_func (t, CSPLINE);
328 }
329
330 static void
correct_adjacent(rectangles & rs1,rectangles & rs2)331 correct_adjacent (rectangles& rs1, rectangles& rs2) {
332 if (N(rs1) != 1 || N(rs2) != 1) return;
333 SI bot1= rs1->item->y1;
334 SI top2= rs2->item->y2;
335 if (rs1->item->y1 <= rs2->item->y1) {
336 //cout << "Discard " << rs1->item->y1 << ", " << rs2->item->y1 << "\n";
337 return;
338 }
339 if (rs1->item->y2 <= rs2->item->y2) {
340 //cout << "Discard " << rs1->item->y2 << ", " << rs2->item->y2 << "\n";
341 return;
342 }
343 SI mid= (bot1 + top2) >> 1;
344 rs1->item->y1= mid;
345 rs2->item->y2= mid;
346 }
347
348 void
compute_env_rects(path p,rectangles & rs,bool recurse)349 edit_interface_rep::compute_env_rects (path p, rectangles& rs, bool recurse) {
350 if (p == rp) return;
351 tree st= subtree (et, p);
352 if ((is_func (st, TABLE) || is_func (st, SUBTABLE)) &&
353 recurse && get_preference ("show table cells") == "on") {
354 rectangles rl;
355 for (int i=0; i<N(st); i++) {
356 if (is_func (st[i], ROW))
357 for (int j=0; j<N(st[i]); j++) {
358 selection sel= eb->find_check_selection (p*i*j*0, p*i*j*1);
359 rectangles rsel= copy (thicken (sel->rs, 0, 2 * pixel));
360 if (i > 0 && is_func (st[i-1], ROW) && j < N(st[i-1])) {
361 selection bis= eb->find_check_selection (p*(i-1)*j*0, p*(i-1)*j*1);
362 rectangles rbis= copy (thicken (bis->rs, 0, 2 * pixel));
363 correct_adjacent (rbis, rsel);
364 }
365 if (i+1 < N(st) && is_func (st[i+1], ROW) && j < N(st[i+1])) {
366 selection bis= eb->find_check_selection (p*(i+1)*j*0, p*(i+1)*j*1);
367 rectangles rbis= copy (thicken (bis->rs, 0, 2 * pixel));
368 correct_adjacent (rsel, rbis);
369 }
370 rectangles selp= thicken (rsel, pixel/2, pixel/2);
371 rectangles selm= thicken (rsel, -pixel/2, -pixel/2);
372 rl << simplify (::correct (selp - selm));
373 }
374 }
375 rs << simplify (rl);
376 if (recurse) compute_env_rects (path_up (p), rs, recurse);
377 }
378 else if (is_atomic (st) ||
379 drd->is_child_enforcing (st) ||
380 //is_document (st) || is_concat (st) ||
381 is_func (st, TABLE) || is_func (st, SUBTABLE) ||
382 is_func (st, ROW) || is_func (st, TFORMAT) ||
383 is_graphical (st) ||
384 (is_func (st, WITH) && is_graphical (st[N(st)-1])) ||
385 (is_func (st, WITH) && is_graphical_text (st[N(st)-1])) ||
386 is_compound (st, "shared", 3) ||
387 (is_compound (st, "math", 1) &&
388 is_compound (subtree (et, path_up (p)), "input")))
389 compute_env_rects (path_up (p), rs, recurse);
390 else {
391 int new_mode= DRD_ACCESS_NORMAL;
392 if (get_init_string (MODE) == "src") new_mode= DRD_ACCESS_SOURCE;
393 int old_mode= set_access_mode (new_mode);
394 tree st= subtree (et, p);
395 if (is_accessible_cursor (et, p * right_index (st)) || in_source ()) {
396 bool right;
397 path p1= p * 0, p2= p * 1, q1, q2;
398 if (is_script (subtree (et, p), right) ||
399 is_func (st, TEXT_AT) ||
400 is_func (st, MATH_AT))
401 {
402 p1= start (et, p * 0);
403 p2= end (et, p * 0);
404 }
405 if (is_func (st, CELL)) { q1= p1; q2= p2; }
406 else selection_correct (p1, p2, q1, q2);
407 selection sel= eb->find_check_selection (q1, q2);
408 if (N(focus_get ()) >= N(p))
409 if (!recurse || get_preference ("show full context") == "on")
410 rs << outline (sel->rs, pixel);
411 }
412 set_access_mode (old_mode);
413 if (recurse || N(rs) == 0)
414 compute_env_rects (path_up (p), rs, recurse);
415 }
416 }
417
418 /******************************************************************************
419 * handling changes
420 ******************************************************************************/
421
422 void
notify_change(int change)423 edit_interface_rep::notify_change (int change) {
424 env_change= env_change | change;
425 needs_update ();
426 if ((change & (THE_TREE | THE_SELECTION | THE_CURSOR)) != 0)
427 manual_focus_set (path (), (change & THE_TREE) != 0);
428 }
429
430 bool
has_changed(int question)431 edit_interface_rep::has_changed (int question) {
432 return (env_change & question) != 0;
433 }
434
435 int
idle_time(int event_type)436 edit_interface_rep::idle_time (int event_type) {
437 if (env_change == 0 &&
438 got_focus &&
439 (!query_invalid (this)) &&
440 (!check_event (event_type)))
441 return texmacs_time () - last_change;
442 else return 0;
443 }
444
445 int
change_time()446 edit_interface_rep::change_time () {
447 return last_change;
448 }
449
450 void
apply_changes()451 edit_interface_rep::apply_changes () {
452 //cout << "Apply changes\n";
453 //cout << "et= " << et << "\n";
454 //cout << "tp= " << tp << "\n";
455 //cout << HRULE << "\n";
456 if (env_change == 0) {
457 if (last_change-last_update > 0 &&
458 idle_time (INTERRUPTED_EVENT) >= 1000/6)
459 {
460 SERVER (menu_main ("(horizontal (link texmacs-menu))"));
461 SERVER (menu_icons (0, "(horizontal (link texmacs-main-icons))"));
462 SERVER (menu_icons (1, "(horizontal (link texmacs-mode-icons))"));
463 SERVER (menu_icons (2, "(horizontal (link texmacs-focus-icons))"));
464 SERVER (menu_icons (3, "(horizontal (link texmacs-extra-icons))"));
465 if (use_side_tools)
466 { SERVER (side_tools (0, "(vertical (link texmacs-side-tools))")); }
467 SERVER (bottom_tools (0, "(vertical (link texmacs-bottom-tools))"));
468 set_footer ();
469 if (has_current_window ()) {
470 array<url> ws= buffer_to_windows (
471 window_to_buffer (
472 abstract_window (concrete_window ())));
473 int n= N(ws);
474 bool ns= need_save ();
475 for (int i=0; i<n; i++)
476 concrete_window (ws[i])->set_modified (ns);
477 }
478 if (!gui_interrupted ()) drd_update ();
479 cache_memorize ();
480 last_update= last_change;
481 save_user_preferences ();
482 }
483 return;
484 }
485
486 // cout << "Applying changes " << env_change << " to " << get_name() << "\n";
487 // time_t t1= texmacs_time ();
488
489 // cout << "Always\n";
490 update_visible ();
491
492 // cout << "Handling automatic resizing\n";
493 int sb= 1;
494 if (is_attached (this) && has_current_window ()) {
495 tree new_zoom= as_string (zoomf);
496 tree old_zoom= get_init_value (ZOOM_FACTOR);
497 if (new_zoom != old_zoom) {
498 init_env (ZOOM_FACTOR, new_zoom);
499 notify_change (THE_ENVIRONMENT);
500 }
501 }
502 if (is_attached (this) &&
503 has_current_window () &&
504 get_init_string (PAGE_MEDIUM) == "automatic")
505 {
506 SI wx, wy;
507 if (cvw == NULL) ::get_size (get_window (this), wx, wy);
508 else ::get_size (widget (cvw), wx, wy);
509 if (get_init_string (SCROLL_BARS) == "false") sb= 0;
510 if (get_server () -> in_full_screen_mode ()) sb= 0;
511 if (sb) wx -= scrollbar_width();
512 if (wx != cur_wx || wy != cur_wy) {
513 cur_wx= wx; cur_wy= wy;
514 init_env (PAGE_SCREEN_WIDTH, as_string ((SI) (wx/magf)) * "tmpt");
515 init_env (PAGE_SCREEN_HEIGHT, as_string ((SI) (wy/magf)) * "tmpt");
516 notify_change (THE_ENVIRONMENT);
517 }
518 }
519 if (get_init_string (PAGE_MEDIUM) == "beamer" && full_screen) sb= 0;
520 if (sb != cur_sb) {
521 cur_sb= sb;
522 if (has_current_window ())
523 concrete_window () -> set_scrollbars (sb);
524 }
525
526 // window decorations (menu bar, icon bars, footer)
527 int wb= 2;
528 if (is_attached (this)) {
529 string val= get_init_string (WINDOW_BARS);
530 if (val == "auto") wb= 2;
531 else if (val == "false") wb= 0;
532 else if (val == "true") wb= 1;
533 if (wb != cur_wb) {
534 cur_wb= wb;
535 if (wb != 2) {
536 get_server () -> show_header (wb);
537 get_server () -> show_footer (wb);
538 }
539 }
540 }
541
542 // cout << "Handling selection\n";
543 if (env_change & (THE_TREE+THE_ENVIRONMENT+THE_SELECTION)) {
544 if (!is_nil (selection_rects)) {
545 invalidate (selection_rects);
546 if (!selection_active_any ()) {
547 set_selection (tp, tp);
548 selection_rects= rectangles ();
549 }
550 }
551 if (N (alt_selection_rects) != 0) {
552 rectangles visible (rectangle (vx1, vy1, vx2, vy2));
553 for (int i=0; i<N(alt_selection_rects); i++)
554 invalidate (alt_selection_rects[i] & visible);
555 range_set alt_sel= append (get_alt_selection ("alternate"),
556 get_alt_selection ("brackets"));
557 if (is_empty (alt_sel))
558 alt_selection_rects= array<rectangles> ();
559 }
560 }
561
562 // cout << "Handling environment\n";
563 if (env_change & THE_ENVIRONMENT)
564 typeset_invalidate_all ();
565
566 // cout << "Handling tree\n";
567 if (env_change & (THE_TREE+THE_ENVIRONMENT)) {
568 typeset_invalidate_env ();
569 SI x1, y1, x2, y2;
570 typeset (x1, y1, x2, y2);
571 invalidate (x1- 2*pixel, y1- 2*pixel, x2+ 2*pixel, y2+ 2*pixel);
572 // check_data_integrety ();
573 the_ghost_cursor()= eb->find_check_cursor (tp);
574 }
575
576 #ifdef EXPERIMENTAL
577 if (env_change & THE_ENVIRONMENT)
578 environment_update ();
579 if (env_change & THE_TREE) {
580 cout << HRULE;
581 mem= evaluate (ste, cct);
582 tree rew= mem->get_tree ();
583 cout << HRULE;
584 cout << tree_to_texmacs (rew) << LF;
585 //print_tree (rew);
586 }
587 #endif
588
589 // cout << "Handling extents\n";
590 if (env_change & (THE_TREE+THE_ENVIRONMENT+THE_EXTENTS)) {
591 string medium= get_init_string (PAGE_MEDIUM);
592 SI ex1= (SI) (((double) eb->x1) * magf);
593 SI ey1= (SI) (((double) eb->y1) * magf);
594 SI ex2= (SI) (((double) eb->x2) * magf);
595 SI ey2= (SI) (((double) eb->y2) * magf);
596 abs_round (ex1, ey1);
597 abs_round (ex2, ey2);
598 SI w, h;
599 widget me= ::get_canvas (widget (cvw));
600 ::get_size (me, w, h);
601 #ifdef X11TEXMACS
602 w -= 2*PIXEL;
603 h -= 2*PIXEL;
604 #endif
605 if (cur_sb && ey2 - ey1 > h) w -= scrollbar_width ();
606 if (cur_sb && ex2 - ex1 > w) h -= scrollbar_width ();
607 if (ex2 - ex1 <= w + 2*PIXEL) {
608 if (medium == "automatic" ||
609 (medium == "beamer" && full_screen))
610 ex2= ex1 + w;
611 else {
612 #ifdef X11TEXMACS
613 ex1= (ex1 + ex2 - w) / 2;
614 abs_round (ex1);
615 ex2= ex1 + w;
616 #endif
617 }
618 }
619 if (ey2 - ey1 <= h + 2*PIXEL) {
620 if (medium == "papyrus" || medium == "automatic" ||
621 (medium == "beamer" && full_screen))
622 ey1= ey2 - h;
623 else {
624 #ifdef X11TEXMACS
625 ey1= (ey1 + ey2 - h) / 2;
626 abs_round (ey1);
627 ey2= ey1 + h;
628 #endif
629 }
630 }
631 SERVER (set_extents (ex1, ey1, ex2, ey2));
632 //set_extents (eb->x1, eb->y1, eb->x2, eb->y2);
633 }
634
635 // cout << "Cursor\n";
636 temp_invalid_cursor= false;
637 if (env_change & (THE_TREE+THE_ENVIRONMENT+THE_EXTENTS+
638 THE_CURSOR+THE_SELECTION+THE_FOCUS)) {
639 SI /*P1= pixel,*/ P2= 2*pixel, P3= 3*pixel;
640 int THE_CURSOR_BAK= env_change & THE_CURSOR;
641 go_to_here ();
642 env_change= (env_change & (~THE_CURSOR)) | THE_CURSOR_BAK;
643 if (env_change & (THE_TREE+THE_ENVIRONMENT+THE_EXTENTS+THE_CURSOR))
644 if (!inside_active_graphics ())
645 cursor_visible ();
646
647 cursor cu= get_cursor();
648 rectangle ocr (oc->ox+ ((SI) (oc->y1*oc->slope))- P3, oc->oy+ oc->y1- P3,
649 oc->ox+ ((SI) (oc->y2*oc->slope))+ P2, oc->oy+ oc->y2+ P3);
650 copy_always= rectangles (ocr, copy_always);
651 invalidate (ocr->x1, ocr->y1, ocr->x2, ocr->y2);
652 rectangle ncr (cu->ox+ ((SI) (cu->y1*cu->slope))- P3, cu->oy+ cu->y1- P3,
653 cu->ox+ ((SI) (cu->y2*cu->slope))+ P2, cu->oy+ cu->y2+ P3);
654 invalidate (ncr->x1, ncr->y1, ncr->x2, ncr->y2);
655 copy_always= rectangles (ncr, copy_always);
656 oc= copy (cu);
657
658 // set hot spot in the gui
659 send_cursor (this, (SI) floor (cu->ox * magf),
660 (SI) floor (cu->oy * magf));
661
662 path sp= selection_get_cursor_path ();
663 bool semantic_flag= semantic_active (path_up (sp));
664 bool full_context= (get_preference ("show full context") == "on");
665 bool table_cells= (get_preference ("show table cells") == "on");
666 bool show_focus= (get_preference ("show focus") == "on");
667 bool semantic_only= (get_preference ("show only semantic focus") == "on");
668 rectangles old_env_rects= env_rects;
669 rectangles old_foc_rects= foc_rects;
670 env_rects= rectangles ();
671 foc_rects= rectangles ();
672 path pp= path_up (tp);
673 tree pt= subtree (et, pp);
674 if (none_accessible (pt));
675 else pp= path_up (pp);
676 if (full_context || table_cells)
677 compute_env_rects (pp, env_rects, true);
678 if (show_focus && (!semantic_flag || !semantic_only))
679 compute_env_rects (pp, foc_rects, false);
680 if (env_rects != old_env_rects) {
681 invalidate (old_env_rects);
682 invalidate (env_rects);
683 }
684 else if (env_change & THE_FOCUS) invalidate (env_rects);
685 if (foc_rects != old_foc_rects) {
686 invalidate (old_foc_rects);
687 invalidate (foc_rects);
688 }
689 else if (env_change & THE_FOCUS) invalidate (foc_rects);
690
691 rectangles old_sem_rects= sem_rects;
692 bool old_sem_correct= sem_correct;
693 sem_rects= rectangles ();
694 sem_correct= true;
695 if (semantic_flag && show_focus) {
696 path sp= selection_get_cursor_path ();
697 path p1= tp, p2= tp;
698 if (selection_active_any ()) selection_get (p1, p2);
699 sem_correct= semantic_select (path_up (sp), p1, p2, 2);
700 if (!sem_correct) {
701 path sr= semantic_root (path_up (sp));
702 p1= start (et, sr);
703 p2= end (et, sr);
704 }
705 path q1, q2;
706 selection_correct (p1, p2, q1, q2);
707 selection sel= eb->find_check_selection (q1, q2);
708 sem_rects << outline (sel->rs, pixel);
709 }
710 if (sem_rects != old_sem_rects || sem_correct != old_sem_correct) {
711 invalidate (old_sem_rects);
712 invalidate (sem_rects);
713 }
714 else if (env_change & THE_FOCUS) invalidate (sem_rects);
715
716 invalidate_graphical_object ();
717 }
718
719 // cout << "Handling selection\n";
720 if (env_change & THE_SELECTION) {
721 if (selection_active_any ()) {
722 table_selection= selection_active_table ();
723 selection sel; selection_get (sel);
724 rectangles rs= thicken (sel->rs, pixel, 3*pixel);
725 #ifndef QTTEXMACS
726 rs= simplify (::correct (rs - thicken (rs, -pixel, -pixel)));
727 #endif
728 selection_rects= rs;
729 invalidate (selection_rects);
730 }
731 range_set alt_sel= append (get_alt_selection ("alternate"),
732 get_alt_selection ("brackets"));
733 if (!is_empty (alt_sel)) {
734 alt_selection_rects= array<rectangles> ();
735 for (int i=0; i+1<N(alt_sel); i+=2) {
736 range_set sub_sel= simple_range (alt_sel[i], alt_sel[i+1]);
737 selection sel= compute_selection (sub_sel);
738 rectangles rs= thicken (sel->rs, pixel, 3*pixel);
739 #ifndef QTTEXMACS
740 rs= simplify (::correct (rs - thicken (rs, -pixel, -pixel)));
741 #endif
742 if (N(rs) != 0) alt_selection_rects << rs;
743 }
744 rectangles visible (rectangle (vx1, vy1, vx2, vy2));
745 for (int i=0; i<N(alt_selection_rects); i++)
746 invalidate (alt_selection_rects[i] & visible);
747 }
748 }
749
750 // cout << "Handling locus highlighting\n";
751 if (env_change & (THE_TREE+THE_ENVIRONMENT+THE_EXTENTS)) {
752 update_mouse_loci ();
753 update_focus_loci ();
754 }
755 if (env_change & THE_LOCUS) {
756 if (locus_new_rects != locus_rects) {
757 invalidate (locus_rects);
758 invalidate (locus_new_rects);
759 locus_rects= locus_new_rects;
760 }
761 }
762
763 // cout << "Handling backing store\n";
764 if (!is_nil (stored_rects)) {
765 if (env_change & (THE_TREE+THE_ENVIRONMENT+THE_SELECTION+THE_EXTENTS))
766 stored_rects= rectangles ();
767 }
768 if (inside_active_graphics ()) {
769 SI gx1, gy1, gx2, gy2;
770 if (find_graphical_region (gx1, gy1, gx2, gy2)) {
771 rectangle gr= rectangle (gx1, gy1, gx2, gy2);
772 if (!is_nil (gr - stored_rects))
773 invalidate (gx1, gy1, gx2, gy2);
774 }
775 }
776
777 // cout << "Handling environment changes\n";
778 if (env_change & THE_ENVIRONMENT)
779 send_invalidate_all (this);
780
781 // cout << "Applied changes\n";
782 // time_t t2= texmacs_time ();
783 // if (t2 - t1 >= 10) cout << "apply_changes took " << t2-t1 << "ms\n";
784 env_change = 0;
785 last_change = texmacs_time ();
786 last_update = last_change-1;
787 manual_focus_release ();
788 }
789
790 /******************************************************************************
791 * Animations
792 ******************************************************************************/
793
794 void
animate()795 edit_interface_rep::animate () {
796 // cout << do_animate << ", " << next_animate << "\n";
797 if (do_animate && texmacs_time () - next_animate >= 0) {
798 bool flag= false;
799 time_t at= 0;
800 rectangles rs;
801 eb->anim_get_invalid (flag, at, rs);
802 if (flag && texmacs_time () - at >= 0)
803 invalidate (rs);
804 do_animate = flag;
805 next_animate= at;
806 }
807 }
808
809 /******************************************************************************
810 * Miscellaneous routines
811 ******************************************************************************/
812
813 void
full_screen_mode(bool flag)814 edit_interface_rep::full_screen_mode (bool flag) {
815 full_screen= flag;
816 send_invalidate_all (this);
817 }
818
819 void
before_menu_action()820 edit_interface_rep::before_menu_action () {
821 archive_state ();
822 start_editing ();
823 set_input_normal ();
824 }
825
826 void
after_menu_action()827 edit_interface_rep::after_menu_action () {
828 notify_change (THE_DECORATIONS);
829 end_editing ();
830 windows_delayed_refresh (1);
831 }
832
833 void
cancel_menu_action()834 edit_interface_rep::cancel_menu_action () {
835 notify_change (THE_DECORATIONS);
836 cancel_editing ();
837 windows_delayed_refresh (1);
838 }
839
840 rectangle
get_window_extents()841 edit_interface_rep::get_window_extents () {
842 SI ox, oy, w, h;
843 widget me= ::get_canvas (widget (cvw));
844 ::get_position (me, ox, oy);
845 ::get_size (me, w, h);
846 SI vx1, vy1, vx2, vy2;
847 SERVER (get_visible (vx1, vy1, vx2, vy2));
848 ox -= vx1; oy -= vy2;
849 return rectangle (ox, oy - h, ox + w, oy);
850 }
851
852 cursor
search_cursor(path p)853 edit_interface_rep::search_cursor (path p) {
854 return eb->find_check_cursor (p);
855 }
856
857 selection
search_selection(path start,path end)858 edit_interface_rep::search_selection (path start, path end) {
859 selection sel= eb->find_check_selection (start, end);
860 rectangle r= least_upper_bound (sel->rs) / std_shrinkf;
861 return sel;
862 }
863
864 /******************************************************************************
865 * event handlers
866 ******************************************************************************/
867
868 bool
is_editor_widget()869 edit_interface_rep::is_editor_widget () {
870 return true;
871 }
872
873 void
handle_get_size_hint(SI & w,SI & h)874 edit_interface_rep::handle_get_size_hint (SI& w, SI& h) {
875 gui_root_extents (w, h);
876 }
877
878 void
handle_notify_resize(SI w,SI h)879 edit_interface_rep::handle_notify_resize (SI w, SI h) {
880 (void) w; (void) h;
881 notify_change (THE_TREE);
882 }
883
884 void
handle_set_zoom_factor(double zoom)885 edit_interface_rep::handle_set_zoom_factor (double zoom) {
886 set_zoom_factor (zoom);
887 }
888