1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-1998 The LyX Team
9 * ====================================================== */
14 #pragma implementation "lyxscreen.h"
19 #include "lyxscreen.h"
34 val.foreground = BlackPixel(fl_display,
35 DefaultScreen(fl_display));
38 val.graphics_exposures = false;
39 val.line_style = LineSolid;
41 return XCreateGC(fl_display, RootWindow(fl_display, 0),
42 GCForeground | GCFunction | GCGraphicsExposures
43 | GCLineWidth | GCLineStyle , &val);
48 LyXScreen::LyXScreen(WorkArea & o, LyXText * text_ptr)
49 : owner(o), text(text_ptr)
53 /* the cursor isnt yet visible */
54 cursor_visible = false;
66 void LyXScreen::Redraw()
68 DrawFromTo(0, owner.height());
69 expose(0, 0, owner.workWidth(), owner.height());
71 cursor_visible = false;
77 void LyXScreen::expose(int x, int y, int exp_width, int exp_height)
84 exp_width, exp_height,
90 void LyXScreen::DrawFromTo(int y1, int y2)
92 long y_text = first + y1;
94 /* get the first needed row */
95 Row * row = text->GetRowNearY(y_text);
96 /* y_text is now the real beginning of the row */
98 long y = y_text - first;
99 /* y1 is now the real beginning of row on the screen */
101 while (row != 0 && y < y2) {
102 text->GetVisibleRow(y, row, y + first);
107 /* maybe we have to clear the screen at the bottom */
109 owner.getPainter().fillRectangle(0, y,
118 void LyXScreen::DrawOneRow(Row * row, long y_text)
120 long y = y_text - first;
122 if (y + row->height > 0 && y - row->height <= long(owner.height())) {
123 /* ok there is something visible */
124 text->GetVisibleRow(y, row, y + first);
128 void LyXScreen::DrawOneRow(Row * row, long & y_text)
130 long y = y_text - first;
132 if (y + row->height > 0 && y - row->height <= long(owner.height())) {
133 /* ok there is something visible */
134 text->GetVisibleRow(y, row, y + first);
136 y_text += row->height;
141 /* draws the screen, starting with textposition y. uses as much already
142 * printed pixels as possible */
143 void LyXScreen::Draw(unsigned long y)
145 if (cursor_visible) HideCursor();
148 unsigned long old_first = first;
151 /* is any optimiziation possible? */
152 if ((y - old_first) < owner.height()
153 && (old_first - y) < owner.height()) {
154 if (first < old_first) {
155 DrawFromTo(0, old_first - first);
156 XCopyArea (fl_display,
163 owner.height() - old_first + first,
165 owner.ypos() + old_first - first
167 // expose the area drawn
173 owner.height() + old_first - first,
175 XCopyArea (fl_display,
180 owner.ypos() + first - old_first,
182 owner.height() + old_first - first,
185 // expose the area drawn
186 expose(0, owner.height() + old_first - first,
187 owner.workWidth(), first - old_first);
190 /* make a dumb new-draw */
191 DrawFromTo(0, owner.height());
192 expose(0, 0, owner.workWidth(), owner.height());
197 void LyXScreen::ShowCursor()
199 if (!cursor_visible) {
200 Cursor_Shape shape = BAR_SHAPE;
201 if (text->real_current_font.language() !=
202 text->buffer->params.language_info
203 || text->real_current_font.isVisibleRightToLeft()
204 != text->buffer->params.language_info->RightToLeft)
205 shape = (text->real_current_font.isVisibleRightToLeft())
206 ? REVERSED_L_SHAPE : L_SHAPE;
207 ShowManualCursor(text->cursor.x, text->cursor.y,
208 lyxfont::maxAscent(text->real_current_font),
209 lyxfont::maxDescent(text->real_current_font),
215 /* returns true if first has changed, otherwise false */
216 bool LyXScreen::FitManualCursor(long /*x*/, long y, int asc, int desc)
220 if (y + desc - first >= owner.height())
221 newtop = y - 3 * owner.height() / 4; /* the scroll region must be so big!! */
222 else if (y - asc < long(first)
224 newtop = y - owner.height() / 4;
227 newtop = max(newtop, 0L); // can newtop ever be < 0? (Lgb)
229 if (newtop != long(first)) {
238 void LyXScreen::ShowManualCursor(long x, long y, int asc, int desc,
241 unsigned long y1 = max(y - first - asc, 0UL);
242 typedef unsigned long ulong;
244 unsigned long y2 = min(y - first + desc, ulong(owner.height()));
246 // Secure against very strange situations
247 //if (y2 < y1) y2 = y1;
251 XFreePixmap(fl_display, cursor_pixmap);
255 if (y2 > 0 && y1 < owner.height()) {
256 cursor_pixmap_h = y2 - y1 + 1;
257 cursor_pixmap_y = y1;
265 cursor_pixmap_w = cursor_pixmap_h/3;
268 case REVERSED_L_SHAPE:
269 cursor_pixmap_w = cursor_pixmap_h/3;
270 cursor_pixmap_x = x - cursor_pixmap_w + 1;
275 XCreatePixmap (fl_display,
279 fl_get_visual_depth());
280 XCopyArea (fl_display,
284 owner.xpos() + cursor_pixmap_x,
285 owner.ypos() + cursor_pixmap_y,
289 XDrawLine(fl_display,
300 case REVERSED_L_SHAPE:
301 int rectangle_h = (cursor_pixmap_h+10)/20;
302 XFillRectangle(fl_display,
305 cursor_pixmap_x + owner.xpos(),
306 y2 - rectangle_h + 1 + owner.ypos(),
307 cursor_pixmap_w - 1, rectangle_h);
312 cursor_visible = true;
316 void LyXScreen::HideCursor()
318 if (!cursor_visible) return;
321 XCopyArea (fl_display,
326 cursor_pixmap_w, cursor_pixmap_h,
327 cursor_pixmap_x + owner.xpos(),
328 cursor_pixmap_y + owner.ypos());
330 cursor_visible = false;
334 void LyXScreen::CursorToggle()
343 /* returns a new top so that the cursor is visible */
344 unsigned long LyXScreen::TopCursorVisible()
349 - text->cursor.row->baseline
350 + text->cursor.row->height
351 - first >= owner.height()) {
352 if (text->cursor.row->height < owner.height()
353 && text->cursor.row->height > owner.height() / 4)
354 newtop = text->cursor.y
355 + text->cursor.row->height
356 - text->cursor.row->baseline - owner.height();
358 newtop = text->cursor.y
359 - 3 * owner.height() / 4; /* the scroll region must be so big!! */
360 } else if (text->cursor.y - text->cursor.row->baseline < first
362 if (text->cursor.row->height < owner.height()
363 && text->cursor.row->height > owner.height() / 4)
364 newtop = text->cursor.y - text->cursor.row->baseline;
366 newtop = text->cursor.y - owner.height() / 4;
367 //if (newtop > long(first))
368 newtop = min(newtop, long(first));
373 newtop = max(newtop, 0L);
379 /* scrolls the screen so that the cursor is visible, if necessary.
380 * returns true if a change was made, otherwise false */
381 bool LyXScreen::FitCursor()
383 // Is a change necessary?
384 unsigned long newtop = TopCursorVisible();
385 bool result = (newtop != first);
392 void LyXScreen::Update()
395 switch(text->status) {
396 case LyXText::NEED_MORE_REFRESH:
398 long y = max(text->refresh_y - long(first), 0L);
400 DrawFromTo(y, owner.height());
402 text->status = LyXText::UNCHANGED;
404 owner.workWidth(), owner.height() - y);
407 case LyXText::NEED_VERY_LITTLE_REFRESH:
409 /* ok I will update the current cursor row */
410 DrawOneRow(text->refresh_row, text->refresh_y);
411 text->status = LyXText::UNCHANGED;
412 expose(0, text->refresh_y - first,
413 owner.workWidth(), text->refresh_row->height);
416 case LyXText::UNCHANGED:
417 // Nothing needs done
421 if (text->status == LyXText::NEED_MORE_REFRESH
422 || screen_refresh_y > -1 ) {
424 if (screen_refresh_y > -1
425 && screen_refresh_y < text->refresh_y)
426 y = screen_refresh_y;
430 //if (y < first) y = first;
431 y = max(y, long(first));
433 DrawFromTo(y - first, owner.height());
435 text->status = LyXText::UNCHANGED;
436 screen_refresh_y = -1;
438 owner.workWidth(), owner.height() - (y - first));
439 } else if (text->status == LyXText::NEED_VERY_LITTLE_REFRESH) {
440 /* ok I will update the current cursor row */
441 long y = text->refresh_y;
442 DrawOneRow(text->refresh_row, y);
443 text->status = LyXText::UNCHANGED;
444 expose(0, text->refresh_y - first,
445 owner.workWidth(), text->refresh_row->height);
452 void LyXScreen::SmallUpdate()
457 if (text->status == LyXText::NEED_MORE_REFRESH) {
458 /* ok I will update till the current cursor row */
459 Row * row = text->refresh_row;
460 long y = text->refresh_y;
463 if (y > long(text->cursor.y)) {
469 && row != text->cursor.row
470 && y < long(first + owner.height())) {
476 screen_refresh_y = y;
477 screen_refresh_row = row->next;
478 text->status = LyXText::UNCHANGED;
479 // Is the right regin exposed?
480 expose(0, y2 - first,
481 owner.workWidth(), y - y2);
482 } else if (text->status == LyXText::NEED_VERY_LITTLE_REFRESH) {
483 /* ok I will update the current cursor row */
484 long y = text->refresh_y;
485 DrawOneRow(text->refresh_row, y);
486 text->status = LyXText::UNCHANGED;
487 expose(0, text->refresh_y - first,
488 owner.workWidth(), text->refresh_row->height);
495 void LyXScreen::ToggleSelection(bool kill_selection)
497 /* only if there is a selection */
498 if (!text->selection) return;
500 //long top = text->sel_start_cursor.y
501 // - text->sel_start_cursor.row->baseline;
502 //long bottom = text->sel_end_cursor.y
503 // - text->sel_end_cursor.row->baseline
504 // + text->sel_end_cursor.row->height;
506 //top = max(top, first);
507 //bottom = max(bottom, first);
509 //bottom = min(max(bottom, first), first + owner.height());
510 //top = min(max(top, first), first + owner.height());
511 long bottom = min(max(text->sel_end_cursor.y
512 - text->sel_end_cursor.row->baseline
513 + text->sel_end_cursor.row->height, first),
514 first + owner.height());
515 long top = min(max(text->sel_start_cursor.y
516 - text->sel_start_cursor.row->baseline, first),
517 first + owner.height());
521 DrawFromTo(top - first, bottom - first);
522 expose(0, top - first,
524 bottom - first - (top - first));
528 void LyXScreen::ToggleToggle()
530 if (text->toggle_cursor.par == text->toggle_end_cursor.par
531 && text->toggle_cursor.pos == text->toggle_end_cursor.pos)
534 long top = text->toggle_cursor.y
535 - text->toggle_cursor.row->baseline;
536 long bottom = text->toggle_end_cursor.y
537 - text->toggle_end_cursor.row->baseline
538 + text->toggle_end_cursor.row->height;
540 //top = max(top, first);
541 //bottom = max(bottom, first);
542 typedef unsigned long ulong;
544 bottom = min(max(ulong(bottom), first), first + owner.height());
545 top = min(max(ulong(top), first), first + owner.height());
547 DrawFromTo(top - first, bottom - first);
548 expose(0, top - first, owner.workWidth(),
549 bottom - first - (top - first));