You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1205 lines
24 KiB

#include "PageView.h"
#include "Cursor.h"
#include "RepaintHandler.h"
#include "TextEditor.h"
#include "XournalView.h"
#include "control/Control.h"
#include "control/SearchControl.h"
#include "control/settings/ButtonConfig.h"
#include "control/settings/Settings.h"
#include "control/jobs/BlockingJob.h"
#include "control/tools/ArrowHandler.h"
#include "control/tools/CircleHandler.h"
#include "control/tools/EraseHandler.h"
#include "control/tools/ImageHandler.h"
#include "control/tools/InputHandler.h"
#include "control/tools/RectangleHandler.h"
#include "control/tools/RulerHandler.h"
#include "control/tools/Selection.h"
#include "control/tools/StrokeHandler.h"
#include "control/tools/VerticalToolHandler.h"
#include "model/Image.h"
#include "model/Layer.h"
#include "model/PageRef.h"
#include "model/Stroke.h"
#include "model/Text.h"
#include "undo/DeleteUndoAction.h"
#include "undo/InsertUndoAction.h"
#include "undo/TextBoxUndoAction.h"
#include "view/TextView.h"
#include "widgets/XournalWidget.h"
#include <config.h>
#include <config-debug.h>
#include <i18n.h>
#include <pixbuf-utils.h>
#include <Range.h>
#include <Rectangle.h>
#include <gdk/gdk.h>
#include <stdlib.h>
#include <math.h>
string lastfn = "";
XojPageView::XojPageView(XournalView* xournal, PageRef page)
{
XOJ_INIT_TYPE(XojPageView);
this->page = page;
this->registerListener(this->page);
this->xournal = xournal;
this->selected = false;
this->settings = xournal->getControl()->getSettings();
this->lastVisibleTime = -1;
g_mutex_init(&this->drawingMutex);
this->rerenderComplete = false;
g_mutex_init(&this->repaintRectMutex);
this->crBuffer = NULL;
this->inEraser = false;
this->verticalSpace = NULL;
this->selection = NULL;
this->textEditor = NULL;
// this does not have to be deleted afterwards:
// (we need it for undo commands)
this->oldtext = NULL;
this->search = NULL;
this->eraser = new EraseHandler(xournal->getControl()->getUndoRedoHandler(), xournal->getControl()->getDocument(),
this->page, xournal->getControl()->getToolHandler(), this);
this->inputHandler = NULL;
}
XojPageView::~XojPageView()
{
XOJ_CHECK_TYPE(XojPageView);
// Unregister listener before destroying this handler
this->unregisterListener();
this->xournal->getControl()->getScheduler()->removePage(this);
delete this->inputHandler;
this->inputHandler = NULL;
delete this->eraser;
this->eraser = NULL;
endText();
deleteViewBuffer();
for (Rectangle* rect : this->rerenderRects)
{
delete rect;
}
this->rerenderRects.clear();
delete this->search;
this->search = NULL;
XOJ_RELEASE_TYPE(XojPageView);
}
void XojPageView::setIsVisible(bool visible)
{
XOJ_CHECK_TYPE(XojPageView);
if (visible)
{
this->lastVisibleTime = 0;
}
else if (this->lastVisibleTime <= 0)
{
GTimeVal val;
g_get_current_time(&val);
this->lastVisibleTime = val.tv_sec;
}
}
int XojPageView::getLastVisibleTime()
{
XOJ_CHECK_TYPE(XojPageView);
if (this->crBuffer == NULL)
{
return -1;
}
return this->lastVisibleTime;
}
void XojPageView::deleteViewBuffer()
{
XOJ_CHECK_TYPE(XojPageView);
g_mutex_lock(&this->drawingMutex);
if (this->crBuffer)
{
cairo_surface_destroy(this->crBuffer);
this->crBuffer = NULL;
}
g_mutex_unlock(&this->drawingMutex);
}
bool XojPageView::containsPoint(int x, int y, bool local)
{
XOJ_CHECK_TYPE(XojPageView);
if (!local)
{
bool leftOk = this->layout.getLayoutAbsoluteX() <= x;
bool rightOk = x <= this->layout.getLayoutAbsoluteX() + this->getDisplayWidth();
bool topOk = this->layout.getLayoutAbsoluteY() <= y;
bool bottomOk = y <= this->layout.getLayoutAbsoluteY() + this->getDisplayHeight();
return leftOk && rightOk && topOk && bottomOk;
}
else
{
return x >= 0 && y >= 0 && x <= this->getWidth() && y <= this->getHeight();
}
}
bool XojPageView::searchTextOnPage(string& text, int* occures, double* top)
{
XOJ_CHECK_TYPE(XojPageView);
if (this->search == NULL)
{
if (text.empty()) return true;
int pNr = this->page->getPdfPageNr();
XojPdfPageSPtr pdf = NULL;
if (pNr != -1)
{
Document* doc = xournal->getControl()->getDocument();
doc->lock();
pdf = doc->getPdfPage(pNr);
doc->unlock();
}
this->search = new SearchControl(page, pdf);
}
bool found = this->search->search(text, occures, top);
repaintPage();
return found;
}
void XojPageView::endText()
{
XOJ_CHECK_TYPE(XojPageView);
if (!this->textEditor)
{
return;
}
Text* txt = this->textEditor->getText();
Layer* layer = this->page->getSelectedLayer();
UndoRedoHandler* undo = xournal->getControl()->getUndoRedoHandler();
// Text deleted
if (txt->getText().empty())
{
// old element
int pos = layer->indexOf(txt);
if (pos != -1)
{
DeleteUndoAction* eraseDeleteUndoAction = new DeleteUndoAction(page, true);
layer->removeElement(txt, false);
eraseDeleteUndoAction->addElement(layer, txt, pos);
undo->addUndoAction(eraseDeleteUndoAction);
}
}
else
{
// new element
if (layer->indexOf(txt) == -1)
{
undo->addUndoActionBefore(new InsertUndoAction(page, layer, txt), this->textEditor->getFirstUndoAction());
layer->addElement(txt);
this->textEditor->textCopyed();
}
// or if the file was saved and reopened
// and/or if we click away from the text window
else
{
// TextUndoAction does not work because the textEdit object is destroyed
// after endText() so we need to instead copy the information between an
// old and new element that we can push and pop to recover.
undo->addUndoAction(new TextBoxUndoAction(page, layer, txt, this->oldtext));
}
}
delete this->textEditor;
this->textEditor = NULL;
this->rerenderPage();
}
void XojPageView::startText(double x, double y)
{
XOJ_CHECK_TYPE(XojPageView);
this->xournal->endTextAllPages(this);
this->xournal->getControl()->getSearchBar()->showSearchBar(false);
if (this->textEditor == NULL)
{
// Is there already a textfield?
Text* text = NULL;
for (Element* e : *this->page->getSelectedLayer()->getElements())
{
if (e->getType() == ELEMENT_TEXT)
{
GdkRectangle matchRect = { gint(x - 10), gint(y - 10), 20, 20 };
if (e->intersectsArea(&matchRect))
{
text = (Text*) e;
break;
}
}
}
bool ownText = false;
if (text == NULL)
{
ToolHandler* h = xournal->getControl()->getToolHandler();
ownText = true;
text = new Text();
text->setX(x);
text->setY(y);
text->setColor(h->getColor());
text->setFont(settings->getFont());
}
else
{
// We can try to add an undo action here. The initial text shows up in this
// textEditor element.
this->oldtext = text;
// text = new Text(*oldtext);
// need to clone the old text so that references still work properly.
// cloning breaks things a little. do it manually
text = new Text();
text->setX(oldtext->getX());
text->setY(oldtext->getY());
text->setColor(oldtext->getColor());
text->setFont(oldtext->getFont());
text->setText(oldtext->getText());
Layer* layer = this->page->getSelectedLayer();
layer->removeElement(this->oldtext, false);
layer->addElement(text);
// perform the old swap onto the new text drawn.
}
this->textEditor = new TextEditor(this, xournal->getWidget(), text, ownText);
if (!ownText)
{
this->textEditor->mousePressed(x - text->getX(), y - text->getY());
}
this->rerenderPage();
}
else
{
Text* text = this->textEditor->getText();
GdkRectangle matchRect = {gint(x - 10), gint(y - 10), 20, 20};
if (!text->intersectsArea(&matchRect))
{
endText();
}
else
{
this->textEditor->mousePressed(x - text->getX(), y - text->getY());
}
}
}
void XojPageView::playObjectAt(double x, double y)
{
XOJ_CHECK_TYPE(XojPageView);
int selected = this->page->getSelectedLayerId();
GdkRectangle matchRect =
{ gint(x - 10), gint(y - 10), 20, 20 };
double gap = 1000000000;
// clear old selection anyway
this->xournal->getControl()->clearSelection();
for (Layer* l : *this->page->getLayers())
{
for (Element* e : *l->getElements())
{
if (e->intersectsArea(&matchRect))
{
if (e->getType() == ELEMENT_STROKE)
{
Stroke* s = (Stroke*) e;
double tmpGap = 0;
if ((s->intersects(x, y, 15, &tmpGap)) && (gap > tmpGap))
{
gap = tmpGap;
int ts = s->getTimestamp();
int buffer = 5;
if (ts >= buffer)
{
ts -= buffer;
}
else
{
ts = 0;
}
string fn = s->getAudioFilename();
if (fn != lastfn)
{
if (fn != "")
{
lastfn = fn;
string command(
"vlc --qt-start-minimized " + settings->getAudioFolder() + "/" + fn + " --start-time="
+ std::to_string(ts) + " &>/dev/null &");
system(command.c_str());
}
}
else
{
//TODO: substitute system(..) with some c++ curl library
string psw("password");
string command(
"curl -s -u \"\":\""+psw+"\" --url \"http://127.0.0.1:8080/requests/status.xml?command=seek&val="
+ std::to_string(ts) + "\" >/dev/null"
+ "&& curl -s -u \"\":\""+psw+"\" --url \"http://127.0.0.1:8080/requests/status.xml?command=pl_play\" >/dev/null");
system(command.c_str());
}
}
}
}
}
selected--;
}
}
void XojPageView::selectObjectAt(double x, double y)
{
XOJ_CHECK_TYPE(XojPageView);
int selected = this->page->getSelectedLayerId();
GdkRectangle matchRect = { gint(x - 10), gint(y - 10), 20, 20 };
Stroke* strokeMatch = NULL;
double gap = 1000000000;
Element* elementMatch = NULL;
// clear old selection anyway
this->xournal->getControl()->clearSelection();
for (Layer* l : *this->page->getLayers())
{
for (Element* e : *l->getElements())
{
if (e->intersectsArea(&matchRect))
{
if (e->getType() == ELEMENT_STROKE)
{
Stroke* s = (Stroke*) e;
double tmpGap = 0;
if ((s->intersects(x, y, 5, &tmpGap)) && (gap > tmpGap))
{
gap = tmpGap;
strokeMatch = s;
}
}
else
{
elementMatch = e;
}
}
}
selected--;
}
if (strokeMatch)
{
elementMatch = strokeMatch;
}
if (elementMatch)
{
xournal->setSelection(new EditSelection(xournal->getControl()->getUndoRedoHandler(), elementMatch, this, page));
repaintPage();
}
}
bool XojPageView::onButtonPressEvent(const PositionInputData& pos)
{
XOJ_CHECK_TYPE(XojPageView);
if ((pos.state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) != 0)
{
return false; // not handled here
}
if (!this->selected)
{
xournal->getControl()->firePageSelected(this->page);
}
ToolHandler* h = xournal->getControl()->getToolHandler();
double x = pos.x;
double y = pos.y;
if (x < 0 || y < 0)
{
return false;
}
double zoom = xournal->getZoom();
x /= zoom;
y /= zoom;
Cursor* cursor = xournal->getCursor();
cursor->setMouseDown(true);
if (h->getToolType() == TOOL_PEN || h->getToolType() == TOOL_HILIGHTER ||
(h->getToolType() == TOOL_ERASER && h->getEraserType() == ERASER_TYPE_WHITEOUT))
{
delete this->inputHandler;
this->inputHandler = NULL;
if (h->getDrawingType() == DRAWING_TYPE_LINE)
{
this->inputHandler = new RulerHandler(this->xournal, this, getPage());
}
else if (h->getDrawingType() == DRAWING_TYPE_RECTANGLE)
{
this->inputHandler = new RectangleHandler(this->xournal, this, getPage());
}
else if (h->getDrawingType() == DRAWING_TYPE_CIRCLE)
{
this->inputHandler = new CircleHandler(this->xournal, this, getPage());
}
else if (h->getDrawingType() == DRAWING_TYPE_ARROW)
{
this->inputHandler = new ArrowHandler(this->xournal, this, getPage());
}
else
{
this->inputHandler = new StrokeHandler(this->xournal, this, getPage());
}
this->inputHandler->onButtonPressEvent(pos);
}
else if(h->getToolType() == TOOL_ERASER)
{
this->eraser->erase(x, y);
this->inEraser = true;
}
else if (h->getToolType() == TOOL_VERTICAL_SPACE)
{
this->verticalSpace = new VerticalToolHandler(this, this->page, y, zoom);
}
else if (h->getToolType() == TOOL_SELECT_RECT ||
h->getToolType() == TOOL_SELECT_REGION ||
h->getToolType() == TOOL_PLAY_OBJECT ||
h->getToolType() == TOOL_SELECT_OBJECT)
{
if (h->getToolType() == TOOL_SELECT_RECT)
{
if (this->selection)
{
delete this->selection;
this->selection = NULL;
repaintPage();
}
this->selection = new RectSelection(x, y, this);
}
else if (h->getToolType() == TOOL_SELECT_REGION)
{
if (this->selection)
{
delete this->selection;
this->selection = NULL;
repaintPage();
}
this->selection = new RegionSelect(x, y, this);
}
else if (h->getToolType() == TOOL_SELECT_OBJECT)
{
selectObjectAt(x, y);
}
else if (h->getToolType() == TOOL_PLAY_OBJECT)
{
playObjectAt(x, y);
}
}
else if (h->getToolType() == TOOL_TEXT)
{
startText(x, y);
}
else if (h->getToolType() == TOOL_IMAGE)
{
ImageHandler imgHandler(xournal->getControl(), this);
imgHandler.insertImage(x, y);
}
return true;
}
void XojPageView::resetShapeRecognizer()
{
XOJ_CHECK_TYPE(XojPageView);
if (this->inputHandler != NULL)
{
this->inputHandler->resetShapeRecognizer();
}
}
bool XojPageView::onMotionNotifyEvent(const PositionInputData& pos)
{
XOJ_CHECK_TYPE(XojPageView);
double zoom = xournal->getZoom();
double x = pos.x / zoom;
double y = pos.y / zoom;
ToolHandler* h = xournal->getControl()->getToolHandler();
if (containsPoint(x, y, true) &&
this->inputHandler &&
this->inputHandler->onMotionNotifyEvent(pos))
{
//input handler used this event
}
else if (this->selection)
{
this->selection->currentPos(x, y);
}
else if (this->verticalSpace)
{
this->verticalSpace->currentPos(x, y);
}
else if (this->textEditor)
{
Cursor* cursor = getXournal()->getCursor();
cursor->setInvisible(false);
Text* text = this->textEditor->getText();
this->textEditor->mouseMoved(x - text->getX(), y - text->getY());
}
else if (h->getToolType() == TOOL_ERASER && h->getEraserType() != ERASER_TYPE_WHITEOUT && this->inEraser)
{
this->eraser->erase(x, y);
}
return false;
}
bool XojPageView::onButtonReleaseEvent(const PositionInputData& pos)
{
XOJ_CHECK_TYPE(XojPageView);
Control* control = xournal->getControl();
if (this->inputHandler)
{
this->inputHandler->onButtonReleaseEvent(pos);
delete this->inputHandler;
this->inputHandler = NULL;
}
if (this->inEraser)
{
this->inEraser = false;
Document* doc = this->xournal->getControl()->getDocument();
doc->lock();
this->eraser->finalize();
doc->unlock();
}
if (this->verticalSpace)
{
MoveUndoAction* undo = this->verticalSpace->finalize();
delete this->verticalSpace;
this->verticalSpace = NULL;
control->getUndoRedoHandler()->addUndoAction(undo);
}
if (this->selection)
{
if (this->selection->finalize(this->page))
{
xournal->setSelection(new EditSelection(control->getUndoRedoHandler(), this->selection, this));
delete this->selection;
this->selection = NULL;
}
else
{
delete this->selection;
this->selection = NULL;
repaintPage();
}
}
else if (this->textEditor)
{
this->textEditor->mouseReleased();
}
return false;
}
bool XojPageView::onKeyPressEvent(GdkEventKey* event)
{
XOJ_CHECK_TYPE(XojPageView);
// Esc leaves text edition
if (event->keyval == GDK_KEY_Escape)
{
if (this->textEditor)
{
endText();
return true;
}
else if (xournal->getSelection())
{
xournal->clearSelection();
return true;
}
else
{
return false;
}
}
if (this->textEditor && this->textEditor->onKeyPressEvent(event))
{
return true;
}
return false;
}
bool XojPageView::onKeyReleaseEvent(GdkEventKey* event)
{
XOJ_CHECK_TYPE(XojPageView);
if (this->textEditor && this->textEditor->onKeyReleaseEvent(event))
{
return true;
}
return false;
}
void XojPageView::rerenderPage()
{
XOJ_CHECK_TYPE(XojPageView);
this->rerenderComplete = true;
this->xournal->getControl()->getScheduler()->addRerenderPage(this);
}
void XojPageView::repaintPage()
{
XOJ_CHECK_TYPE(XojPageView);
xournal->getRepaintHandler()->repaintPage(this);
}
void XojPageView::repaintArea(double x1, double y1, double x2, double y2)
{
XOJ_CHECK_TYPE(XojPageView);
double zoom = xournal->getZoom();
xournal->getRepaintHandler()->repaintPageArea(this, x1 * zoom - 10, y1 * zoom - 10, x2 * zoom + 20, y2 * zoom + 20);
}
void XojPageView::rerenderRect(double x, double y, double width, double height)
{
XOJ_CHECK_TYPE(XojPageView);
int rx = (int) MAX(x - 10, 0);
int ry = (int) MAX(y - 10, 0);
int rwidth = (int) (width + 20);
int rheight = (int) (height + 20);
addRerenderRect(rx, ry, rwidth, rheight);
}
void XojPageView::addRerenderRect(double x, double y, double width, double height)
{
XOJ_CHECK_TYPE(XojPageView);
if (this->rerenderComplete)
{
return;
}
Rectangle* rect = new Rectangle(x, y, width, height);
g_mutex_lock(&this->repaintRectMutex);
for (Rectangle* r : this->rerenderRects)
{
// its faster to redraw only one rect than repaint twice the same area
// so loop through the rectangles to be redrawn, if new rectangle
// intersects any of them, replace it by the union with the new one
if (r->intersects(*rect))
{
r->add(*rect);
delete rect;
g_mutex_unlock(&this->repaintRectMutex);
return;
}
}
this->rerenderRects.push_back(rect);
g_mutex_unlock(&this->repaintRectMutex);
this->xournal->getControl()->getScheduler()->addRerenderPage(this);
}
void XojPageView::setSelected(bool selected)
{
XOJ_CHECK_TYPE(XojPageView);
this->selected = selected;
if (selected)
{
this->xournal->requestFocus();
this->xournal->getRepaintHandler()->repaintPageBorder(this);
}
}
bool XojPageView::cut()
{
XOJ_CHECK_TYPE(XojPageView);
if (this->textEditor)
{
this->textEditor->cutToClipboard();
return true;
}
return false;
}
bool XojPageView::copy()
{
XOJ_CHECK_TYPE(XojPageView);
if (this->textEditor)
{
this->textEditor->copyToCliboard();
return true;
}
return false;
}
bool XojPageView::paste()
{
XOJ_CHECK_TYPE(XojPageView);
if (this->textEditor)
{
this->textEditor->pasteFromClipboard();
return true;
}
return false;
}
bool XojPageView::actionDelete()
{
XOJ_CHECK_TYPE(XojPageView);
if (this->textEditor)
{
this->textEditor->deleteFromCursor(GTK_DELETE_CHARS, 1);
return true;
}
return false;
}
void XojPageView::drawLoadingPage(cairo_t* cr)
{
XOJ_CHECK_TYPE(XojPageView);
static const string txtLoading = _("Loading...");
double zoom = xournal->getZoom();
int dispWidth = getDisplayWidth();
int dispHeight = getDisplayHeight();
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_rectangle(cr, 0, 0, dispWidth, dispHeight);
cairo_fill(cr);
cairo_scale(cr, zoom, zoom);
cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 32.0);
cairo_text_extents_t ex;
cairo_text_extents(cr, txtLoading.c_str(), &ex);
cairo_move_to(cr, (page->getWidth() - ex.width) / 2 - ex.x_bearing,
(page->getHeight() - ex.height) / 2 - ex.y_bearing);
cairo_show_text(cr, txtLoading.c_str());
rerenderPage();
}
/**
* Does the painting, called in synchronized block
*/
void XojPageView::paintPageSync(cairo_t* cr, GdkRectangle* rect)
{
XOJ_CHECK_TYPE(XojPageView);
if (this->crBuffer == NULL)
{
drawLoadingPage(cr);
return;
}
double zoom = xournal->getZoom();
int dispWidth = getDisplayWidth();
cairo_save(cr);
double width = cairo_image_surface_get_width(this->crBuffer);
if (width != dispWidth)
{
double scale = ((double) dispWidth) / ((double) width);
// Scale current image to fit the zoom level
cairo_scale(cr, scale, scale);
cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST);
cairo_set_source_surface(cr, this->crBuffer, 0, 0);
rerenderPage();
rect = NULL;
}
else
{
cairo_set_source_surface(cr, this->crBuffer, 0, 0);
}
if (rect)
{
cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height);
cairo_fill(cr);
#ifdef DEBUG_SHOW_PAINT_BOUNDS
cairo_set_source_rgb(cr, 1.0, 0.5, 1.0);
cairo_set_line_width(cr, 1. / zoom);
cairo_rectangle(cr, rect->x, rect->y, rect->width, rect->height);
cairo_stroke(cr);
#endif
}
else
{
cairo_paint(cr);
}
cairo_restore(cr);
// don't paint this with scale, because it needs a 1:1 zoom
if (this->verticalSpace)
{
this->verticalSpace->paint(cr, rect, zoom);
}
if (this->textEditor)
{
cairo_scale(cr, zoom, zoom);
this->textEditor->paint(cr, rect, zoom);
}
if (this->selection)
{
cairo_scale(cr, zoom, zoom);
this->selection->paint(cr, rect, zoom);
}
if (this->search)
{
cairo_scale(cr, zoom, zoom);
this->search->paint(cr, rect, zoom, getSelectionColor());
}
if (this->inputHandler)
{
this->inputHandler->draw(cr);
}
}
bool XojPageView::paintPage(cairo_t* cr, GdkRectangle* rect)
{
XOJ_CHECK_TYPE(XojPageView);
g_mutex_lock(&this->drawingMutex);
paintPageSync(cr, rect);
g_mutex_unlock(&this->drawingMutex);
return true;
}
bool XojPageView::containsY(int y)
{
XOJ_CHECK_TYPE(XojPageView);
return (y >= this->getY() && y <= (this->getY() + this->getDisplayHeight()));
}
/**
* GETTER / SETTER
*/
bool XojPageView::isSelected()
{
XOJ_CHECK_TYPE(XojPageView);
return selected;
}
int XojPageView::getBufferPixels()
{
XOJ_CHECK_TYPE(XojPageView);
if (crBuffer)
{
return cairo_image_surface_get_width(crBuffer) * cairo_image_surface_get_height(crBuffer);
}
return 0;
}
GtkColorWrapper XojPageView::getSelectionColor()
{
XOJ_CHECK_TYPE(XojPageView);
XOJ_CHECK_TYPE(XojPageView);
GtkWidget* widget = getXournal()->getWidget();
GtkStyleContext *context = gtk_widget_get_style_context(widget);
gtk_style_context_save(context);
gtk_style_context_add_class(context, GTK_STYLE_CLASS_RUBBERBAND);
GdkRGBA col;
gtk_style_context_get_border_color(context,
gtk_widget_get_state_flags(widget),
&col);
// TODO: The correct border color is not sufficient,
// we should also get the actual color and the GtkBorder
// to draw the selection correctly
/*
gtk_style_context_get_border (context, state,
&border);
*/
gtk_style_context_restore(context);
return col;
}
TextEditor* XojPageView::getTextEditor()
{
XOJ_CHECK_TYPE(XojPageView);
return textEditor;
}
int XojPageView::getX() const
{
XOJ_CHECK_TYPE(XojPageView);
return this->layout.getLayoutAbsoluteX();
}
int XojPageView::getY() const
{
XOJ_CHECK_TYPE(XojPageView);
return this->layout.getLayoutAbsoluteY();
}
PageRef XojPageView::getPage()
{
XOJ_CHECK_TYPE(XojPageView);
return page;
}
XournalView* XojPageView::getXournal()
{
XOJ_CHECK_TYPE(XojPageView);
return this->xournal;
}
double XojPageView::getHeight() const
{
XOJ_CHECK_TYPE(XojPageView);
return this->page->getHeight();
}
double XojPageView::getWidth() const
{
XOJ_CHECK_TYPE(XojPageView);
return this->page->getWidth();
}
int XojPageView::getDisplayWidth() const
{
XOJ_CHECK_TYPE(XojPageView);
return this->page->getWidth() * this->xournal->getZoom();
}
int XojPageView::getDisplayHeight() const
{
XOJ_CHECK_TYPE(XojPageView);
return this->page->getHeight() * this->xournal->getZoom();
}
TexImage* XojPageView::getSelectedTex()
{
XOJ_CHECK_TYPE(XojPageView);
EditSelection* theSelection = this->xournal->getSelection();
if (!theSelection)
{
return NULL;
}
for (Element* e : *theSelection->getElements())
{
if (e->getType() == ELEMENT_TEXIMAGE)
{
return (TexImage*) e;
}
}
return NULL;
}
Text* XojPageView::getSelectedText()
{
XOJ_CHECK_TYPE(XojPageView);
EditSelection* theSelection = this->xournal->getSelection();
if (!theSelection)
{
return NULL;
}
for (Element* e : *theSelection->getElements())
{
if (e->getType() == ELEMENT_TEXT)
{
return (Text*) e;
}
}
return NULL;
}
Rectangle* XojPageView::getVisibleRect()
{
XOJ_CHECK_TYPE(XojPageView);
Rectangle* rect = xournal->getVisibleRect(this);
if (!rect)
{
return NULL;
}
(*rect) *= xournal->getZoom();
(*rect) = rect->translated(-getX(), -getY());
return rect;
}
Rectangle XojPageView::getRect()
{
XOJ_CHECK_TYPE(XojPageView);
return Rectangle(getX(), getY(), getDisplayWidth(), getDisplayHeight());
}
void XojPageView::rectChanged(Rectangle& rect)
{
XOJ_CHECK_TYPE(XojPageView);
rerenderRect(rect.x, rect.y, rect.width, rect.height);
}
void XojPageView::rangeChanged(Range &range)
{
XOJ_CHECK_TYPE(XojPageView);
rerenderRange(range);
}
void XojPageView::pageChanged()
{
XOJ_CHECK_TYPE(XojPageView);
rerenderPage();
}
void XojPageView::elementChanged(Element* elem)
{
XOJ_CHECK_TYPE(XojPageView);
if (this->inputHandler && elem == this->inputHandler->getStroke())
{
g_mutex_lock(&this->drawingMutex);
cairo_t* cr = cairo_create(this->crBuffer);
this->inputHandler->draw(cr);
cairo_destroy(cr);
g_mutex_unlock(&this->drawingMutex);
}
else
{
rerenderElement(elem);
}
}