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"
25 #include "BufferView.h"
27 #include "insets/insettext.h"
28 #include "ColorHandler.h"
39 val.foreground = BlackPixel(fl_get_display(),
40 DefaultScreen(fl_get_display()));
42 val.function = GXcopy;
43 val.graphics_exposures = false;
44 val.line_style = LineSolid;
46 return XCreateGC(fl_get_display(), RootWindow(fl_get_display(), 0),
47 GCForeground | GCFunction | GCGraphicsExposures
48 | GCLineWidth | GCLineStyle , &val);
55 LyXScreen::LyXScreen(WorkArea & o)
56 : owner(o), force_clear(true)
58 // the cursor isnt yet visible
59 cursor_visible = false;
71 LyXScreen::~LyXScreen()
73 XFreeGC(fl_get_display(), gc_copy);
77 void LyXScreen::setCursorColor()
79 if (!lyxColorHandler.get()) return;
81 GC gc = lyxColorHandler->getGCForeground(LColor::cursor);
84 XGetGCValues(fl_get_display(),
85 gc, GCForeground, &val);
86 XChangeGC(fl_get_display(), gc_copy, GCForeground, &val);
90 void LyXScreen::redraw(LyXText * text, BufferView * bv)
92 drawFromTo(text, bv, 0, owner.height());
93 expose(0, 0, owner.workWidth(), owner.height());
95 cursor_visible = false;
101 void LyXScreen::expose(int x, int y, int exp_width, int exp_height)
103 XCopyArea(fl_get_display(),
108 exp_width, exp_height,
114 void LyXScreen::drawFromTo(LyXText * text, BufferView * bv,
115 int y1, int y2, int y_offset, int x_offset)
117 int y_text = text->first + y1;
119 // get the first needed row
120 Row * row = text->getRowNearY(y_text);
121 // y_text is now the real beginning of the row
123 int y = y_text - text->first;
124 // y1 is now the real beginning of row on the screen
126 while (row != 0 && y < y2) {
127 LyXText::text_status st = bv->text->status();
129 bv->text->status(bv, st);
130 text->getVisibleRow(bv, y + y_offset,
131 x_offset, row, y + text->first);
132 } while (bv->text->status() == LyXText::CHANGED_IN_DRAW);
133 bv->text->status(bv, st);
139 // maybe we have to clear the screen at the bottom
140 if ((y < y2) && text->bv_owner) {
141 owner.getPainter().fillRectangle(0, y,
149 void LyXScreen::drawOneRow(LyXText * text, BufferView * bv, Row * row,
150 int y_text, int y_offset, int x_offset)
152 int const y = y_text - text->first + y_offset;
154 if (((y + row->height()) > 0) &&
155 ((y - row->height()) <= static_cast<int>(owner.height()))) {
156 // ok there is something visible
157 LyXText::text_status st = bv->text->status();
159 bv->text->status(bv, st);
160 text->getVisibleRow(bv, y, x_offset, row,
162 } while (bv->text->status() == LyXText::CHANGED_IN_DRAW);
163 bv->text->status(bv, st);
169 /* draws the screen, starting with textposition y. uses as much already
170 * printed pixels as possible */
171 void LyXScreen::draw(LyXText * text, BufferView * bv, unsigned int y)
173 if (cursor_visible) hideCursor();
175 int const old_first = text->first;
178 // is any optimiziation possible?
179 if ((y - old_first) < owner.height()
180 && (old_first - y) < owner.height()) {
181 if (text->first < old_first) {
182 drawFromTo(text, bv, 0, old_first - text->first);
183 XCopyArea (fl_get_display(),
190 owner.height() - old_first + text->first,
192 owner.ypos() + old_first - text->first
194 // expose the area drawn
197 old_first - text->first);
200 owner.height() + old_first - text->first,
202 XCopyArea (fl_get_display(),
207 owner.ypos() + text->first - old_first,
209 owner.height() + old_first - text->first,
212 // expose the area drawn
213 expose(0, owner.height() + old_first - text->first,
214 owner.workWidth(), text->first - old_first);
217 // make a dumb new-draw
218 drawFromTo(text, bv, 0, owner.height());
219 expose(0, 0, owner.workWidth(), owner.height());
224 void LyXScreen::showCursor(LyXText const * text, BufferView const * bv)
226 if (!cursor_visible) {
227 Cursor_Shape shape = BAR_SHAPE;
228 if (text->real_current_font.language() !=
229 bv->buffer()->params.language
230 || text->real_current_font.isVisibleRightToLeft()
231 != bv->buffer()->params.language->RightToLeft())
232 shape = (text->real_current_font.isVisibleRightToLeft())
233 ? REVERSED_L_SHAPE : L_SHAPE;
234 showManualCursor(text, text->cursor.x(), text->cursor.y(),
235 lyxfont::maxAscent(text->real_current_font),
236 lyxfont::maxDescent(text->real_current_font),
242 /* returns true if first has changed, otherwise false */
243 bool LyXScreen::fitManualCursor(LyXText * text, BufferView * bv,
244 int /*x*/, int y, int asc, int desc)
246 int newtop = text->first;
248 if (y + desc - text->first >= static_cast<int>(owner.height()))
249 newtop = y - 3 * owner.height() / 4; // the scroll region must be so big!!
250 else if (y - asc < static_cast<int>(text->first)
251 && text->first > 0) {
252 newtop = y - owner.height() / 4;
255 newtop = max(newtop, 0); // can newtop ever be < 0? (Lgb)
257 if (newtop != static_cast<int>(text->first)) {
258 draw(text, bv, newtop);
259 text->first = newtop;
266 void LyXScreen::showManualCursor(LyXText const * text, int x, int y,
267 int asc, int desc, Cursor_Shape shape)
269 // Update the cursor color.
272 int const y1 = max(y - text->first - asc, 0);
273 int const y_tmp = min(y - text->first + desc,
274 static_cast<int>(owner.height()));
276 // Secure against very strange situations
277 int const y2 = max(y_tmp, y1);
280 XFreePixmap(fl_get_display(), cursor_pixmap);
284 if (y2 > 0 && y1 < int(owner.height())) {
285 cursor_pixmap_h = y2 - y1 + 1;
286 cursor_pixmap_y = y1;
294 cursor_pixmap_w = cursor_pixmap_h/3;
297 case REVERSED_L_SHAPE:
298 cursor_pixmap_w = cursor_pixmap_h/3;
299 cursor_pixmap_x = x - cursor_pixmap_w + 1;
304 XCreatePixmap (fl_get_display(),
308 fl_get_visual_depth());
309 XCopyArea (fl_get_display(),
313 owner.xpos() + cursor_pixmap_x,
314 owner.ypos() + cursor_pixmap_y,
318 XDrawLine(fl_get_display(),
329 case REVERSED_L_SHAPE:
330 int const rectangle_h = (cursor_pixmap_h + 10) / 20;
331 XFillRectangle(fl_get_display(),
334 cursor_pixmap_x + owner.xpos(),
335 y2 - rectangle_h + 1 + owner.ypos(),
336 cursor_pixmap_w - 1, rectangle_h);
341 cursor_visible = true;
345 void LyXScreen::hideCursor()
347 if (!cursor_visible) return;
350 XCopyArea (fl_get_display(),
355 cursor_pixmap_w, cursor_pixmap_h,
356 cursor_pixmap_x + owner.xpos(),
357 cursor_pixmap_y + owner.ypos());
359 cursor_visible = false;
363 void LyXScreen::cursorToggle(LyXText const * text, BufferView const * bv)
368 showCursor(text, bv);
372 /* returns a new top so that the cursor is visible */
373 unsigned int LyXScreen::topCursorVisible(LyXText const * text)
375 int newtop = text->first;
378 - text->cursor.row()->baseline()
379 + text->cursor.row()->height()
380 - text->first >= owner.height()) {
381 if (text->cursor.row()->height() < owner.height()
382 && text->cursor.row()->height() > owner.height() / 4)
383 newtop = text->cursor.y()
384 + text->cursor.row()->height()
385 - text->cursor.row()->baseline() - owner.height();
387 newtop = text->cursor.y()
388 - 3 * owner.height() / 4; /* the scroll region must be so big!! */
389 } else if (static_cast<int>((text->cursor.y()) - text->cursor.row()->baseline()) <
390 text->first && text->first > 0)
392 if (text->cursor.row()->height() < owner.height()
393 && text->cursor.row()->height() > owner.height() / 4)
394 newtop = text->cursor.y() - text->cursor.row()->baseline();
396 newtop = text->cursor.y() - owner.height() / 4;
397 newtop = min(newtop, int(text->first));
401 newtop = max(newtop, 0);
407 /* scrolls the screen so that the cursor is visible, if necessary.
408 * returns true if a change was made, otherwise false */
409 bool LyXScreen::fitCursor(LyXText * text, BufferView * bv)
411 // Is a change necessary?
412 int const newtop = topCursorVisible(text);
413 bool const result = (newtop != text->first);
415 draw(text, bv, newtop);
420 void LyXScreen::update(LyXText * text, BufferView * bv,
421 int y_offset, int x_offset)
423 switch (text->status()) {
424 case LyXText::NEED_MORE_REFRESH:
426 int const y = max(int(text->refresh_y - text->first), 0);
427 drawFromTo(text, bv, y, owner.height(), y_offset, x_offset);
429 text->status(bv, LyXText::UNCHANGED);
430 expose(0, y, owner.workWidth(), owner.height() - y);
433 case LyXText::NEED_VERY_LITTLE_REFRESH:
435 // ok I will update the current cursor row
436 drawOneRow(text, bv, text->refresh_row, text->refresh_y,
438 text->status(bv, LyXText::UNCHANGED);
439 expose(0, text->refresh_y - text->first + y_offset,
440 owner.workWidth(), text->refresh_row->height());
443 case LyXText::CHANGED_IN_DRAW: // just to remove the warning
444 case LyXText::UNCHANGED:
445 // Nothing needs done
451 void LyXScreen::toggleSelection(LyXText * text, BufferView * bv,
453 int y_offset, int x_offset)
455 // only if there is a selection
456 if (!text->selection.set()) return;
458 int const bottom = min(
459 max(static_cast<int>(text->selection.end.y()
460 - text->selection.end.row()->baseline()
461 + text->selection.end.row()->height()),
463 static_cast<int>(text->first + owner.height()));
465 max(static_cast<int>(text->selection.start.y() -
466 text->selection.start.row()->baseline()),
468 static_cast<int>(text->first + owner.height()));
471 text->selection.set(false);
472 drawFromTo(text, bv, top - text->first, bottom - text->first,
474 expose(0, top - text->first,
476 bottom - text->first - (top - text->first));
480 void LyXScreen::toggleToggle(LyXText * text, BufferView * bv,
481 int y_offset, int x_offset)
483 if (text->toggle_cursor.par() == text->toggle_end_cursor.par()
484 && text->toggle_cursor.pos() == text->toggle_end_cursor.pos())
487 int const top_tmp = text->toggle_cursor.y()
488 - text->toggle_cursor.row()->baseline();
489 int const bottom_tmp = text->toggle_end_cursor.y()
490 - text->toggle_end_cursor.row()->baseline()
491 + text->toggle_end_cursor.row()->height();
493 int const bottom = min(max(bottom_tmp, text->first),
494 static_cast<int>(text->first + owner.height()));
495 int const top = min(max(top_tmp, text->first),
496 static_cast<int>(text->first + owner.height()));
498 drawFromTo(text, bv, top - text->first, bottom - text->first, y_offset,
500 expose(0, top - text->first, owner.workWidth(),
501 bottom - text->first - (top - text->first));