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.
 
 
 
 
 
 

622 lines
16 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 "../../model/Layer.h"
#include "EditSelectionContents.h"
EditSelection::EditSelection(UndoRedoHandler * undo, double x, double y, double width, double height, PageRef 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, PageRef 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);
addElement(e);
this->sourceLayer->removeElement(e, false);
}
/**
* Our internal constructor
*/
void EditSelection::contstruct(UndoRedoHandler * undo, PageView * view, PageRef sourcePage) {
XOJ_CHECK_TYPE(EditSelection);
this->view = view;
this->undo = undo;
this->sourcePage = sourcePage;
this->sourceLayer = this->sourcePage.getSelectedLayer();
this->aspectRatio = false;
this->relMousePosX = 0;
this->relMousePosY = 0;
this->mouseDownType = CURSOR_SELECTION_NONE;
this->contents = new EditSelectionContents(this->x, this->y, this->width, this->height, this->sourcePage, this->sourceLayer, this->view);
}
EditSelection::~EditSelection() {
XOJ_CHECK_TYPE(EditSelection);
finalizeSelection();
this->sourcePage = NULL;
this->sourceLayer = NULL;
delete this->contents;
this->contents = NULL;
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);
PageView * v = getBestMatchingPageView();
if(v == NULL) {
this->view->getXournal()->deleteSelection();
} else {
PageRef page = this->view->getPage();
Layer * layer = page.getSelectedLayer();
this->contents->finalizeSelection(this->x, this->y, this->width, this->height, this->aspectRatio, layer, page, this->view, this->undo);
this->view->rerenderRect(this->x, this->y, this->width, this->height);
// This is needed if the selection not was 100% on a page
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;
}
/**
* get the Y coordinate relative to the provided view (getView())
* in document coordinates
*/
double EditSelection::getYOnView() {
XOJ_CHECK_TYPE(EditSelection);
return this->y;
}
/**
* 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)
*/
PageRef EditSelection::getSourcePage() {
XOJ_CHECK_TYPE(EditSelection);
return this->sourcePage;
}
/**
* 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);
return this->contents->setSize(size, thiknessPen, thiknessHilighter, thiknessEraser);
}
/**
* 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);
return this->contents->setColor(color);
}
/**
* 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);
return this->contents->setFont(font);
}
/**
* Fills de undo item if the selection is deleted
* the selection is cleared after
*/
void EditSelection::fillUndoItem(DeleteUndoAction * undo) {
this->contents->fillUndoItem(undo);
}
/**
* Add an element to the this selection
*/
void EditSelection::addElement(Element * e) {
XOJ_CHECK_TYPE(EditSelection);
this->contents->addElement(e);
if (e->rescaleOnlyAspectRatio()) {
this->aspectRatio = true;
}
}
/**
* Returns all containig elements of this selections
*/
ListIterator<Element *> EditSelection::getElements() {
XOJ_CHECK_TYPE(EditSelection);
return this->contents->getElements();
}
/**
* 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;
}
/**
* 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->relMousePosY = y - this->y;
}
/**
* 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->x = x - this->relMousePosX;
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();
}
PageView * v = getBestMatchingPageView();
if (v && v != this->view) {
XournalView * xournal = this->view->getXournal();
int pageNr = xournal->getControl()->getDocument()->indexOf(v->getPage());
xournal->pageSelected(pageNr);
translateToView(v);
}
}
PageView * EditSelection::getBestMatchingPageView() {
PagePositionHandler * pp = this->view->getXournal()->getPagePositionHandler();
int rx = this->getXOnViewAbsolute();
int ry = this->getYOnViewAbsolute();
PageView * v = pp->getBestMatchingView(rx, ry, this->getViewWidth(), this->getViewHeight());
return 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();
int aX1 = getXOnViewAbsolute();
int aY1 = getYOnViewAbsolute();
this->x = (aX1 - v->getX()) / zoom;
this->y = (aY1 - v->getY()) / zoom;
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->x -= dx;
this->y -= dy;
ensureWithinVisibleArea();
int x = this->view->getX();
int y = this->view->getY();
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;
double y = this->y;
this->contents->paint(cr, x, y, this->width, this->height, zoom);
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);
}
/**
* 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;
}