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.
1125 lines
21 KiB
1125 lines
21 KiB
#include "XournalView.h" |
|
|
|
#include "Cursor.h" |
|
#include "Layout.h" |
|
#include "PageView.h" |
|
#include "RepaintHandler.h" |
|
#include "Shadow.h" |
|
|
|
#include "control/Control.h" |
|
#include "control/PdfCache.h" |
|
#include "control/settings/MetadataManager.h" |
|
#include "gui/inputdevices/TouchHelper.h" |
|
#include "model/Document.h" |
|
#include "model/Stroke.h" |
|
#include "undo/DeleteUndoAction.h" |
|
#include "widgets/XournalWidget.h" |
|
|
|
#include <Rectangle.h> |
|
#include <Util.h> |
|
|
|
#include <gdk/gdk.h> |
|
|
|
#include <tuple> |
|
#include <cmath> |
|
|
|
XournalView::XournalView(GtkWidget* parent, Control* control, ScrollHandling* scrollHandling) |
|
: scrollHandling(scrollHandling), |
|
control(control) |
|
{ |
|
XOJ_INIT_TYPE(XournalView); |
|
|
|
this->cache = new PdfCache(control->getSettings()->getPdfPageCacheSize()); |
|
registerListener(control); |
|
|
|
this->widget = gtk_xournal_new(this, scrollHandling); |
|
// we need to refer widget here, because we unref it somewhere twice!? |
|
g_object_ref(this->widget); |
|
|
|
gtk_container_add(GTK_CONTAINER(parent), this->widget); |
|
gtk_widget_show(this->widget); |
|
|
|
g_signal_connect(getWidget(), "realize", G_CALLBACK(onRealized), this); |
|
|
|
this->repaintHandler = new RepaintHandler(this); |
|
this->touchHelper = new TouchHelper(control->getSettings()); |
|
|
|
control->getZoomControl()->addZoomListener(this); |
|
|
|
gtk_widget_set_can_default(this->widget, true); |
|
gtk_widget_grab_default(this->widget); |
|
|
|
gtk_widget_grab_focus(this->widget); |
|
|
|
this->cleanupTimeout = g_timeout_add_seconds(5, (GSourceFunc) clearMemoryTimer, this); |
|
} |
|
|
|
XournalView::~XournalView() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
g_source_remove(this->cleanupTimeout); |
|
|
|
for (size_t i = 0; i < this->viewPagesLen; i++) |
|
{ |
|
delete this->viewPages[i]; |
|
} |
|
delete[] this->viewPages; |
|
this->viewPagesLen = 0; |
|
this->viewPages = NULL; |
|
|
|
delete this->cache; |
|
this->cache = NULL; |
|
delete this->repaintHandler; |
|
this->repaintHandler = NULL; |
|
|
|
|
|
gtk_widget_destroy(this->widget); |
|
this->widget = NULL; |
|
|
|
delete this->touchHelper; |
|
this->touchHelper = NULL; |
|
|
|
XOJ_RELEASE_TYPE(XournalView); |
|
} |
|
|
|
gint pageViewCmpSize(XojPageView* a, XojPageView* b) |
|
{ |
|
return a->getLastVisibleTime() - b->getLastVisibleTime(); |
|
} |
|
|
|
void XournalView::staticLayoutPages(GtkWidget *widget, GtkAllocation *allocation, void *data) |
|
{ |
|
XournalView *xv = (XournalView *)data; |
|
XOJ_CHECK_TYPE_OBJ(xv, XournalView); |
|
xv->layoutPages(); |
|
} |
|
|
|
gboolean XournalView::clearMemoryTimer(XournalView* widget) |
|
{ |
|
XOJ_CHECK_TYPE_OBJ(widget, XournalView); |
|
|
|
GList* list = NULL; |
|
|
|
for (size_t i = 0; i < widget->viewPagesLen; i++) |
|
{ |
|
XojPageView* v = widget->viewPages[i]; |
|
if (v->getLastVisibleTime() > 0) |
|
{ |
|
list = g_list_insert_sorted(list, v, (GCompareFunc) pageViewCmpSize); |
|
} |
|
} |
|
|
|
int pixel = 2884560; |
|
int firstPages = 4; |
|
|
|
int i = 0; |
|
|
|
for (GList* l = list; l != NULL; l = l->next) |
|
{ |
|
if (firstPages) |
|
{ |
|
firstPages--; |
|
} |
|
else |
|
{ |
|
XojPageView* v = (XojPageView*) l->data; |
|
|
|
if (pixel <= 0) |
|
{ |
|
v->deleteViewBuffer(); |
|
} |
|
else |
|
{ |
|
pixel -= v->getBufferPixels(); |
|
} |
|
} |
|
i++; |
|
} |
|
|
|
g_list_free(list); |
|
|
|
// call again |
|
return true; |
|
} |
|
|
|
size_t XournalView::getCurrentPage() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
return currentPage; |
|
} |
|
|
|
const int scrollKeySize = 30; |
|
|
|
bool XournalView::onKeyPressEvent(GdkEventKey* event) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
size_t p = getCurrentPage(); |
|
if (p != size_t_npos && p < this->viewPagesLen) |
|
{ |
|
XojPageView* v = this->viewPages[p]; |
|
if (v->onKeyPressEvent(event)) |
|
{ |
|
return true; |
|
} |
|
} |
|
|
|
// Esc leaves fullscreen mode |
|
if (event->keyval == GDK_KEY_Escape || event->keyval == GDK_KEY_F11) |
|
{ |
|
if (control->isFullscreen()) |
|
{ |
|
control->setFullscreen(false); |
|
return true; |
|
} |
|
} |
|
|
|
// F5 starts presentation modus |
|
if (event->keyval == GDK_KEY_F5) |
|
{ |
|
if (!control->isFullscreen()) |
|
{ |
|
control->setViewPresentationMode(true); |
|
control->setFullscreen(true); |
|
return true; |
|
} |
|
} |
|
|
|
guint state = event->state & gtk_accelerator_get_default_mod_mask(); |
|
|
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
|
|
if (state & GDK_SHIFT_MASK) |
|
{ |
|
GtkAllocation alloc = |
|
{ 0 }; |
|
gtk_widget_get_allocation(gtk_widget_get_parent(this->widget), &alloc); |
|
int windowHeight = alloc.height - scrollKeySize; |
|
|
|
if (event->keyval == GDK_KEY_Page_Down) |
|
{ |
|
layout->scrollRelativ(0, windowHeight); |
|
return false; |
|
} |
|
if (event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_space) |
|
{ |
|
layout->scrollRelativ(0, -windowHeight); |
|
return true; |
|
} |
|
} |
|
else |
|
{ |
|
if (event->keyval == GDK_KEY_Page_Down || event->keyval == GDK_KEY_KP_Page_Down) |
|
{ |
|
control->getScrollHandler()->goToNextPage(); |
|
return true; |
|
} |
|
if (event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_KP_Page_Up) |
|
{ |
|
control->getScrollHandler()->goToPreviousPage(); |
|
return true; |
|
} |
|
} |
|
|
|
if (event->keyval == GDK_KEY_space) { |
|
GtkAllocation alloc = { 0 }; |
|
gtk_widget_get_allocation(gtk_widget_get_parent(this->widget), &alloc); |
|
int windowHeight = alloc.height - scrollKeySize; |
|
|
|
layout->scrollRelativ(0, windowHeight); |
|
return true; |
|
} |
|
|
|
//Numeric keypad always navigates by page |
|
if (event->keyval == GDK_KEY_KP_Up) |
|
{ |
|
this->pageRelativeXY(0,-1); |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_KP_Down) |
|
{ |
|
this->pageRelativeXY(0,1); |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_KP_Left) |
|
{ |
|
this->pageRelativeXY(-1, 0); |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_KP_Right) |
|
{ |
|
this->pageRelativeXY(1,0); |
|
return true; |
|
} |
|
|
|
|
|
if (event->keyval == GDK_KEY_Up) |
|
{ |
|
if (control->getSettings()->isPresentationMode()) |
|
{ |
|
control->getScrollHandler()->goToPreviousPage(); |
|
return true; |
|
} |
|
else |
|
{ |
|
if (state & GDK_SHIFT_MASK) |
|
{ |
|
this->pageRelativeXY(0,-1); |
|
} |
|
else |
|
{ |
|
layout->scrollRelativ(0, -scrollKeySize); |
|
} |
|
return true; |
|
} |
|
} |
|
|
|
if (event->keyval == GDK_KEY_Down) |
|
{ |
|
if (control->getSettings()->isPresentationMode()) |
|
{ |
|
control->getScrollHandler()->goToNextPage(); |
|
return true; |
|
} |
|
else |
|
{ |
|
if (state & GDK_SHIFT_MASK) |
|
{ |
|
this->pageRelativeXY(0,1); |
|
} |
|
else |
|
{ |
|
layout->scrollRelativ(0, scrollKeySize); |
|
} |
|
return true; |
|
} |
|
} |
|
|
|
if (event->keyval == GDK_KEY_Left) |
|
{ |
|
if (state & GDK_SHIFT_MASK) |
|
{ |
|
this->pageRelativeXY(-1,0); |
|
} |
|
else |
|
{ |
|
layout->scrollRelativ(-scrollKeySize, 0); |
|
} |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_Right) |
|
{ |
|
if (state & GDK_SHIFT_MASK) |
|
{ |
|
this->pageRelativeXY(1,0); |
|
} |
|
else |
|
{ |
|
layout->scrollRelativ(scrollKeySize, 0); |
|
} |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End) |
|
{ |
|
control->getScrollHandler()->goToLastPage(); |
|
return true; |
|
} |
|
|
|
if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home) |
|
{ |
|
control->getScrollHandler()->goToFirstPage(); |
|
return true; |
|
} |
|
|
|
// vim like scrolling |
|
if (event->keyval == GDK_KEY_j) |
|
{ |
|
layout->scrollRelativ(0, 60); |
|
return true; |
|
} |
|
if (event->keyval == GDK_KEY_k) |
|
{ |
|
layout->scrollRelativ(0, -60); |
|
return true; |
|
} |
|
if (event->keyval == GDK_KEY_h) |
|
{ |
|
layout->scrollRelativ(-60, 0); |
|
return true; |
|
} |
|
if (event->keyval == GDK_KEY_l) |
|
{ |
|
layout->scrollRelativ(60, 0); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
RepaintHandler* XournalView::getRepaintHandler() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
return this->repaintHandler; |
|
} |
|
|
|
bool XournalView::onKeyReleaseEvent(GdkEventKey* event) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
size_t p = getCurrentPage(); |
|
if (p != size_t_npos && p < this->viewPagesLen) |
|
{ |
|
XojPageView* v = this->viewPages[p]; |
|
if (v->onKeyReleaseEvent(event)) |
|
{ |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void XournalView::onRealized(GtkWidget* widget, XournalView* view) |
|
{ |
|
XOJ_CHECK_TYPE_OBJ(view, XournalView); |
|
|
|
// Disable event compression |
|
if (gtk_widget_get_realized(view->getWidget())) |
|
{ |
|
gdk_window_set_event_compression(gtk_widget_get_window(view->getWidget()), false); |
|
} |
|
else |
|
{ |
|
g_warning("could not disable event compression"); |
|
} |
|
} |
|
|
|
// send the focus back to the appropriate widget |
|
void XournalView::requestFocus() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
gtk_widget_grab_focus(this->widget); |
|
} |
|
|
|
bool XournalView::searchTextOnPage(string text, size_t p, int* occures, double* top) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
if (p == size_t_npos || p >= this->viewPagesLen) |
|
{ |
|
return false; |
|
} |
|
XojPageView* v = this->viewPages[p]; |
|
|
|
return v->searchTextOnPage(text, occures, top); |
|
} |
|
|
|
void XournalView::forceUpdatePagenumbers() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
size_t p = this->currentPage; |
|
this->currentPage = size_t_npos; |
|
|
|
control->firePageSelected(p); |
|
} |
|
|
|
XojPageView* XournalView::getViewFor(size_t pageNr) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
if (pageNr == size_t_npos || pageNr >= this->viewPagesLen) |
|
{ |
|
return NULL; |
|
} |
|
return this->viewPages[pageNr]; |
|
} |
|
|
|
void XournalView::pageSelected(size_t page) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
if (this->currentPage == page && this->lastSelectedPage == page) |
|
{ |
|
return; |
|
} |
|
|
|
Document* doc = control->getDocument(); |
|
doc->lock(); |
|
Path file = doc->getEvMetadataFilename(); |
|
doc->unlock(); |
|
|
|
control->getMetadataManager()->storeMetadata(file.str(), page, getZoom()); |
|
|
|
if (this->lastSelectedPage != size_t_npos && this->lastSelectedPage < this->viewPagesLen) |
|
{ |
|
this->viewPages[this->lastSelectedPage]->setSelected(false); |
|
} |
|
|
|
this->currentPage = page; |
|
|
|
size_t pdfPage = size_t_npos; |
|
|
|
if (page != size_t_npos && page < viewPagesLen) |
|
{ |
|
XojPageView* vp = viewPages[page]; |
|
vp->setSelected(true); |
|
lastSelectedPage = page; |
|
pdfPage = vp->getPage()->getPdfPageNr(); |
|
} |
|
|
|
control->updatePageNumbers(currentPage, pdfPage); |
|
|
|
control->updateBackgroundSizeButton(); |
|
} |
|
|
|
Control* XournalView::getControl() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
return control; |
|
} |
|
|
|
void XournalView::scrollTo(size_t pageNo, double yDocument) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
if (pageNo >= this->viewPagesLen) |
|
{ |
|
return; |
|
} |
|
|
|
XojPageView* v = this->viewPages[pageNo]; |
|
|
|
// Make sure it is visible |
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
|
|
int x = v->getX(); |
|
int y = v->getY() + yDocument; |
|
int width = v->getDisplayWidth(); |
|
int height = v->getDisplayHeight(); |
|
|
|
layout->ensureRectIsVisible(x, y, width, height); |
|
|
|
// Select the page |
|
control->firePageSelected(pageNo); |
|
} |
|
|
|
|
|
void XournalView::pageRelativeXY(int offCol, int offRow) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
int currPage = getCurrentPage(); |
|
|
|
XojPageView* view = getViewFor(currPage ); |
|
int row = view->getMappedRow(); |
|
int col = view->getMappedCol(); |
|
|
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
int page = layout->getIndexAtGridMap(row +offRow ,col + offCol); |
|
if( page >=0) |
|
{ |
|
this-> scrollTo(page, 0); |
|
} |
|
|
|
} |
|
|
|
|
|
void XournalView::endTextAllPages(XojPageView* except) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
for (size_t i = 0; i < this->viewPagesLen; i++) |
|
{ |
|
XojPageView* v = this->viewPages[i]; |
|
if (except != v) |
|
{ |
|
v->endText(); |
|
} |
|
} |
|
} |
|
|
|
void XournalView::layerChanged(size_t page) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
if (page != size_t_npos && page < this->viewPagesLen) |
|
{ |
|
this->viewPages[page]->rerenderPage(); |
|
} |
|
} |
|
|
|
void XournalView::getPasteTarget(double& x, double& y) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
size_t pageNo = getCurrentPage(); |
|
if (pageNo == size_t_npos) |
|
{ |
|
return; |
|
} |
|
|
|
Rectangle* rect = getVisibleRect(pageNo); |
|
|
|
if (rect) |
|
{ |
|
x = rect->x + rect->width / 2; |
|
y = rect->y + rect->height / 2; |
|
delete rect; |
|
} |
|
} |
|
|
|
/** |
|
* Return the rectangle which is visible on screen, in document cooordinates |
|
* |
|
* Or NULL if the page is not visible |
|
*/ |
|
Rectangle* XournalView::getVisibleRect(size_t page) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
if (page == size_t_npos || page >= this->viewPagesLen) |
|
{ |
|
return NULL; |
|
} |
|
XojPageView* p = this->viewPages[page]; |
|
|
|
return getVisibleRect(p); |
|
} |
|
|
|
Rectangle* XournalView::getVisibleRect(XojPageView* redrawable) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
return gtk_xournal_get_visible_area(this->widget, redrawable); |
|
} |
|
|
|
/** |
|
* A pen action was detected now, therefore ignore touch events |
|
* for a short time |
|
*/ |
|
void XournalView::penActionDetected() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
this->lastPenAction = g_get_monotonic_time() / 1000; |
|
} |
|
|
|
/** |
|
* If the pen was active a short time before, ignore touch events |
|
*/ |
|
bool XournalView::shouldIgnoreTouchEvents() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
if ((g_get_monotonic_time() / 1000 - this->lastPenAction) < 500) |
|
{ |
|
// g_message("Ignore touch, pen was active\n"); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
/** |
|
* @return Helper class for Touch specific fixes |
|
*/ |
|
TouchHelper* XournalView::getTouchHelper() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
return touchHelper; |
|
} |
|
|
|
/** |
|
* @returnScrollbars |
|
*/ |
|
ScrollHandling* XournalView::getScrollHandling() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
return scrollHandling; |
|
} |
|
|
|
GtkWidget* XournalView::getWidget() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
return widget; |
|
} |
|
|
|
void XournalView::zoomIn() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
control->getZoomControl()->zoomOneStep(ZOOM_IN); |
|
} |
|
|
|
void XournalView::zoomOut() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
control->getZoomControl()->zoomOneStep(ZOOM_OUT); |
|
} |
|
|
|
void XournalView::ensureRectIsVisible(int x, int y, int width, int height) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
layout->ensureRectIsVisible(x, y, width, height); |
|
} |
|
|
|
void XournalView::zoomChanged() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
int currentPage = this->getCurrentPage(); |
|
XojPageView* view = getViewFor(currentPage); |
|
ZoomControl* zoom = control->getZoomControl(); |
|
|
|
if (!view) |
|
{ |
|
return; |
|
} |
|
|
|
// move this somewhere else maybe |
|
layout->layoutPages(); |
|
|
|
if(zoom->isZoomPresentationMode() || zoom->isZoomFitMode()) |
|
{ |
|
scrollTo(currentPage); |
|
} |
|
else |
|
{ |
|
std::tuple<double, double> pos = zoom->getScrollPositionAfterZoom(view); |
|
if(std::get<0>(pos) != -1 && std::get<1>(pos) != -1) |
|
{ |
|
layout->scrollAbs(std::get<0>(pos), std::get<1>(pos)); |
|
} |
|
} |
|
|
|
Document* doc = control->getDocument(); |
|
doc->lock(); |
|
Path file = doc->getEvMetadataFilename(); |
|
doc->unlock(); |
|
|
|
control->getMetadataManager()->storeMetadata(file.str(), getCurrentPage(), zoom->getZoomReal()); |
|
|
|
// Updates the Eraser's cursor icon in order to make it as big as the erasing area |
|
control->getCursor()->updateCursor(); |
|
|
|
this->control->getScheduler()->blockRerenderZoom(); |
|
} |
|
|
|
void XournalView::pageSizeChanged(size_t page) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
layoutPages(); |
|
} |
|
|
|
void XournalView::pageChanged(size_t page) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
if (page != size_t_npos && page < this->viewPagesLen) |
|
{ |
|
this->viewPages[page]->rerenderPage(); |
|
} |
|
} |
|
|
|
void XournalView::pageDeleted(size_t page) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
size_t currentPage = control->getCurrentPageNo(); |
|
|
|
delete this->viewPages[page]; |
|
|
|
for (size_t i = page; i < this->viewPagesLen - 1; i++) |
|
{ |
|
this->viewPages[i] = this->viewPages[i + 1]; |
|
} |
|
|
|
this->viewPagesLen--; |
|
this->viewPages[this->viewPagesLen] = NULL; |
|
|
|
if (currentPage >= page) |
|
{ |
|
currentPage--; |
|
} |
|
|
|
layoutPages(); |
|
control->getScrollHandler()->scrollToPage(currentPage); |
|
} |
|
|
|
TextEditor* XournalView::getTextEditor() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
for (size_t i = 0; i < this->viewPagesLen; i++) |
|
{ |
|
XojPageView* v = this->viewPages[i]; |
|
if (v->getTextEditor()) |
|
{ |
|
return v->getTextEditor(); |
|
} |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
void XournalView::resetShapeRecognizer() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
for (size_t i = 0; i < this->viewPagesLen; i++) |
|
{ |
|
XojPageView* v = this->viewPages[i]; |
|
v->resetShapeRecognizer(); |
|
} |
|
} |
|
|
|
PdfCache* XournalView::getCache() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
return this->cache; |
|
} |
|
|
|
void XournalView::pageInserted(size_t page) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
XojPageView** lastViewPages = this->viewPages; |
|
|
|
this->viewPages = new XojPageView *[this->viewPagesLen + 1]; |
|
|
|
for (size_t i = 0; i < page; i++) |
|
{ |
|
this->viewPages[i] = lastViewPages[i]; |
|
|
|
// unselect to prevent problems... |
|
this->viewPages[i]->setSelected(false); |
|
} |
|
|
|
for (size_t i = page; i < this->viewPagesLen; i++) |
|
{ |
|
this->viewPages[i + 1] = lastViewPages[i]; |
|
|
|
// unselect to prevent problems... |
|
this->viewPages[i + 1]->setSelected(false); |
|
} |
|
|
|
this->lastSelectedPage = -1; |
|
|
|
this->viewPagesLen++; |
|
|
|
delete[] lastViewPages; |
|
|
|
Document* doc = control->getDocument(); |
|
doc->lock(); |
|
XojPageView* pageView = new XojPageView(this, doc->getPage(page)); |
|
doc->unlock(); |
|
|
|
this->viewPages[page] = pageView; |
|
|
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
layout->layoutPages(); |
|
layout->updateVisibility(); |
|
} |
|
|
|
double XournalView::getZoom() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
return control->getZoomControl()->getZoom(); |
|
} |
|
|
|
int XournalView::getDpiScaleFactor() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
return gtk_widget_get_scale_factor(widget); |
|
} |
|
|
|
void XournalView::clearSelection() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
EditSelection* sel = GTK_XOURNAL(widget)->selection; |
|
GTK_XOURNAL(widget)->selection = NULL; |
|
delete sel; |
|
|
|
control->setClipboardHandlerSelection(getSelection()); |
|
|
|
getCursor()->setMouseSelectionType(CURSOR_SELECTION_NONE); |
|
control->getToolHandler()->setSelectionEditTools(false, false, false); |
|
} |
|
|
|
void XournalView::deleteSelection(EditSelection* sel) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
if (sel == NULL) |
|
{ |
|
sel = getSelection(); |
|
} |
|
|
|
if (sel) |
|
{ |
|
XojPageView* view = sel->getView(); |
|
DeleteUndoAction* undo = new DeleteUndoAction(sel->getSourcePage(), false); |
|
sel->fillUndoItem(undo); |
|
control->getUndoRedoHandler()->addUndoAction(undo); |
|
|
|
clearSelection(); |
|
|
|
view->rerenderPage(); |
|
repaintSelection(true); |
|
} |
|
} |
|
|
|
void XournalView::setSelection(EditSelection* selection) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
clearSelection(); |
|
GTK_XOURNAL(this->widget)->selection = selection; |
|
|
|
control->setClipboardHandlerSelection(getSelection()); |
|
|
|
bool canChangeSize = false; |
|
bool canChangeColor = false; |
|
bool canChangeFill = false; |
|
|
|
for (Element* e : *selection->getElements()) |
|
{ |
|
if (e->getType() == ELEMENT_TEXT) |
|
{ |
|
canChangeColor = true; |
|
} |
|
else if (e->getType() == ELEMENT_STROKE) |
|
{ |
|
Stroke* s = (Stroke*) e; |
|
if (s->getToolType() != STROKE_TOOL_ERASER) |
|
{ |
|
canChangeColor = true; |
|
canChangeFill = true; |
|
} |
|
canChangeSize = true; |
|
} |
|
|
|
if (canChangeColor && canChangeSize && canChangeFill) |
|
{ |
|
break; |
|
} |
|
} |
|
|
|
control->getToolHandler()->setSelectionEditTools(canChangeColor, canChangeSize, canChangeFill); |
|
|
|
repaintSelection(); |
|
} |
|
|
|
void XournalView::repaintSelection(bool evenWithoutSelection) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
if (evenWithoutSelection) |
|
{ |
|
gtk_widget_queue_draw(this->widget); |
|
return; |
|
} |
|
|
|
EditSelection* selection = getSelection(); |
|
if (selection == NULL) |
|
{ |
|
return; |
|
} |
|
|
|
// repaint always the whole widget |
|
gtk_widget_queue_draw(this->widget); |
|
} |
|
|
|
void XournalView::layoutPages() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
Layout* layout = gtk_xournal_get_layout(this->widget); |
|
layout->layoutPages(); |
|
} |
|
|
|
int XournalView::getDisplayHeight() const { |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
GtkAllocation allocation = { 0 }; |
|
gtk_widget_get_allocation(this->widget, &allocation); |
|
return allocation.height; |
|
} |
|
|
|
int XournalView::getDisplayWidth() const { |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
GtkAllocation allocation = { 0 }; |
|
gtk_widget_get_allocation(this->widget, &allocation); |
|
return allocation.width; |
|
} |
|
|
|
bool XournalView::isPageVisible(size_t page, int* visibleHeight) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
Rectangle* rect = getVisibleRect(page); |
|
if (rect) |
|
{ |
|
if (visibleHeight) |
|
{ |
|
*visibleHeight = rect->height; |
|
} |
|
|
|
delete rect; |
|
return true; |
|
} |
|
if (visibleHeight) |
|
{ |
|
*visibleHeight = 0; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void XournalView::documentChanged(DocumentChangeType type) |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
if (type != DOCUMENT_CHANGE_CLEARED && type != DOCUMENT_CHANGE_COMPLETE) |
|
{ |
|
return; |
|
} |
|
|
|
XournalScheduler* scheduler = this->control->getScheduler(); |
|
scheduler->lock(); |
|
scheduler->removeAllJobs(); |
|
|
|
clearSelection(); |
|
|
|
for (size_t i = 0; i < this->viewPagesLen; i++) |
|
{ |
|
delete this->viewPages[i]; |
|
} |
|
delete[] this->viewPages; |
|
|
|
Document* doc = control->getDocument(); |
|
doc->lock(); |
|
|
|
this->viewPagesLen = doc->getPageCount(); |
|
this->viewPages = new XojPageView*[viewPagesLen]; |
|
|
|
for (size_t i = 0; i < viewPagesLen; i++) |
|
{ |
|
XojPageView* pageView = new XojPageView(this, doc->getPage(i)); |
|
viewPages[i] = pageView; |
|
} |
|
|
|
doc->unlock(); |
|
|
|
layoutPages(); |
|
scrollTo(0, 0); |
|
|
|
scheduler->unlock(); |
|
} |
|
|
|
bool XournalView::cut() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
size_t p = getCurrentPage(); |
|
if (p == size_t_npos || p >= viewPagesLen) |
|
{ |
|
return false; |
|
} |
|
|
|
XojPageView* page = viewPages[p]; |
|
return page->cut(); |
|
} |
|
|
|
bool XournalView::copy() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
size_t p = getCurrentPage(); |
|
if (p == size_t_npos || p >= viewPagesLen) |
|
{ |
|
return false; |
|
} |
|
|
|
XojPageView* page = viewPages[p]; |
|
return page->copy(); |
|
} |
|
|
|
bool XournalView::paste() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
size_t p = getCurrentPage(); |
|
if (p == size_t_npos || p >= viewPagesLen) |
|
{ |
|
return false; |
|
} |
|
|
|
XojPageView* page = viewPages[p]; |
|
return page->paste(); |
|
} |
|
|
|
bool XournalView::actionDelete() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
size_t p = getCurrentPage(); |
|
if (p == size_t_npos || p >= viewPagesLen) |
|
{ |
|
return false; |
|
} |
|
|
|
XojPageView* page = viewPages[p]; |
|
return page->actionDelete(); |
|
} |
|
|
|
Document* XournalView::getDocument() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
return control->getDocument(); |
|
} |
|
|
|
ArrayIterator<XojPageView*> XournalView::pageViewIterator() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
return ArrayIterator<XojPageView*> (viewPages, viewPagesLen); |
|
} |
|
|
|
|
|
Cursor* XournalView::getCursor() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
return control->getCursor(); |
|
} |
|
|
|
EditSelection* XournalView::getSelection() |
|
{ |
|
XOJ_CHECK_TYPE(XournalView); |
|
|
|
g_return_val_if_fail(this->widget != NULL, NULL); |
|
g_return_val_if_fail(GTK_IS_XOURNAL(this->widget), NULL); |
|
|
|
return GTK_XOURNAL(this->widget)->selection; |
|
}
|
|
|