X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fscreen.C;h=79ac58e5ae6153d43421d4ea10d0b342ae94aaf9;hb=558e849e692cc72ea74ac3859405b85e54c6e315;hp=79dd6542d522a623e8ffe9179e8d673e1b530a8e;hpb=021ad027a9d378b5d6e2e78ed768428867e1f7a8;p=lyx.git diff --git a/src/frontends/screen.C b/src/frontends/screen.C index 79dd6542d5..79ac58e5ae 100644 --- a/src/frontends/screen.C +++ b/src/frontends/screen.C @@ -1,547 +1,311 @@ -/* This file is part of -* ====================================================== -* -* LyX, The Document Processor -* -* Copyright 1995 Matthias Ettrich -* Copyright 1995-1998 The LyX Team -* -* ====================================================== */ +/** + * \file screen.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author John Levon + * + * Full author contact details are available in file CREDITS. + * + * Splash screen code added by Angus Leeming + */ #include -#ifdef __GNUG__ -#pragma implementation -#endif - -#include - #include "screen.h" -#include "lyxtext.h" -#include "lyxrow.h" -#include "frontends/Painter.h" -#include "frontends/WorkArea.h" -#include "buffer.h" -#include "BufferView.h" #include "font_metrics.h" -#include "insets/insettext.h" -#include "frontends/xforms/ColorHandler.h" +#include "lyx_gui.h" +#include "Painter.h" +#include "WorkArea.h" + +#include "BufferView.h" +#include "buffer.h" +#include "bufferparams.h" +#include "cursor.h" +#include "debug.h" #include "language.h" +#include "LColor.h" +#include "lyxfont.h" +#include "lyxrc.h" +#include "lyxrow.h" +#include "lyxtext.h" +#include "metricsinfo.h" +#include "paragraph.h" +#include "rowpainter.h" +#include "version.h" -using std::max; -using std::min; +#include "insets/updatableinset.h" -namespace { +#include "graphics/GraphicsImage.h" +#include "graphics/GraphicsLoader.h" -GC createGC() -{ - XGCValues val; - val.foreground = BlackPixel(fl_get_display(), - DefaultScreen(fl_get_display())); - - val.function = GXcopy; - val.graphics_exposures = false; - val.line_style = LineSolid; - val.line_width = 0; - return XCreateGC(fl_get_display(), RootWindow(fl_get_display(), 0), - GCForeground | GCFunction | GCGraphicsExposures - | GCLineWidth | GCLineStyle , &val); -} +#include "support/filetools.h" // LibFileSearch -} // namespace anon +#include +#include +#include +using lyx::support::LibFileSearch; -// Constructor -LScreen::LScreen(WorkArea & o) - : owner(o), force_clear(true) -{ - // the cursor isnt yet visible - cursor_visible = false; - cursor_pixmap = 0; - cursor_pixmap_x = 0; - cursor_pixmap_y = 0; - cursor_pixmap_w = 0; - cursor_pixmap_h = 0; - - // We need this GC - gc_copy = createGC(); -} +using std::endl; +using std::min; +using std::max; +using std::string; -LScreen::~LScreen() -{ - XFreeGC(fl_get_display(), gc_copy); -} - +namespace { -void LScreen::reset() -{ - XFreeGC(fl_get_display(), gc_copy); - // the cursor isnt yet visible - cursor_visible = false; - cursor_pixmap = 0; - cursor_pixmap_x = 0; - cursor_pixmap_y = 0; - cursor_pixmap_w = 0; - cursor_pixmap_h = 0; - - // We need this GC - gc_copy = createGC(); -} - - -void LScreen::setCursorColor() -{ - if (!lyxColorHandler.get()) return; +class SplashScreen : boost::noncopyable, boost::signals::trackable { +public: + /// This is a singleton class. Get the instance. + static SplashScreen const & get(); + /// + lyx::graphics::Image const * image() const { return loader_.image(); } + /// + string const & text() const { return text_; } + /// + LyXFont const & font() const { return font_; } + /// + void connect(lyx::graphics::Loader::slot_type const & slot) const { + loader_.connect(slot); + } + /// + void startLoading() const { + if (loader_.status() == lyx::graphics::WaitingToLoad) + loader_.startLoading(); + } - GC gc = lyxColorHandler->getGCForeground(LColor::cursor); +private: + /** Make the c-tor private so we can control how many objects + * are instantiated. + */ + SplashScreen(); - XGCValues val; - XGetGCValues(fl_get_display(), - gc, GCForeground, &val); - XChangeGC(fl_get_display(), gc_copy, GCForeground, &val); -} + /// + lyx::graphics::Loader loader_; + /// The text to be written on top of the pixmap + string const text_; + /// in this font... + LyXFont font_; +}; -void LScreen::redraw(LyXText * text, BufferView * bv) +SplashScreen const & SplashScreen::get() { - drawFromTo(text, bv, 0, owner.workHeight(), 0, 0, text == bv->text); - expose(0, 0, owner.workWidth(), owner.workHeight()); - if (cursor_visible) { - cursor_visible = false; - bv->showCursor(); - } + static SplashScreen singleton; + return singleton; } -void LScreen::expose(int x, int y, int exp_width, int exp_height) +SplashScreen::SplashScreen() + : text_(lyx_version ? lyx_version : "unknown") { - XCopyArea(fl_get_display(), - owner.getPixmap(), - owner.getWin(), - gc_copy, - x, y, - exp_width, exp_height, - x + owner.xpos(), - y + owner.ypos()); -} + if (!lyxrc.show_banner) + return; + string const file = LibFileSearch("images", "banner", "ppm"); + if (file.empty()) + return; -void LScreen::drawFromTo(LyXText * text, BufferView * bv, - int y1, int y2, int y_offset, int x_offset, - bool internal) -{ - int y_text = text->first_y + y1; - - // get the first needed row - Row * row = text->getRowNearY(y_text); - // y_text is now the real beginning of the row - - int y = y_text - text->first_y; - // y1 is now the real beginning of row on the screen - - while (row != 0 && y < y2) { - LyXText::text_status st = text->status(); - text->getVisibleRow(bv, y + y_offset, - x_offset, row, y + text->first_y); - internal = internal && (st != LyXText::CHANGED_IN_DRAW); - while (internal && text->status() == LyXText::CHANGED_IN_DRAW) { - text->fullRebreak(bv); - st = LyXText::NEED_MORE_REFRESH; - text->setCursor(bv, text->cursor.par(), - text->cursor.pos()); - text->status(bv, st); - // we should be sure our row-pointer is still valid, so it's - // better to recompute it. - y_text = y + text->first_y; - row = text->getRowNearY(y_text); - y = y_text - text->first_y; - text->getVisibleRow(bv, y + y_offset, - x_offset, row, y + text->first_y); - } - y += row->height(); - row = row->next(); - } - force_clear = false; + // The font used to display the version info + font_.setFamily(LyXFont::SANS_FAMILY); + font_.setSeries(LyXFont::BOLD_SERIES); + font_.setSize(LyXFont::SIZE_NORMAL); + font_.setColor(LColor::yellow); - // maybe we have to clear the screen at the bottom - if ((y < y2) && text->bv_owner) { - owner.getPainter().fillRectangle(0, y, - owner.workWidth(), - y2 - y, - LColor::bottomarea); - } + // Load up the graphics file + loader_.reset(file); } - -void LScreen::drawOneRow(LyXText * text, BufferView * bv, Row * row, - int y_text, int y_offset, int x_offset) -{ - int const y = y_text - text->first_y + y_offset; - - if (((y + row->height()) > 0) && - ((y - row->height()) <= static_cast(owner.workHeight()))) { - // ok there is something visible - text->getVisibleRow(bv, y, x_offset, row, y + text->first_y); - } - force_clear = false; -} +} // namespace anon -/* draws the screen, starting with textposition y. uses as much already - * printed pixels as possible */ -void LScreen::draw(LyXText * text, BufferView * bv, unsigned int y) +LyXScreen::LyXScreen() + : cursor_visible_(false), greyed_out_(true) { - if (cursor_visible) hideCursor(); - - int const old_first = text->first_y; - bool internal = (text == bv->text); - text->first_y = y; - - // is any optimiziation possible? - if ((y - old_first) < owner.workHeight() - && (old_first - y) < owner.workHeight()) - { - if (text->first_y < old_first) { - drawFromTo(text, bv, 0, - old_first - text->first_y, 0, 0, internal); - XCopyArea (fl_get_display(), - owner.getWin(), - owner.getWin(), - gc_copy, - owner.xpos(), - owner.ypos(), - owner.workWidth(), - owner.workHeight() - old_first + text->first_y, - owner.xpos(), - owner.ypos() + old_first - text->first_y - ); - // expose the area drawn - expose(0, 0, - owner.workWidth(), - old_first - text->first_y); - } else { - drawFromTo(text, bv, - owner.workHeight() + old_first - text->first_y, - owner.workHeight(), 0, 0, internal); - XCopyArea (fl_get_display(), - owner.getWin(), - owner.getWin(), - gc_copy, - owner.xpos(), - owner.ypos() + text->first_y - old_first, - owner.workWidth(), - owner.workHeight() + old_first - text->first_y, - owner.xpos(), - owner.ypos()); - // expose the area drawn - expose(0, owner.workHeight() + old_first - text->first_y, - owner.workWidth(), text->first_y - old_first); - } - } else { - // make a dumb new-draw - drawFromTo(text, bv, 0, owner.workHeight(), 0, 0, internal); - expose(0, 0, owner.workWidth(), owner.workHeight()); + // Start loading the pixmap as soon as possible + if (lyxrc.show_banner) { + SplashScreen const & splash = SplashScreen::get(); + splash.connect(boost::bind(&LyXScreen::greyOut, this)); + splash.startLoading(); } } -void LScreen::showCursor(LyXText const * text, BufferView const * bv) +LyXScreen::~LyXScreen() { - if (!cursor_visible) { - Cursor_Shape shape = BAR_SHAPE; - if (text->real_current_font.language() != - bv->buffer()->params.language - || text->real_current_font.isVisibleRightToLeft() - != bv->buffer()->params.language->RightToLeft()) - shape = (text->real_current_font.isVisibleRightToLeft()) - ? REVERSED_L_SHAPE : L_SHAPE; - showManualCursor(text, text->cursor.x(), text->cursor.y(), - font_metrics::maxAscent(text->real_current_font), - font_metrics::maxDescent(text->real_current_font), - shape); - } } -/* returns true if first has changed, otherwise false */ -bool LScreen::fitManualCursor(LyXText * text, BufferView * bv, - int /*x*/, int y, int asc, int desc) +void LyXScreen::showCursor(BufferView & bv) { - int newtop = text->first_y; - - if (y + desc - text->first_y >= static_cast(owner.workHeight())) - newtop = y - 3 * owner.workHeight() / 4; // the scroll region must be so big!! - else if (y - asc < text->first_y - && text->first_y > 0) { - newtop = y - owner.workHeight() / 4; - } - - newtop = max(newtop, 0); // can newtop ever be < 0? (Lgb) - - if (newtop != text->first_y) { - draw(text, bv, newtop); - text->first_y = newtop; - return true; - } - return false; -} + // this is needed to make sure we copy back the right + // pixmap on the hide for the Qt frontend + lyx_gui::sync_events(); + if (cursor_visible_) + return; -void LScreen::showManualCursor(LyXText const * text, int x, int y, - int asc, int desc, Cursor_Shape shape) -{ - // Update the cursor color. - setCursorColor(); + if (!bv.available()) + return; - int const y1 = max(y - text->first_y - asc, 0); - int const y_tmp = min(y - text->first_y + desc, - static_cast(owner.workHeight())); + Cursor_Shape shape = BAR_SHAPE; - // Secure against very strange situations - int const y2 = max(y_tmp, y1); + LyXText const & text = *bv.getLyXText(); + LyXFont const & realfont = text.real_current_font; + BufferParams const & bp = bv.buffer()->params(); + bool const samelang = realfont.language() == bp.language; + bool const isrtl = realfont.isVisibleRightToLeft(); - if (cursor_pixmap) { - XFreePixmap(fl_get_display(), cursor_pixmap); - cursor_pixmap = 0; + if (!samelang || isrtl != bp.language->RightToLeft()) { + shape = L_SHAPE; + if (isrtl) + shape = REVERSED_L_SHAPE; } - if (y2 > 0 && y1 < int(owner.workHeight())) { - cursor_pixmap_h = y2 - y1 + 1; - cursor_pixmap_y = y1; - - switch (shape) { - case BAR_SHAPE: - cursor_pixmap_w = 1; - cursor_pixmap_x = x; - break; - case L_SHAPE: - cursor_pixmap_w = cursor_pixmap_h/3; - cursor_pixmap_x = x; - break; - case REVERSED_L_SHAPE: - cursor_pixmap_w = cursor_pixmap_h/3; - cursor_pixmap_x = x - cursor_pixmap_w + 1; - break; - } - - cursor_pixmap = - XCreatePixmap (fl_get_display(), - fl_root, - cursor_pixmap_w, - cursor_pixmap_h, - fl_get_visual_depth()); - XCopyArea (fl_get_display(), - owner.getWin(), - cursor_pixmap, - gc_copy, - owner.xpos() + cursor_pixmap_x, - owner.ypos() + cursor_pixmap_y, - cursor_pixmap_w, - cursor_pixmap_h, - 0, 0); - XDrawLine(fl_get_display(), - owner.getWin(), - gc_copy, - x + owner.xpos(), - y1 + owner.ypos(), - x + owner.xpos(), - y2 + owner.ypos()); - switch (shape) { - case BAR_SHAPE: - break; - case L_SHAPE: - case REVERSED_L_SHAPE: - int const rectangle_h = (cursor_pixmap_h + 10) / 20; - XFillRectangle(fl_get_display(), - owner.getWin(), - gc_copy, - cursor_pixmap_x + owner.xpos(), - y2 - rectangle_h + 1 + owner.ypos(), - cursor_pixmap_w - 1, rectangle_h); - break; - } + // The ERT language hack needs fixing up + if (realfont.language() == latex_language) + shape = BAR_SHAPE; + + int ascent = font_metrics::maxAscent(realfont); + int descent = font_metrics::maxDescent(realfont); + int h = ascent + descent; + int x = 0; + int y = 0; + bv.cursor().getPos(x, y); + y -= ascent + bv.top_y(); + //lyxerr << "LyXScreen::showCursor x: " << x << " y: " << y << endl; + + // if it doesn't fit entirely on the screen, don't try to show it + if (y < 0 || y + h > workarea().workHeight()) + return; - } - cursor_visible = true; + cursor_visible_ = true; + showCursor(x, y, h, shape); } -void LScreen::hideCursor() +void LyXScreen::hideCursor() { - if (!cursor_visible) return; - - if (cursor_pixmap) { - XCopyArea (fl_get_display(), - cursor_pixmap, - owner.getWin(), - gc_copy, - 0, 0, - cursor_pixmap_w, cursor_pixmap_h, - cursor_pixmap_x + owner.xpos(), - cursor_pixmap_y + owner.ypos()); - } - cursor_visible = false; + if (!cursor_visible_) + return; + + cursor_visible_ = false; + removeCursor(); } -void LScreen::cursorToggle(BufferView * bv) const +void LyXScreen::toggleCursor(BufferView & bv) { - if (cursor_visible) - bv->hideCursor(); + if (cursor_visible_) + hideCursor(); else - bv->showCursor(); + showCursor(bv); } -/* returns a new top so that the cursor is visible */ -unsigned int LScreen::topCursorVisible(LyXCursor const & cursor, int top_y) +bool LyXScreen::fitCursor(BufferView * bv) { - int const vheight = owner.workHeight(); - int newtop = top_y; - - Row * row = cursor.row(); - - // Is this a hack? Yes, probably... (Lgb) - if (!row) - return max(newtop, 0); - - if (cursor.y() - row->baseline() + row->height() - - top_y >= vheight) { - if (row->height() < vheight - && row->height() > vheight / 4) { - newtop = cursor.y() - + row->height() - - row->baseline() - vheight; - } else { - // scroll down - newtop = cursor.y() - - vheight / 2; /* the scroll region must be so big!! */ - } - - } else if (static_cast(cursor.y() - row->baseline()) < - top_y && top_y > 0) { - if (row->height() < vheight - && row->height() > vheight / 4) { - newtop = cursor.y() - row->baseline(); - } else { - // scroll up - newtop = cursor.y() - vheight / 2; + int const top_y = bv->top_y(); + int const h = workarea().workHeight(); + int newtop = top_y; + int x, y, asc, desc; + + bv->cursor().getPos(x, y); + bv->cursor().getDim(asc, desc); + lyxerr[Debug::DEBUG] << "LyXScreen::fitCursor: x: " << x + << " y: " << y + << " top_y: " << top_y + << endl; + + bool const big_row = h / 4 < asc + desc && asc + desc < h; + + if (y + desc - top_y >= h) { + if (big_row) + newtop = y + desc - h; + else + newtop = y - h / 2; + + } else if (top_y > max(y - asc, 0)) { + if (big_row) + newtop = y - asc; + else { + newtop = y - h / 2; newtop = min(newtop, top_y); } } newtop = max(newtop, 0); + if (newtop == top_y) + return false; - return newtop; + bv->top_y(newtop); + return true; } -/* scrolls the screen so that the cursor is visible, if necessary. -* returns true if a change was made, otherwise false */ -bool LScreen::fitCursor(LyXText * text, BufferView * bv) +void LyXScreen::redraw(BufferView & bv) { - // Is a change necessary? - int const newtop = topCursorVisible(text->cursor, text->first_y); - bool const result = (newtop != text->first_y); - if (result) - draw(text, bv, newtop); - return result; -} - + greyed_out_ = !bv.text(); -void LScreen::update(LyXText * text, BufferView * bv, - int y_offset, int x_offset) -{ - switch (text->status()) { - case LyXText::NEED_MORE_REFRESH: - { - int const y = max(int(text->refresh_y - text->first_y), 0); - drawFromTo(text, bv, y, owner.workHeight(), y_offset, x_offset); - text->refresh_y = 0; - // otherwise this is called ONLY from BufferView_pimpl(update) - // or we should see to set this flag accordingly - if (text != bv->text) - text->status(bv, LyXText::UNCHANGED); - expose(0, y, owner.workWidth(), owner.workHeight() - y); - } - break; - case LyXText::NEED_VERY_LITTLE_REFRESH: - { - // ok I will update the current cursor row - drawOneRow(text, bv, text->refresh_row, text->refresh_y, - y_offset, x_offset); - // this because if we had a major update the refresh_row could - // have been set to 0! - if (text->refresh_row) { - // otherwise this is called ONLY from BufferView_pimpl(update) - // or we should see to set this flag accordingly - if (text != bv->text) - text->status(bv, LyXText::UNCHANGED); - expose(0, text->refresh_y - text->first_y + y_offset, - owner.workWidth(), text->refresh_row->height()); - } + if (greyed_out_) { + greyOut(); + return; } - break; - case LyXText::CHANGED_IN_DRAW: // just to remove the warning - case LyXText::UNCHANGED: - // Nothing needs done - break; + + workarea().getPainter().start(); + + hideCursor(); + + int const y = paintText(bv); + + // maybe we have to clear the screen at the bottom + int const y2 = workarea().workHeight(); + if (y < y2 && bv.text()->isMainText()) { + workarea().getPainter().fillRectangle(0, y, + workarea().workWidth(), y2 - y, + LColor::bottomarea); } -} + lyxerr[Debug::DEBUG] << "Redraw screen" << endl; -void LScreen::toggleSelection(LyXText * text, BufferView * bv, - bool kill_selection, - int y_offset, int x_offset) -{ - // only if there is a selection - if (!text->selection.set()) return; - - int const bottom = min( - max(static_cast(text->selection.end.y() - - text->selection.end.row()->baseline() - + text->selection.end.row()->height()), - text->first_y), - static_cast(text->first_y + owner.workHeight())); - int const top = min( - max(static_cast(text->selection.start.y() - - text->selection.start.row()->baseline()), - text->first_y), - static_cast(text->first_y + owner.workHeight())); - - if (kill_selection) - text->selection.set(false); - drawFromTo(text, bv, top - text->first_y, bottom - text->first_y, - y_offset, x_offset); - expose(0, top - text->first_y, - owner.workWidth(), - bottom - text->first_y - (top - text->first_y)); + expose(0, 0, workarea().workWidth(), workarea().workHeight()); + + workarea().getPainter().end(); + + showCursor(bv); } -void LScreen::toggleToggle(LyXText * text, BufferView * bv, - int y_offset, int x_offset) +void LyXScreen::greyOut() { - if (text->toggle_cursor.par() == text->toggle_end_cursor.par() - && text->toggle_cursor.pos() == text->toggle_end_cursor.pos()) + if (!greyed_out_) return; - int const top_tmp = text->toggle_cursor.y() - - text->toggle_cursor.row()->baseline(); - int const bottom_tmp = text->toggle_end_cursor.y() - - text->toggle_end_cursor.row()->baseline() - + text->toggle_end_cursor.row()->height(); - - int const offset = y_offset < 0 ? y_offset : 0; - int const bottom = min(max(bottom_tmp, text->first_y), - static_cast(text->first_y + owner.workHeight()))-offset; - int const top = min(max(top_tmp, text->first_y), - static_cast(text->first_y + owner.workHeight()))-offset; - - drawFromTo(text, bv, top - text->first_y, - bottom - text->first_y, y_offset, - x_offset); - expose(0, top - text->first_y, owner.workWidth(), - bottom - text->first_y - (top - text->first_y)); + workarea().getPainter().start(); + + workarea().getPainter().fillRectangle(0, 0, + workarea().workWidth(), + workarea().workHeight(), + LColor::bottomarea); + + // Add a splash screen to the centre of the work area + SplashScreen const & splash = SplashScreen::get(); + lyx::graphics::Image const * const splash_image = splash.image(); + if (splash_image) { + int const w = splash_image->getWidth(); + int const h = splash_image->getHeight(); + + int x = (workarea().workWidth() - w) / 2; + int y = (workarea().workHeight() - h) / 2; + + workarea().getPainter().image(x, y, w, h, *splash_image); + + x += 260; + y += 265; + + workarea().getPainter().text(x, y, splash.text(), splash.font()); + } + expose(0, 0, workarea().workWidth(), workarea().workHeight()); + workarea().getPainter().end(); }