3 * Copyright 2002 the LyX Team
4 * Read the file COPYING
6 * \author John Levon <moz@compsoc.man.ac.uk>
10 #pragma implementation
18 #include "BufferView.h"
22 #include "font_metrics.h"
30 LyXScreen::LyXScreen()
31 : force_clear_(true), cursor_visible_(false)
36 LyXScreen::~LyXScreen()
40 // FIXME: GUII these cursor methods need to decide
41 // whether the workarea is focused or not
43 void LyXScreen::showCursor(LyXText const * text, BufferView const * bv)
48 workarea().getPainter().start();
50 Cursor_Shape shape = BAR_SHAPE;
51 BufferParams const & bp(bv->buffer()->params);
52 LyXFont const & realfont(text->real_current_font);
54 if (realfont.language() != bp.language
55 || realfont.isVisibleRightToLeft()
56 != bp.language->RightToLeft()) {
57 shape = (realfont.isVisibleRightToLeft())
58 ? REVERSED_L_SHAPE : L_SHAPE;
61 showManualCursor(text, text->cursor.x(), text->cursor.y(),
62 font_metrics::maxAscent(realfont),
63 font_metrics::maxDescent(realfont),
66 workarea().getPainter().end();
70 bool LyXScreen::fitManualCursor(BufferView * bv, LyXText * text,
71 int /*x*/, int y, int asc, int desc)
73 int const vheight = workarea().workHeight();
74 int newtop = text->first_y;
76 if (y + desc - text->first_y >= vheight)
77 newtop = y - 3 * vheight / 4; // the scroll region must be so big!!
78 else if (y - asc < text->first_y
79 && text->first_y > 0) {
80 newtop = y - vheight / 4;
83 newtop = max(newtop, 0); // can newtop ever be < 0? (Lgb)
85 if (newtop != text->first_y) {
86 draw(text, bv, newtop);
87 text->first_y = newtop;
94 void LyXScreen::cursorToggle(BufferView * bv) const
103 unsigned int LyXScreen::topCursorVisible(LyXCursor const & cursor, int top_y)
105 int const vheight = workarea().workHeight();
108 Row * row = cursor.row();
110 // Is this a hack? Yes, probably... (Lgb)
112 return max(newtop, 0);
114 if (cursor.y() - row->baseline() + row->height()
115 - top_y >= vheight) {
116 if (row->height() < vheight
117 && row->height() > vheight / 4) {
120 - row->baseline() - vheight;
124 - vheight / 2; /* the scroll region must be so big!! */
127 } else if (static_cast<int>((cursor.y()) - row->baseline()) <
128 top_y && top_y > 0) {
129 if (row->height() < vheight
130 && row->height() > vheight / 4) {
131 newtop = cursor.y() - row->baseline();
134 newtop = cursor.y() - vheight / 2;
135 newtop = min(newtop, top_y);
139 newtop = max(newtop, 0);
145 bool LyXScreen::fitCursor(LyXText * text, BufferView * bv)
147 // Is a change necessary?
148 int const newtop = topCursorVisible(text->cursor, text->first_y);
149 bool const result = (newtop != text->first_y);
151 draw(text, bv, newtop);
156 void LyXScreen::update(LyXText * text, BufferView * bv,
159 int const vwidth = workarea().workWidth();
160 int const vheight = workarea().workHeight();
162 workarea().getPainter().start();
164 switch (text->status()) {
165 case LyXText::NEED_MORE_REFRESH:
167 int const y = max(int(text->refresh_y - text->first_y), 0);
168 drawFromTo(text, bv, y, vheight, yo, xo);
170 // otherwise this is called ONLY from BufferView_pimpl(update)
171 // or we should see to set this flag accordingly
172 if (text != bv->text)
173 text->status(bv, LyXText::UNCHANGED);
174 expose(0, y, vwidth, vheight - y);
177 case LyXText::NEED_VERY_LITTLE_REFRESH:
179 // ok I will update the current cursor row
180 drawOneRow(text, bv, text->refresh_row, text->refresh_y,
182 // this because if we had a major update the refresh_row could
183 // have been set to 0!
184 if (text->refresh_row) {
185 // otherwise this is called ONLY from BufferView_pimpl(update)
186 // or we should see to set this flag accordingly
187 if (text != bv->text)
188 text->status(bv, LyXText::UNCHANGED);
189 expose(0, text->refresh_y - text->first_y + yo,
190 vwidth, text->refresh_row->height());
194 case LyXText::CHANGED_IN_DRAW: // just to remove the warning
195 case LyXText::UNCHANGED:
196 // Nothing needs done
200 workarea().getPainter().end();
204 void LyXScreen::toggleSelection(LyXText * text, BufferView * bv,
208 // only if there is a selection
209 if (!text->selection.set()) return;
211 int const bottom = min(
212 max(static_cast<int>(text->selection.end.y()
213 - text->selection.end.row()->baseline()
214 + text->selection.end.row()->height()),
216 static_cast<int>(text->first_y + workarea().workHeight()));
218 max(static_cast<int>(text->selection.start.y() -
219 text->selection.start.row()->baseline()),
221 static_cast<int>(text->first_y + workarea().workHeight()));
224 text->selection.set(false);
226 workarea().getPainter().start();
228 drawFromTo(text, bv, top - text->first_y, bottom - text->first_y,
230 expose(0, top - text->first_y,
231 workarea().workWidth(),
232 bottom - text->first_y - (top - text->first_y));
234 workarea().getPainter().end();
238 void LyXScreen::toggleToggle(LyXText * text, BufferView * bv,
241 if (text->toggle_cursor.par() == text->toggle_end_cursor.par()
242 && text->toggle_cursor.pos() == text->toggle_end_cursor.pos())
245 int const top_tmp = text->toggle_cursor.y()
246 - text->toggle_cursor.row()->baseline();
247 int const bottom_tmp = text->toggle_end_cursor.y()
248 - text->toggle_end_cursor.row()->baseline()
249 + text->toggle_end_cursor.row()->height();
251 int const offset = yo < 0 ? yo : 0;
252 int const bottom = min(max(bottom_tmp, text->first_y),
253 static_cast<int>(text->first_y + workarea().workHeight())) - offset;
254 int const top = min(max(top_tmp, text->first_y),
255 static_cast<int>(text->first_y + workarea().workHeight())) - offset;
257 workarea().getPainter().start();
259 drawFromTo(text, bv, top - text->first_y,
260 bottom - text->first_y, yo,
262 expose(0, top - text->first_y, workarea().workWidth(),
263 bottom - text->first_y - (top - text->first_y));
265 workarea().getPainter().end();
269 void LyXScreen::redraw(LyXText * text, BufferView * bv)
271 workarea().getPainter().start();
275 expose(0, 0, workarea().workWidth(), workarea().workHeight());
276 workarea().getPainter().end();
280 drawFromTo(text, bv, 0, workarea().workHeight(), 0, 0, text == bv->text);
281 expose(0, 0, workarea().workWidth(), workarea().workHeight());
283 workarea().getPainter().end();
285 if (cursor_visible_) {
286 cursor_visible_ = false;
292 void LyXScreen::greyOut()
294 workarea().getPainter().fillRectangle(0, 0,
295 workarea().workWidth(),
296 workarea().workHeight(),
299 /* FIXME: pending GUIIzation / cleanup of graphics cache
302 static GImage splash(LibFileSearch(...));
303 workarea().getPainter().image(splash);
308 // Add a splash screen to the centre of the work area
309 string const splash_file = LibFileSearch("images", "banner", "xpm");
314 void LyXScreen::drawFromTo(LyXText * text, BufferView * bv,
315 int y1, int y2, int yo, int xo,
318 lyxerr[Debug::GUI] << "screen: drawFromTo " << y1 << "-" << y2 << endl;
320 int y_text = text->first_y + y1;
322 // get the first needed row
323 Row * row = text->getRowNearY(y_text);
324 // y_text is now the real beginning of the row
326 int y = y_text - text->first_y;
327 // y1 is now the real beginning of row on the screen
329 while (row != 0 && y < y2) {
330 LyXText::text_status st = text->status();
331 text->getVisibleRow(bv, y + yo,
332 xo, row, y + text->first_y);
333 internal = internal && (st != LyXText::CHANGED_IN_DRAW);
334 while (internal && text->status() == LyXText::CHANGED_IN_DRAW) {
335 text->fullRebreak(bv);
336 st = LyXText::NEED_MORE_REFRESH;
337 text->setCursor(bv, text->cursor.par(), text->cursor.pos());
338 text->status(bv, st);
339 text->getVisibleRow(bv, y + yo,
340 xo, row, y + text->first_y);
345 force_clear_ = false;
347 // maybe we have to clear the screen at the bottom
348 if ((y < y2) && text->bv_owner) {
349 workarea().getPainter().fillRectangle(0, y,
350 workarea().workWidth(), y2 - y,
356 void LyXScreen::drawOneRow(LyXText * text, BufferView * bv, Row * row,
357 int y_text, int yo, int xo)
359 int const y = y_text - text->first_y + yo;
361 if (((y + row->height()) > 0) &&
362 ((y - row->height()) <= static_cast<int>(workarea().workHeight()))) {
363 text->getVisibleRow(bv, y, xo, row, y + text->first_y);
365 force_clear_ = false;