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;
56 screen_refresh_y = -1;
69 void LyXScreen::Redraw()
71 DrawFromTo(0, owner.height());
73 screen_refresh_y = -1;
75 expose(0, 0, owner.workWidth(), owner.height());
77 cursor_visible = false;
83 void LyXScreen::expose(int x, int y, int exp_width, int exp_height)
90 exp_width, exp_height,
96 void LyXScreen::DrawFromTo(int y1, int y2)
98 long y_text = first + y1;
100 /* get the first needed row */
101 Row * row = text->GetRowNearY(y_text);
102 /* y_text is now the real beginning of the row */
104 long y = y_text - first;
105 /* y1 is now the real beginning of row on the screen */
107 while (row != 0 && y < y2) {
108 text->GetVisibleRow(y, row, y + first);
113 /* maybe we have to clear the screen at the bottom */
115 owner.getPainter().fillRectangle(0, y,
124 void LyXScreen::DrawOneRow(Row * row, long y_text)
126 long y = y_text - first;
128 if (y + row->height > 0 && y - row->height <= long(owner.height())) {
129 /* ok there is something visible */
130 text->GetVisibleRow(y, row, y + first);
134 void LyXScreen::DrawOneRow(Row * row, long & y_text)
136 long y = y_text - first;
138 if (y + row->height > 0 && y - row->height <= long(owner.height())) {
139 /* ok there is something visible */
140 text->GetVisibleRow(y, row, y + first);
142 y_text += row->height;
147 /* draws the screen, starting with textposition y. uses as much already
148 * printed pixels as possible */
149 void LyXScreen::Draw(unsigned long y)
151 if (cursor_visible) HideCursor();
154 unsigned long old_first = first;
157 /* is any optimiziation possible? */
158 if ((y - old_first) < owner.height()
159 && (old_first - y) < owner.height()) {
160 if (first < old_first) {
161 DrawFromTo(0, old_first - first);
162 XCopyArea (fl_display,
169 owner.height() - old_first + first,
171 owner.ypos() + old_first - first
173 // expose the area drawn
179 owner.height() + old_first - first,
181 XCopyArea (fl_display,
186 owner.ypos() + first - old_first,
188 owner.height() + old_first - first,
191 // expose the area drawn
192 expose(0, owner.height() + old_first - first,
193 owner.workWidth(), first - old_first);
196 /* make a dumb new-draw */
197 DrawFromTo(0, owner.height());
198 expose(0, 0, owner.workWidth(), owner.height());
203 void LyXScreen::ShowCursor()
205 if (!cursor_visible) {
206 Cursor_Shape shape = BAR_SHAPE;
207 if (text->real_current_font.language() !=
208 text->buffer->params.language_info
209 || text->real_current_font.isVisibleRightToLeft()
210 != text->buffer->params.language_info->RightToLeft)
211 shape = (text->real_current_font.isVisibleRightToLeft())
212 ? REVERSED_L_SHAPE : L_SHAPE;
213 ShowManualCursor(text->cursor.x, text->cursor.y,
214 lyxfont::maxAscent(text->real_current_font),
215 lyxfont::maxDescent(text->real_current_font),
221 /* returns true if first has changed, otherwise false */
222 bool LyXScreen::FitManualCursor(long /*x*/, long y, int asc, int desc)
226 if (y + desc - first >= owner.height())
227 newtop = y - 3 * owner.height() / 4; /* the scroll region must be so big!! */
228 else if (y - asc < long(first)
230 newtop = y - owner.height() / 4;
233 newtop = max(newtop, 0L); // can newtop ever be < 0? (Lgb)
235 if (newtop != long(first)) {
244 void LyXScreen::ShowManualCursor(long x, long y, int asc, int desc,
247 unsigned long y1 = max(y - first - asc, 0UL);
248 typedef unsigned long ulong;
250 unsigned long y2 = min(y - first + desc, ulong(owner.height()));
252 // Secure against very strange situations
253 //if (y2 < y1) y2 = y1;
257 XFreePixmap(fl_display, cursor_pixmap);
261 if (y2 > 0 && y1 < owner.height()) {
262 cursor_pixmap_h = y2 - y1 + 1;
263 cursor_pixmap_y = y1;
271 cursor_pixmap_w = cursor_pixmap_h/3;
274 case REVERSED_L_SHAPE:
275 cursor_pixmap_w = cursor_pixmap_h/3;
276 cursor_pixmap_x = x - cursor_pixmap_w + 1;
281 XCreatePixmap (fl_display,
285 fl_get_visual_depth());
286 XCopyArea (fl_display,
290 owner.xpos() + cursor_pixmap_x,
291 owner.ypos() + cursor_pixmap_y,
295 XDrawLine(fl_display,
306 case REVERSED_L_SHAPE:
307 int rectangle_h = (cursor_pixmap_h+10)/20;
308 XFillRectangle(fl_display,
311 cursor_pixmap_x + owner.xpos(),
312 y2 - rectangle_h + 1 + owner.ypos(),
313 cursor_pixmap_w - 1, rectangle_h);
318 cursor_visible = true;
322 void LyXScreen::HideCursor()
324 if (!cursor_visible) return;
327 XCopyArea (fl_display,
332 cursor_pixmap_w, cursor_pixmap_h,
333 cursor_pixmap_x + owner.xpos(),
334 cursor_pixmap_y + owner.ypos());
336 cursor_visible = false;
340 void LyXScreen::CursorToggle()
349 /* returns a new top so that the cursor is visible */
350 unsigned long LyXScreen::TopCursorVisible()
355 - text->cursor.row->baseline
356 + text->cursor.row->height
357 - first >= owner.height()) {
358 if (text->cursor.row->height < owner.height()
359 && text->cursor.row->height > owner.height() / 4)
360 newtop = text->cursor.y
361 + text->cursor.row->height
362 - text->cursor.row->baseline - owner.height();
364 newtop = text->cursor.y
365 - 3 * owner.height() / 4; /* the scroll region must be so big!! */
366 } else if (text->cursor.y - text->cursor.row->baseline < first
368 if (text->cursor.row->height < owner.height()
369 && text->cursor.row->height > owner.height() / 4)
370 newtop = text->cursor.y - text->cursor.row->baseline;
372 newtop = text->cursor.y - owner.height() / 4;
373 //if (newtop > long(first))
374 newtop = min(newtop, long(first));
379 newtop = max(newtop, 0L);
385 /* scrolls the screen so that the cursor is visible, if necessary.
386 * returns true if a change was made, otherwise false */
387 bool LyXScreen::FitCursor()
389 // Is a change necessary?
390 unsigned long newtop = TopCursorVisible();
391 bool result = (newtop != first);
398 void LyXScreen::Update()
401 switch(text->status) {
402 case LyXText::NEED_MORE_REFRESH:
404 long y = max(text->refresh_y - long(first), 0L);
406 DrawFromTo(y, owner.height());
408 text->status = LyXText::UNCHANGED;
410 owner.workWidth(), owner.height() - y);
413 case LyXText::NEED_VERY_LITTLE_REFRESH:
415 /* ok I will update the current cursor row */
416 DrawOneRow(text->refresh_row, text->refresh_y);
417 text->status = LyXText::UNCHANGED;
418 expose(0, text->refresh_y - first,
419 owner.workWidth(), text->refresh_row->height);
422 case LyXText::UNCHANGED:
423 // Nothing needs done
427 if (text->status == LyXText::NEED_MORE_REFRESH
428 || screen_refresh_y > -1 ) {
430 if (screen_refresh_y > -1
431 && screen_refresh_y < text->refresh_y)
432 y = screen_refresh_y;
436 //if (y < first) y = first;
437 y = max(y, long(first));
439 DrawFromTo(y - first, owner.height());
441 text->status = LyXText::UNCHANGED;
442 screen_refresh_y = -1;
444 owner.workWidth(), owner.height() - (y - first));
445 } else if (text->status == LyXText::NEED_VERY_LITTLE_REFRESH) {
446 /* ok I will update the current cursor row */
447 long y = text->refresh_y;
448 DrawOneRow(text->refresh_row, y);
449 text->status = LyXText::UNCHANGED;
450 expose(0, text->refresh_y - first,
451 owner.workWidth(), text->refresh_row->height);
458 void LyXScreen::SmallUpdate()
463 if (text->status == LyXText::NEED_MORE_REFRESH) {
464 /* ok I will update till the current cursor row */
465 Row * row = text->refresh_row;
466 long y = text->refresh_y;
469 if (y > long(text->cursor.y)) {
475 && row != text->cursor.row
476 && y < long(first + owner.height())) {
482 screen_refresh_y = y;
483 screen_refresh_row = row->next;
484 text->status = LyXText::UNCHANGED;
485 // Is the right regin exposed?
486 expose(0, y2 - first,
487 owner.workWidth(), y - y2);
488 } else if (text->status == LyXText::NEED_VERY_LITTLE_REFRESH) {
489 /* ok I will update the current cursor row */
490 long y = text->refresh_y;
491 DrawOneRow(text->refresh_row, y);
492 text->status = LyXText::UNCHANGED;
493 expose(0, text->refresh_y - first,
494 owner.workWidth(), text->refresh_row->height);
501 void LyXScreen::ToggleSelection(bool kill_selection)
503 /* only if there is a selection */
504 if (!text->selection) return;
506 //long top = text->sel_start_cursor.y
507 // - text->sel_start_cursor.row->baseline;
508 //long bottom = text->sel_end_cursor.y
509 // - text->sel_end_cursor.row->baseline
510 // + text->sel_end_cursor.row->height;
512 //top = max(top, first);
513 //bottom = max(bottom, first);
515 //bottom = min(max(bottom, first), first + owner.height());
516 //top = min(max(top, first), first + owner.height());
517 long bottom = min(max(text->sel_end_cursor.y
518 - text->sel_end_cursor.row->baseline
519 + text->sel_end_cursor.row->height, first),
520 first + owner.height());
521 long top = min(max(text->sel_start_cursor.y
522 - text->sel_start_cursor.row->baseline, first),
523 first + owner.height());
527 DrawFromTo(top - first, bottom - first);
528 expose(0, top - first,
530 bottom - first - (top - first));
534 void LyXScreen::ToggleToggle()
536 if (text->toggle_cursor.par == text->toggle_end_cursor.par
537 && text->toggle_cursor.pos == text->toggle_end_cursor.pos)
540 long top = text->toggle_cursor.y
541 - text->toggle_cursor.row->baseline;
542 long bottom = text->toggle_end_cursor.y
543 - text->toggle_end_cursor.row->baseline
544 + text->toggle_end_cursor.row->height;
546 //top = max(top, first);
547 //bottom = max(bottom, first);
548 typedef unsigned long ulong;
550 bottom = min(max(ulong(bottom), first), first + owner.height());
551 top = min(max(ulong(top), first), first + owner.height());
553 DrawFromTo(top - first, bottom - first);
554 expose(0, top - first, owner.workWidth(),
555 bottom - first - (top - first));