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.
829 lines
21 KiB
829 lines
21 KiB
#include "EditSelection.h" |
|
#include "../../undo/UndoRedoHandler.h" |
|
#include "../../model/Element.h" |
|
#include "../../model/Stroke.h" |
|
#include "../../model/Text.h" |
|
#include "Selection.h" |
|
#include "../../gui/PageView.h" |
|
#include "../../view/DocumentView.h" |
|
#include "../../undo/SizeUndoAction.h" |
|
#include "../../undo/ColorUndoAction.h" |
|
#include "../../undo/FontUndoAction.h" |
|
#include "../../gui/XournalView.h" |
|
#include "../../gui/pageposition/PagePositionHandler.h" |
|
#include "../../control/Control.h" |
|
#include "../../model/Document.h" |
|
|
|
#include <math.h> |
|
|
|
EditSelection::EditSelection(UndoRedoHandler * undo, double x, double y, double width, double height, XojPage * page, PageView * view) { |
|
XOJ_INIT_TYPE(EditSelection); |
|
|
|
this->x = x; |
|
this->y = y; |
|
this->width = width; |
|
this->height = height; |
|
|
|
contstruct(undo, view, page); |
|
} |
|
|
|
EditSelection::EditSelection(UndoRedoHandler * undo, Selection * selection, PageView * view) { |
|
XOJ_INIT_TYPE(EditSelection); |
|
|
|
selection->getSelectedRect(this->x, this->y, this->width, this->height); |
|
|
|
contstruct(undo, view, view->getPage()); |
|
|
|
for (GList * l = selection->selectedElements; l != NULL; l = l->next) { |
|
Element * e = (Element *) l->data; |
|
this->sourceLayer->removeElement(e, false); |
|
addElement(e); |
|
} |
|
|
|
view->rerenderPage(); |
|
} |
|
|
|
EditSelection::EditSelection(UndoRedoHandler * undo, Element * e, PageView * view, XojPage * page) { |
|
XOJ_INIT_TYPE(EditSelection); |
|
|
|
this->x = e->getX(); |
|
this->y = e->getY(); |
|
this->width = e->getElementWidth(); |
|
this->height = e->getElementHeight(); |
|
|
|
contstruct(undo, view, page); |
|
} |
|
|
|
/** |
|
* Our internal constructor |
|
*/ |
|
void EditSelection::contstruct(UndoRedoHandler * undo, PageView * view, XojPage * sourcePage) { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
this->view = view; |
|
this->undo = undo; |
|
this->sourcePage = sourcePage; |
|
this->sourceLayer = this->sourcePage->getSelectedLayer(); |
|
|
|
this->aspectRatio = false; |
|
this->selected = NULL; |
|
|
|
this->offsetX = 0; |
|
this->offsetY = 0; |
|
this->originalWidth = this->width; |
|
this->originalHeight = this->height; |
|
this->relativeX = ceil(this->x); |
|
this->relativeY = ceil(this->y); |
|
|
|
this->relMousePosX = 0; |
|
this->relMousePosY = 0; |
|
this->mouseDownType = CURSOR_SELECTION_NONE; |
|
|
|
this->crBuffer = NULL; |
|
|
|
this->rescaleId = 0; |
|
} |
|
|
|
EditSelection::~EditSelection() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
if (this->rescaleId) { |
|
g_source_remove(this->rescaleId); |
|
this->rescaleId = 0; |
|
} |
|
|
|
finalizeSelection(); |
|
|
|
this->sourcePage = NULL; |
|
this->sourceLayer = NULL; |
|
|
|
g_list_free(this->selected); |
|
this->selected = NULL; |
|
|
|
deleteViewBuffer(); |
|
|
|
this->view->rerenderPage(); |
|
this->view->getXournal()->repaintSelection(true); |
|
|
|
this->view = NULL; |
|
this->undo = NULL; |
|
|
|
XOJ_RELEASE_TYPE(EditSelection); |
|
} |
|
|
|
/** |
|
* Finishes all pending changes, move the elements, scale the elements and add |
|
* them to new layer if any or to the old if no new layer |
|
*/ |
|
void EditSelection::finalizeSelection() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
double fx = this->width / this->originalWidth; |
|
double fy = this->height / this->originalHeight; |
|
|
|
bool scale = false; |
|
if (this->aspectRatio) { |
|
double f = (fx + fy) / 2; |
|
fx = f; |
|
fy = f; |
|
} |
|
if (this->width != this->originalWidth || this->height != this->originalHeight) { |
|
scale = true; |
|
} |
|
|
|
Layer * layer = this->sourceLayer; |
|
// TODO: add to new layer |
|
|
|
for (GList * l = this->selected; l != NULL; l = l->next) { |
|
Element * e = (Element *) l->data; |
|
e->move(this->x - this->relativeX, this->y - this->relativeY); |
|
if (scale) { |
|
e->scale(this->x, this->y, fx, fy); |
|
} |
|
layer->addElement(e); |
|
} |
|
|
|
if (scale) { |
|
// TODO: ???????????????????????? |
|
// ScaleUndoAction * scaleUndo = new ScaleUndoAction(this->page, this->view, this->selected, this->x, this->y, fx, fy); |
|
// this->undo->addUndoAction(scaleUndo); |
|
} |
|
|
|
this->view->getXournal()->repaintSelection(); |
|
} |
|
|
|
/** |
|
* get the X coordinate relative to the provided view (getView()) |
|
* in document coordinates |
|
*/ |
|
double EditSelection::getXOnView() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
return this->x - this->offsetX; |
|
} |
|
|
|
/** |
|
* get the Y coordinate relative to the provided view (getView()) |
|
* in document coordinates |
|
*/ |
|
double EditSelection::getYOnView() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
return this->y - this->offsetY; |
|
} |
|
|
|
/** |
|
* get the width in document coordinates (multiple with zoom) |
|
*/ |
|
double EditSelection::getWidth() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
return this->width; |
|
} |
|
|
|
/** |
|
* get the height in document coordinates (multiple with zoom) |
|
*/ |
|
double EditSelection::getHeight() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
return this->height; |
|
} |
|
|
|
/** |
|
* get the source page (where the selection was done) |
|
*/ |
|
XojPage * EditSelection::getSourcePage() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
return this->sourcePage; |
|
} |
|
|
|
/** |
|
* get the target page if not the same as the source page, if the selection is moved to a new page |
|
*/ |
|
XojPage * EditSelection::getTargetPage() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
// TODO: implement |
|
return NULL; |
|
} |
|
|
|
/** |
|
* Get the X coordinate in View coordinates (absolute) |
|
*/ |
|
int EditSelection::getXOnViewAbsolute() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
double zoom = view->getXournal()->getZoom(); |
|
return this->view->getX() + this->getXOnView() * zoom; |
|
} |
|
|
|
/** |
|
* Get the Y coordinate in View coordinates (absolute) |
|
*/ |
|
int EditSelection::getYOnViewAbsolute() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
double zoom = view->getXournal()->getZoom(); |
|
return this->view->getY() + this->getYOnView() * zoom; |
|
} |
|
|
|
/** |
|
* Get the width in View coordinates |
|
*/ |
|
int EditSelection::getViewWidth() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
double zoom = view->getXournal()->getZoom(); |
|
return this->width * zoom; |
|
} |
|
|
|
/** |
|
* Get the height in View coordinates |
|
*/ |
|
int EditSelection::getViewHeight() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
double zoom = view->getXournal()->getZoom(); |
|
return this->height * zoom; |
|
} |
|
|
|
/** |
|
* Sets the tool size for pen or eraser, returs an undo action |
|
* (or NULL if nothing is done) |
|
*/ |
|
UndoAction * EditSelection::setSize(ToolSize size, const double * thiknessPen, const double * thiknessHilighter, const double * thiknessEraser) { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
SizeUndoAction * undo = new SizeUndoAction(this->sourcePage, this->sourceLayer, this->view); |
|
|
|
bool found = false; |
|
|
|
for (GList * l = this->selected; l != NULL; l = l->next) { |
|
Element * e = (Element *) l->data; |
|
if (e->getType() == ELEMENT_STROKE) { |
|
Stroke * s = (Stroke *) e; |
|
StrokeTool tool = s->getToolType(); |
|
|
|
double originalWidth = s->getWidth(); |
|
|
|
int pointCount = s->getPointCount(); |
|
double * originalPressure = SizeUndoAction::getPressure(s); |
|
|
|
if (tool == STROKE_TOOL_PEN) { |
|
s->setWidth(thiknessPen[size]); |
|
} else if (tool == STROKE_TOOL_HIGHLIGHTER) { |
|
s->setWidth(thiknessHilighter[size]); |
|
} else if (tool == STROKE_TOOL_ERASER) { |
|
s->setWidth(thiknessEraser[size]); |
|
} |
|
|
|
// scale the stroke |
|
double factor = s->getWidth() / originalWidth; |
|
s->scalePressure(factor); |
|
|
|
// save the new pressure |
|
double * newPressure = SizeUndoAction::getPressure(s); |
|
|
|
undo->addStroke(s, originalWidth, s->getWidth(), originalPressure, newPressure, pointCount); |
|
found = true; |
|
} |
|
} |
|
|
|
if (found) { |
|
this->deleteViewBuffer(); |
|
this->view->getXournal()->repaintSelection(); |
|
|
|
return undo; |
|
} else { |
|
delete undo; |
|
return NULL; |
|
} |
|
} |
|
|
|
/** |
|
* Set the color of all elements, return an undo action |
|
* (Or NULL if nothing done, e.g. because there is only an image) |
|
*/ |
|
UndoAction * EditSelection::setColor(int color) { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
ColorUndoAction * undo = new ColorUndoAction(this->sourcePage, this->sourceLayer, this->view); |
|
|
|
bool found = false; |
|
|
|
for (GList * l = this->selected; l != NULL; l = l->next) { |
|
Element * e = (Element *) l->data; |
|
if (e->getType() == ELEMENT_TEXT || e->getType() == ELEMENT_STROKE) { |
|
int lastColor = e->getColor(); |
|
e->setColor(color); |
|
undo->addStroke(e, lastColor, e->getColor()); |
|
|
|
found = true; |
|
} |
|
} |
|
|
|
if (found) { |
|
this->deleteViewBuffer(); |
|
this->view->getXournal()->repaintSelection(); |
|
|
|
return undo; |
|
} else { |
|
delete undo; |
|
return NULL; |
|
} |
|
} |
|
|
|
/** |
|
* Sets the font of all containing text elements, return an undo action |
|
* (or NULL if there are no Text elements) |
|
*/ |
|
UndoAction * EditSelection::setFont(XojFont & font) { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
double x1 = 0.0 / 0.0; |
|
double x2 = 0.0 / 0.0; |
|
double y1 = 0.0 / 0.0; |
|
double y2 = 0.0 / 0.0; |
|
|
|
FontUndoAction * undo = new FontUndoAction(this->sourcePage, this->sourceLayer, this->view); |
|
|
|
for (GList * l = this->selected; l != NULL; l = l->next) { |
|
Element * e = (Element *) l->data; |
|
if (e->getType() == ELEMENT_TEXT) { |
|
Text * t = (Text *) e; |
|
undo->addStroke(t, t->getFont(), font); |
|
|
|
if (isnan(x1)) { |
|
x1 = t->getX(); |
|
y1 = t->getY(); |
|
x2 = t->getX() + t->getElementWidth(); |
|
y2 = t->getY() + t->getElementHeight(); |
|
} else { |
|
// size with old font |
|
x1 = MIN(x1, t->getX()); |
|
y1 = MIN(y1, t->getY()); |
|
|
|
x2 = MAX(x2, t->getX() + t->getElementWidth()); |
|
y2 = MAX(y2, t->getY() + t->getElementHeight()); |
|
} |
|
|
|
t->setFont(font); |
|
|
|
// size with new font |
|
x1 = MIN(x1, t->getX()); |
|
y1 = MIN(y1, t->getY()); |
|
|
|
x2 = MAX(x2, t->getX() + t->getElementWidth()); |
|
y2 = MAX(y2, t->getY() + t->getElementHeight()); |
|
} |
|
} |
|
|
|
if (!isnan(x1)) { |
|
this->deleteViewBuffer(); |
|
this->view->getXournal()->repaintSelection(); |
|
return undo; |
|
} |
|
delete undo; |
|
return NULL; |
|
} |
|
|
|
/** |
|
* Add an element to the this selection |
|
*/ |
|
void EditSelection::addElement(Element * e) { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
this->selected = g_list_append(this->selected, e); |
|
|
|
if (e->rescaleOnlyAspectRatio()) { |
|
this->aspectRatio = true; |
|
} |
|
} |
|
|
|
/** |
|
* Returns all containig elements of this selections |
|
*/ |
|
ListIterator<Element *> EditSelection::getElements() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
return ListIterator<Element *> (this->selected); |
|
} |
|
|
|
/** |
|
* Finish the current movement |
|
* (should be called in the mouse-button-released event handler) |
|
*/ |
|
void EditSelection::mouseUp() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
this->mouseDownType = CURSOR_SELECTION_NONE; |
|
// TODO ???????????????????? |
|
|
|
} |
|
|
|
/** |
|
* Handles mouse input for moving and resizing, coordinates are relative to "view" |
|
*/ |
|
void EditSelection::mouseDown(CursorSelectionType type, double x, double y) { |
|
double zoom = this->view->getXournal()->getZoom(); |
|
x /= zoom; |
|
y /= zoom; |
|
|
|
this->mouseDownType = type; |
|
this->relMousePosX = x - this->x + this->offsetX; |
|
this->relMousePosY = y - this->y + this->offsetY; |
|
|
|
printf("rel mouse pos: %lf / %lf | %lf / %lf\n", this->relMousePosX, this->relMousePosY, this->width, this->height); |
|
} |
|
|
|
/** |
|
* Handles mouse input for moving and resizing, coordinates are relative to "view" |
|
*/ |
|
void EditSelection::mouseMove(double x, double y) { |
|
double zoom = this->view->getXournal()->getZoom(); |
|
x /= zoom; |
|
y /= zoom; |
|
|
|
if (this->mouseDownType == CURSOR_SELECTION_MOVE) { |
|
this->offsetX = this->x - x + this->relMousePosX; |
|
this->offsetY = this->y - y + this->relMousePosY; |
|
|
|
this->view->getXournal()->repaintSelection(); |
|
} else if (this->mouseDownType == CURSOR_SELECTION_TOP_LEFT) { |
|
double dx = x - this->x; |
|
double dy = y - this->y; |
|
double f; |
|
if (ABS(dy) < ABS(dx)) { |
|
f = (this->height + dy) / this->height; |
|
} else { |
|
f = (this->width + dx) / this->width; |
|
} |
|
|
|
double oldW = this->width; |
|
double oldH = this->height; |
|
this->width /= f; |
|
this->height /= f; |
|
|
|
this->x += oldW - this->width; |
|
this->y += oldH - this->height; |
|
|
|
this->view->getXournal()->repaintSelection(); |
|
} else if (this->mouseDownType == CURSOR_SELECTION_TOP_RIGHT) { |
|
double dx = x - this->x - this->width; |
|
double dy = y - this->y; |
|
double f; |
|
if (ABS(dy) < ABS(dx)) { |
|
f = this->height / (this->height + dy); |
|
} else { |
|
f = (this->width + dx) / this->width; |
|
} |
|
|
|
double oldH = this->height; |
|
this->width *= f; |
|
this->height *= f; |
|
|
|
this->y += oldH - this->height; |
|
|
|
this->view->getXournal()->repaintSelection(); |
|
} else if (this->mouseDownType == CURSOR_SELECTION_BOTTOM_LEFT) { |
|
double dx = x - this->x; |
|
double dy = y - this->y - this->height; |
|
double f; |
|
if (ABS(dy) < ABS(dx)) { |
|
f = (this->height + dy) / this->height; |
|
} else { |
|
f = this->width / (this->width + dx); |
|
} |
|
|
|
double oldW = this->width; |
|
this->width *= f; |
|
this->height *= f; |
|
|
|
this->x += oldW - this->width; |
|
|
|
this->view->getXournal()->repaintSelection(); |
|
} else if (this->mouseDownType == CURSOR_SELECTION_BOTTOM_RIGHT) { |
|
double dx = x - this->x - this->width; |
|
double dy = y - this->y - this->height; |
|
double f; |
|
if (ABS(dy) < ABS(dx)) { |
|
f = (this->height + dy) / this->height; |
|
} else { |
|
f = (this->width + dx) / this->width; |
|
} |
|
|
|
this->width *= f; |
|
this->height *= f; |
|
|
|
this->view->getXournal()->repaintSelection(); |
|
} else if (this->mouseDownType == CURSOR_SELECTION_TOP) { |
|
double dy = y - this->y; |
|
this->height -= dy; |
|
this->y += dy; |
|
this->view->getXournal()->repaintSelection(); |
|
} else if (this->mouseDownType == CURSOR_SELECTION_BOTTOM) { |
|
double dy = y - this->y - this->height; |
|
this->height += dy; |
|
this->view->getXournal()->repaintSelection(); |
|
} else if (this->mouseDownType == CURSOR_SELECTION_LEFT) { |
|
double dx = x - this->x; |
|
this->width -= dx; |
|
this->x += dx; |
|
|
|
this->view->getXournal()->repaintSelection(); |
|
} else if (this->mouseDownType == CURSOR_SELECTION_RIGHT) { |
|
double dx = x - this->x - this->width; |
|
this->width += dx; |
|
this->view->getXournal()->repaintSelection(); |
|
} |
|
|
|
PagePositionHandler * pp = this->view->getXournal()->getPagePositionHandler(); |
|
int rx = this->getXOnViewAbsolute(); |
|
int ry = this->getYOnViewAbsolute(); |
|
PageView * v = pp->getBestMatchingView(rx, ry, this->getViewWidth(), this->getViewHeight()); |
|
|
|
if(v && v != this->view) { |
|
XournalView * xournal = this->view->getXournal(); |
|
int pageNr = xournal->getControl()->getDocument()->indexOf(v->getPage()); |
|
|
|
xournal->pageSelected(pageNr); |
|
|
|
translateToView(v); |
|
} |
|
} |
|
|
|
/** |
|
* Translate all coordinates which are relative to the current view to the new view, |
|
* and set the attribute view to the new view |
|
*/ |
|
void EditSelection::translateToView(PageView * v) { |
|
double zoom = view->getXournal()->getZoom(); |
|
|
|
double absoluteX = getXOnViewAbsolute(); |
|
double absoluteY = getYOnViewAbsolute(); |
|
|
|
int aX1 = getXOnViewAbsolute(); |
|
int aY1 = getYOnViewAbsolute(); |
|
|
|
|
|
absoluteX -= v->getX(); |
|
absoluteY -= v->getY(); |
|
|
|
this->relativeX = absoluteX / zoom - this->x; |
|
this->relativeY = absoluteY / zoom - this->y; |
|
|
|
|
|
|
|
this->view = v; |
|
|
|
|
|
int aX2 = getXOnViewAbsolute(); |
|
int aY2 = getYOnViewAbsolute(); |
|
|
|
if(aX1 != aX2) { |
|
printf("aX1 != aX2!! %i / %i\n", aX1, aX2); |
|
} |
|
if(aY1 != aY2) { |
|
printf("aY1 != aY2!! %i / %i\n", aY1, aY2); |
|
} |
|
} |
|
|
|
/** |
|
* If the selection should moved (or rescaled) |
|
*/ |
|
bool EditSelection::isMoving() { |
|
return this->mouseDownType != CURSOR_SELECTION_NONE; |
|
} |
|
|
|
/** |
|
* Move the selection |
|
*/ |
|
void EditSelection::moveSelection(double dx, double dy) { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
this->offsetX -= dx; |
|
this->offsetY -= dy; |
|
|
|
ensureWithinVisibleArea(); |
|
|
|
int x = this->view->getX() - this->offsetX + this->relativeX; |
|
int y = this->view->getY() - this->offsetY + this->relativeY; |
|
double zoom = this->view->getXournal()->getZoom(); |
|
this->view->getXournal()->ensureRectIsVisible(x, y, this->width * zoom, this->height * zoom); |
|
|
|
this->view->getXournal()->repaintSelection(); |
|
} |
|
|
|
/** |
|
* If the selection is outside the visible area correct the coordinates |
|
*/ |
|
void EditSelection::ensureWithinVisibleArea() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
//TODO: scroll to this point if not in visible area |
|
|
|
double zoom = this->view->getXournal()->getZoom(); |
|
int x = this->view->getX() - this->offsetX + this->relativeX; |
|
if (x < 0) { |
|
this->offsetX += x; |
|
} |
|
int maxX = this->view->getXournal()->getMaxAreaX(); |
|
if (maxX < x + this->width * zoom) { |
|
this->offsetX += (x + this->width * zoom) - maxX; |
|
} |
|
|
|
int y = this->view->getY() - this->offsetY + this->relativeY; |
|
if (y < 0) { |
|
this->offsetY += y; |
|
} |
|
int maxY = this->view->getXournal()->getMaxAreaY(); |
|
if (maxY < y + this->height * zoom) { |
|
this->offsetY += (y + this->height * zoom) - maxY; |
|
} |
|
} |
|
|
|
/** |
|
* Get the cursor type for the current position (if 0 then the default cursor should be used) |
|
*/ |
|
CursorSelectionType EditSelection::getSelectionTypeForPos(double x, double y, double zoom) { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
double x1 = getXOnView() * zoom; |
|
double x2 = x1 + (this->width * zoom); |
|
double y1 = getYOnView() * zoom; |
|
double y2 = y1 + (this->height * zoom); |
|
|
|
const int EDGE_PADDING = 5; |
|
const int BORDER_PADDING = 3; |
|
|
|
if (x1 - EDGE_PADDING <= x && x <= x1 + EDGE_PADDING && y1 - EDGE_PADDING <= y && y <= y1 + EDGE_PADDING) { |
|
return CURSOR_SELECTION_TOP_LEFT; |
|
} |
|
|
|
if (x2 - EDGE_PADDING <= x && x <= x2 + EDGE_PADDING && y1 - EDGE_PADDING <= y && y <= y1 + EDGE_PADDING) { |
|
return CURSOR_SELECTION_TOP_RIGHT; |
|
} |
|
|
|
if (x1 - EDGE_PADDING <= x && x <= x1 + EDGE_PADDING && y2 - EDGE_PADDING <= y && y <= y2 + EDGE_PADDING) { |
|
return CURSOR_SELECTION_BOTTOM_LEFT; |
|
} |
|
|
|
if (x2 - EDGE_PADDING <= x && x <= x2 + EDGE_PADDING && y2 - EDGE_PADDING <= y && y <= y2 + EDGE_PADDING) { |
|
return CURSOR_SELECTION_BOTTOM_RIGHT; |
|
} |
|
|
|
if (!this->aspectRatio) { |
|
if (x1 <= x && x2 >= x) { |
|
if (y1 - BORDER_PADDING <= y && y <= y1 + BORDER_PADDING) { |
|
return CURSOR_SELECTION_TOP; |
|
} |
|
|
|
if (y2 - BORDER_PADDING <= y && y <= y2 + BORDER_PADDING) { |
|
return CURSOR_SELECTION_BOTTOM; |
|
} |
|
} |
|
|
|
if (y1 <= y && y2 >= y) { |
|
if (x1 - BORDER_PADDING <= x && x <= x1 + BORDER_PADDING) { |
|
return CURSOR_SELECTION_LEFT; |
|
} |
|
|
|
if (x2 - BORDER_PADDING <= x && x <= x2 + BORDER_PADDING) { |
|
return CURSOR_SELECTION_RIGHT; |
|
} |
|
} |
|
} |
|
|
|
if (x1 <= x && x <= x2 && y1 <= y && y <= y2) { |
|
return CURSOR_SELECTION_MOVE; |
|
} |
|
|
|
return CURSOR_SELECTION_NONE; |
|
} |
|
|
|
/** |
|
* Paints the selection to cr, with the given zoom factor. The coordinates of cr |
|
* should be relative to the provideded view by getView() (use translateEvent()) |
|
*/ |
|
void EditSelection::paint(cairo_t * cr, double zoom) { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
double x = this->x - this->offsetX; |
|
double y = this->y - this->offsetY; |
|
|
|
double fx = this->width / this->originalWidth; |
|
double fy = this->height / this->originalHeight; |
|
|
|
if (this->crBuffer == NULL) { |
|
this->crBuffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, this->width * zoom, this->height * zoom); |
|
cairo_t * cr2 = cairo_create(this->crBuffer); |
|
|
|
cairo_scale(cr2, zoom * fx, zoom * fy); |
|
cairo_translate(cr2, -this->relativeX, -this->relativeY); |
|
DocumentView view; |
|
view.drawSelection(cr2, this); |
|
|
|
cairo_destroy(cr2); |
|
} |
|
|
|
if ((int) (this->width * zoom) != (int) cairo_image_surface_get_width(this->crBuffer) || (int) (this->height * zoom) |
|
!= (int) cairo_image_surface_get_height(this->crBuffer)) { |
|
if (!this->rescaleId) { |
|
this->rescaleId = g_idle_add((GSourceFunc) repaintSelection, this); |
|
} |
|
} |
|
|
|
cairo_set_source_surface(cr, this->crBuffer, (int) (x * zoom), (int) (y * zoom)); |
|
cairo_paint(cr); |
|
|
|
cairo_set_operator(cr, CAIRO_OPERATOR_OVER); |
|
|
|
GdkColor selectionColor = view->getSelectionColor(); |
|
|
|
// set the line always the same size on display |
|
cairo_set_line_width(cr, 1); |
|
|
|
const double dashes[] = { 10.0, 10.0 }; |
|
cairo_set_dash(cr, dashes, sizeof(dashes) / sizeof(dashes[0]), 0); |
|
cairo_set_source_rgb(cr, selectionColor.red / 65536.0, selectionColor.green / 65536.0, selectionColor.blue / 65536.0); |
|
|
|
cairo_rectangle(cr, x * zoom, y * zoom, width * zoom, height * zoom); |
|
|
|
cairo_stroke_preserve(cr); |
|
cairo_set_source_rgba(cr, selectionColor.red / 65536.0, selectionColor.green / 65536.0, selectionColor.blue / 65536.0, 0.3); |
|
cairo_fill(cr); |
|
|
|
cairo_set_dash(cr, NULL, 0, 0); |
|
|
|
if (!this->aspectRatio) { |
|
// top |
|
drawAnchorRect(cr, x + width / 2, y, zoom); |
|
// bottom |
|
drawAnchorRect(cr, x + width / 2, y + height, zoom); |
|
// left |
|
drawAnchorRect(cr, x, y + height / 2, zoom); |
|
// right |
|
drawAnchorRect(cr, x + width, y + height / 2, zoom); |
|
} |
|
|
|
// top left |
|
drawAnchorRect(cr, x, y, zoom); |
|
// top right |
|
drawAnchorRect(cr, x + width, y, zoom); |
|
// bottom left |
|
drawAnchorRect(cr, x, y + height, zoom); |
|
// bottom right |
|
drawAnchorRect(cr, x + width, y + height, zoom); |
|
} |
|
|
|
/** |
|
* Callback to redrawing the buffer asynchron |
|
*/ |
|
bool EditSelection::repaintSelection(EditSelection * selection) { |
|
XOJ_CHECK_TYPE_OBJ(selection, EditSelection); |
|
|
|
gdk_threads_enter(); |
|
|
|
// delete the selection buffer, force a redraw |
|
selection->deleteViewBuffer(); |
|
selection->view->repaintRect(selection->x, selection->y, selection->width, selection->height); |
|
selection->rescaleId = 0; |
|
|
|
gdk_threads_leave(); |
|
return false; |
|
} |
|
|
|
/** |
|
* draws an idicator where you can scale the selection |
|
*/ |
|
void EditSelection::drawAnchorRect(cairo_t * cr, double x, double y, double zoom) { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
GdkColor selectionColor = view->getSelectionColor(); |
|
cairo_set_source_rgb(cr, selectionColor.red / 65536.0, selectionColor.green / 65536.0, selectionColor.blue / 65536.0); |
|
cairo_rectangle(cr, x * zoom - 4, y * zoom - 4, 8, 8); |
|
cairo_stroke_preserve(cr); |
|
cairo_set_source_rgb(cr, 1, 1, 1); |
|
cairo_fill(cr); |
|
} |
|
|
|
PageView * EditSelection::getView() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
return this->view; |
|
} |
|
|
|
/** |
|
* Delete our internal View buffer, |
|
* it will be recreated when the selection is painted next time |
|
*/ |
|
void EditSelection::deleteViewBuffer() { |
|
XOJ_CHECK_TYPE(EditSelection); |
|
|
|
if (this->crBuffer) { |
|
cairo_surface_destroy(this->crBuffer); |
|
this->crBuffer = NULL; |
|
} |
|
}
|
|
|