]> git.lyx.org Git - lyx.git/blob - src/screen.C
452fe295eb10683cb8bbcb4766c1976a79aaef7b
[lyx.git] / src / screen.C
1 /* This file is part of
2 * ====================================================== 
3
4 *           LyX, The Document Processor
5 *        
6 *           Copyright 1995 Matthias Ettrich
7 *           Copyright 1995-1998 The LyX Team
8 *
9 * ====================================================== */
10
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation "lyxscreen.h"
15 #endif
16
17 #include "lyxscreen.h"
18 #include "lyxtext.h"
19 #include "lyxrow.h"
20 #include "BufferView.h"
21 #include "Painter.h"
22
23
24 static
25 GC createGC()
26 {
27         XGCValues val;
28         val.foreground = BlackPixel(fl_display, 
29                                     DefaultScreen(fl_display));
30         
31         val.function=GXcopy;
32         val.graphics_exposures = false;
33         val.line_style = LineSolid;
34         val.line_width = 0;
35         return XCreateGC(fl_display, RootWindow(fl_display, 0), 
36                          GCForeground | GCFunction | GCGraphicsExposures
37                          | GCLineWidth | GCLineStyle , &val);
38 }
39
40
41 // Constructor
42 LyXScreen::LyXScreen(BufferView * o, Window window,
43                      Pixmap p,
44                      Dimension width, 
45                      Dimension height,
46                      Dimension offset_x,
47                      Dimension offset_y,
48                      LyXText *text_ptr)
49         : owner(o), text(text_ptr), _window(window), 
50         _width(width), _height(height),
51         _offset_x(offset_x), _offset_y(offset_y)
52 {
53         first = 0;
54    
55         /* the cursor isnt yet visible */ 
56         cursor_visible = false;
57         screen_refresh_y = -1;
58
59         /* create the foreground pixmap */
60         foreground = p;
61
62         cursor_pixmap = 0;
63         cursor_pixmap_x = 0;
64         cursor_pixmap_y = 0;
65         cursor_pixmap_w = 0;
66         cursor_pixmap_h = 0;
67
68         // We need this GC
69         gc_copy = createGC();
70 }
71
72
73 // Destructor
74 LyXScreen::~LyXScreen() {}
75
76
77 void LyXScreen::Redraw()
78 {
79         DrawFromTo(0, _height);
80         screen_refresh_y = -1;
81         expose(0, 0, _width, _height);
82         if (cursor_visible) {
83                 cursor_visible = false;
84                 ShowCursor();
85         }
86 }
87
88
89 void LyXScreen::expose(int x, int y, int exp_width, int exp_height)
90 {
91         XCopyArea(fl_display,
92                   foreground,
93                   _window,
94                   gc_copy,
95                   x, y,
96                   exp_width, exp_height,
97                   x+_offset_x, y+_offset_y);
98 }
99
100
101 void LyXScreen::DrawFromTo(int y1, int y2)
102 {
103         long y_text = first + y1;
104    
105         /* get the first needed row */ 
106         Row * row = text->GetRowNearY(y_text);
107         /* y_text is now the real beginning of the row */
108    
109         long y = y_text - first;
110         /* y1 is now the real beginning of row on the screen */
111         
112         while (row != 0 && y < y2) {
113
114                 text->GetVisibleRow(y, row, y + first);
115                 y += row->height;
116                 row = row -> next;
117
118         }
119    
120         /* maybe we have to clear the screen at the bottom */ 
121         if (y < y2) {
122                 owner->painter().fillRectangle(0, y, _width, y2 - y,
123                                                LColor::bottomarea);
124         }
125 }
126
127
128 void LyXScreen::DrawOneRow(Row * row, long & y_text)
129 {
130         long y = y_text - first;
131       
132         if (y + row->height > 0 && y - row->height <= _height) {
133                 /* ok there is something visible */
134                 text->GetVisibleRow(y, row, y + first);
135         }
136         y_text+= row->height;
137 }
138
139
140 /* draws the screen, starting with textposition y. uses as much already
141 * printed pixels as possible */
142 void LyXScreen::Draw(long  y)
143 {
144         if (cursor_visible) HideCursor();
145
146         if (y < 0) y = 0;
147         long old_first = first;
148         first = y;
149
150         /* is any optimiziation possible? */ 
151         if ((y - old_first) < _height 
152             && (old_first - y) < _height) {
153                 if (first < old_first) {
154                         DrawFromTo(0, old_first - first);
155                         XCopyArea (fl_display,
156                                    _window,
157                                    _window,
158                                    gc_copy,
159                                    _offset_x, _offset_y, 
160                                    _width , _height - old_first + first,
161                                    _offset_x, _offset_y + old_first - first);
162                         // expose the area drawn
163                         expose(0, 0, _width, old_first - first);
164                 } else  {
165                         DrawFromTo(_height + old_first - first, _height);
166                         XCopyArea (fl_display,
167                                    _window,
168                                    _window,
169                                    gc_copy,
170                                    _offset_x, _offset_y + first - old_first, 
171                                    _width , _height + old_first - first, 
172                                    _offset_x, _offset_y);
173                         // expose the area drawn
174                         expose(0, _height + old_first - first, 
175                                _width, first - old_first);
176                 }
177         } else {
178                 /* make a dumb new-draw */ 
179                 DrawFromTo(0, _height);
180                 expose(0, 0, _width, _height);
181         }
182 }
183
184
185 void LyXScreen::ShowCursor()
186 {
187         long x = 0;
188         long y1 = 0;
189         long y2 = 0;
190    
191         if (cursor_visible) return;
192    
193         x = text->cursor.x;
194         
195         y1 = text->cursor.y - text->real_current_font.maxAscent() - first;
196         if (y1 < 0) y1 = 0;
197         
198         y2 = text->cursor.y + text->real_current_font.maxDescent() - first;
199         if (y2 > _height) y2 = _height;
200
201         // Secure against very strange situations
202         if (y2 < y1) y2 = y1;
203
204         if (cursor_pixmap){
205                 XFreePixmap(fl_display, cursor_pixmap);
206                 cursor_pixmap = 0;
207         }
208    
209         if (y2 > 0 && y1 < _height) {
210                 cursor_pixmap_w = 1;
211                 cursor_pixmap_h = y2 - y1 + 1;
212                 cursor_pixmap_x = x;
213                 cursor_pixmap_y = y1;
214                 cursor_pixmap = 
215                         XCreatePixmap(fl_display,
216                                       fl_root,
217                                       cursor_pixmap_w,
218                                       cursor_pixmap_h,
219                                       fl_get_visual_depth());
220                 XCopyArea(fl_display,
221                           _window,
222                           cursor_pixmap,
223                           gc_copy,
224                           _offset_x + cursor_pixmap_x, 
225                           _offset_y + cursor_pixmap_y,
226                           cursor_pixmap_w, cursor_pixmap_h,
227                           0, 0);
228                 XDrawLine(fl_display,
229                           _window, gc_copy,
230                           x + _offset_x,
231                           y1 + _offset_y,
232                           x + _offset_x,
233                           y2 + _offset_y);
234                 cursor_visible = true;
235         }
236 }
237
238
239 /* returns 1 if first has changed, otherwise 0 */ 
240 int LyXScreen::FitManualCursor(long /*x*/, long y, int asc, int desc)
241 {
242         long  newtop = first;
243   
244         if (y + desc  - first >= _height)
245                 newtop = y - 3*_height / 4;   /* the scroll region must be so big!! */
246         else if (y - asc < first 
247                  && first > 0) {
248                 newtop = y - _height / 4;
249         }
250         if (newtop < 0)
251                 newtop = 0;
252   
253         if (newtop != first){
254                 Draw(newtop);
255                 first = newtop;
256                 return 1;
257         }
258         return 0;
259 }
260
261
262 void  LyXScreen::HideManualCursor()
263 {
264         HideCursor();
265 }
266
267
268 void  LyXScreen::ShowManualCursor(long x, long y, int asc, int desc)
269 {
270         long y1 = 0;
271         long y2 = 0;
272         
273         y1 = y - first - asc;
274         if (y1 < 0)
275                 y1 = 0;
276         y2 = y -first + desc;
277         if (y2 > _height)
278                 y2 = _height;
279
280         if (cursor_pixmap){
281                 XFreePixmap(fl_display, cursor_pixmap);
282                 cursor_pixmap = 0;
283         }
284                 
285         if (y2 > 0 && y1 < _height) {
286                 cursor_pixmap_w = 1;
287                 cursor_pixmap_h = y2 - y1 + 1;
288                 cursor_pixmap_x = x,
289                         cursor_pixmap_y = y1;
290                 cursor_pixmap = 
291                         XCreatePixmap (fl_display,
292                                        fl_root,
293                                        cursor_pixmap_w,
294                                        cursor_pixmap_h,
295                                        fl_get_visual_depth());
296                 XCopyArea (fl_display,
297                            _window,
298                            cursor_pixmap,
299                            gc_copy,
300                            _offset_x + cursor_pixmap_x,
301                            _offset_y + cursor_pixmap_y,
302                            cursor_pixmap_w,
303                            cursor_pixmap_h,
304                            0, 0);
305                 XDrawLine(fl_display,
306                           _window, gc_copy,
307                           x+_offset_x,
308                           y1+_offset_y,
309                           x+_offset_x,
310                           y2+_offset_y);
311         }
312         cursor_visible = true;
313 }
314
315
316 void LyXScreen::HideCursor()
317 {
318         if (!cursor_visible) return;
319
320         if (cursor_pixmap){
321                 XCopyArea (fl_display, 
322                            cursor_pixmap,
323                            _window,
324                            gc_copy,
325                            0, 0, 
326                            cursor_pixmap_w, cursor_pixmap_h,
327                            cursor_pixmap_x + _offset_x,
328                            cursor_pixmap_y + _offset_y);
329         }
330         cursor_visible = false;
331 }
332
333
334 void LyXScreen::CursorToggle()
335 {
336         if (cursor_visible)
337                 HideCursor();
338         else
339                 ShowCursor();
340 }
341
342
343 /* returns a new top so that the cursor is visible */ 
344 long LyXScreen::TopCursorVisible()
345 {
346         long newtop = first;
347
348         if (text->cursor.y
349             - text->cursor.row->baseline
350             + text->cursor.row->height
351             - first >= _height) {
352                 if (text->cursor.row->height < _height
353                     && text->cursor.row->height > _height/4)
354                         newtop = text->cursor.y
355                                 + text->cursor.row->height
356                                 - text->cursor.row->baseline - _height;
357                 else
358                         newtop = text->cursor.y
359                                 - 3*_height / 4;   /* the scroll region must be so big!! */
360         } else if (text->cursor.y - text->cursor.row->baseline < first 
361                    && first > 0) {
362                 if (text->cursor.row->height < _height
363                     && text->cursor.row->height > _height/4)
364                         newtop = text->cursor.y - text->cursor.row->baseline;
365                 else {
366                         newtop = text->cursor.y - _height / 4;
367                         if (newtop > first)
368                                 newtop = first;
369                 }
370         }
371         if (newtop < 0)
372                 newtop = 0;
373         
374         return newtop;
375 }
376
377
378 /* scrolls the screen so that the cursor is visible, if necessary.
379 * returns 1 if a change was made, otherwise 0 */ 
380 int LyXScreen::FitCursor()
381 {
382         /* is a change necessary */ 
383         long  newtop = TopCursorVisible();
384         int result = (newtop != first);
385         if (result)
386                 Draw(newtop);
387         return result;
388 }
389
390    
391 void LyXScreen::Update()
392 {
393         long y = 0;
394
395         if (text->status == LyXText::NEED_MORE_REFRESH
396             || screen_refresh_y > -1 ) {
397                 if (screen_refresh_y > -1
398                     && screen_refresh_y < text->refresh_y)
399                         y = screen_refresh_y;
400                 else
401                         y = text->refresh_y;
402                 
403                 if (y < first) y = first;
404                 
405                 DrawFromTo(y - first, _height);
406                 text->refresh_y = 0;
407                 text->status = LyXText::UNCHANGED;
408                 screen_refresh_y = -1;
409                 expose(0, y-first, _width, _height - (y - first));
410         } else if (text->status == LyXText::NEED_VERY_LITTLE_REFRESH) {
411                 /* ok I will update the current cursor row */
412                 y = text->refresh_y;
413                 DrawOneRow(text->refresh_row, y);
414                 text->status = LyXText::UNCHANGED;
415                 expose(0, text->refresh_y-first,
416                        _width, text->refresh_row->height);
417         }
418 }
419
420
421 void LyXScreen::SmallUpdate()
422 {
423         Row * row = 0;
424         long y = 0;
425         long y2 = 0;
426         
427         if (text->status == LyXText::NEED_MORE_REFRESH){
428                 /* ok I will update till the current cursor row */
429                 row = text->refresh_row;
430                 y = text->refresh_y;
431                 y2 = y;
432       
433                 if (y > text->cursor.y) {
434                         Update();
435                         return;
436                 }
437          
438                 while (row && row != text->cursor.row && y < first + _height) {
439                         DrawOneRow(row, y);
440                         row = row->next;
441                 }
442       
443                 DrawOneRow(row, y);
444                 screen_refresh_y = y;
445                 screen_refresh_row = row->next;
446                 text->status = LyXText::UNCHANGED;
447                 // Is the right regin exposed?
448                 expose(0, y2-first, _width, y-y2);
449         } else if (text->status == LyXText::NEED_VERY_LITTLE_REFRESH) {
450                 /* ok I will update the current cursor row */
451                 row = text->refresh_row;
452                 y = text->refresh_y;
453                 DrawOneRow(row, y);
454                 text->status = LyXText::UNCHANGED;
455                 expose(0, text->refresh_y - first,
456                        _width, row->height);
457         }
458 }
459
460
461 void LyXScreen::ToggleSelection(bool kill_selection)
462 {
463         /* only if there is a selection */ 
464         if (!text->selection)
465                 return;
466
467         long top = text->sel_start_cursor.y
468                 - text->sel_start_cursor.row->baseline;
469         long bottom = text->sel_end_cursor.y
470                 - text->sel_end_cursor.row->baseline 
471                 + text->sel_end_cursor.row->height;
472         
473         if (top - first < 0)
474                 top = first;
475         if (bottom - first < 0)
476                 bottom = first;
477         
478         if (bottom - first > _height)
479                 bottom = first + _height;
480         if (top - first > _height)
481                 top = first + _height;
482         
483         if (kill_selection)
484                 text->selection = 0;
485         DrawFromTo(top - first, bottom - first);
486         expose(0, top - first, _width, bottom - first - (top - first));
487 }
488   
489    
490 void LyXScreen::ToggleToggle()
491 {
492         if (text->toggle_cursor.par == text->toggle_end_cursor.par
493             && text->toggle_cursor.pos == text->toggle_end_cursor.pos)
494                 return;
495         
496         long top = text->toggle_cursor.y
497                 - text->toggle_cursor.row->baseline;
498         long bottom = text->toggle_end_cursor.y
499                 - text->toggle_end_cursor.row->baseline 
500                 + text->toggle_end_cursor.row->height;
501         
502         if (top - first < 0)
503                 top = first;
504         if (bottom - first < 0)
505                 bottom = first;
506         
507         if (bottom - first > _height)
508                 bottom = first + _height;
509         if (top - first > _height)
510                 top = first + _height;
511         
512         DrawFromTo(top - first, bottom - first);
513         expose(0, top - first, _width, bottom - first - (top - first));
514 }