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.
 
 
 
 
 
 

475 lines
9.4 KiB

#include "DocumentView.h"
#include "TextView.h"
#include "gui/Cursor.h"
extern int currentToolType;
#include "background/MainBackgroundPainter.h"
#include "control/tools/EditSelection.h"
#include "control/tools/Selection.h"
#include "model/BackgroundImage.h"
#include "model/eraser/EraseableStroke.h"
#include "model/Layer.h"
#include <config.h>
#include <config-debug.h>
#include <gdk/gdk.h>
#include <typeinfo>
#ifdef DEBUG_SHOW_REPAINT_BOUNDS
#include <iostream>
using std::cout;
using std::endl;
#endif
DocumentView::DocumentView()
{
XOJ_INIT_TYPE(DocumentView);
this->page = NULL;
this->cr = NULL;
this->lX = -1;
this->lY = -1;
this->lWidth = -1;
this->lHeight = -1;
this->width = 0;
this->height = 0;
this->dontRenderEditingStroke = 0;
this->backgroundPainter = new MainBackgroundPainter();
}
DocumentView::~DocumentView()
{
delete this->backgroundPainter;
this->backgroundPainter = NULL;
XOJ_RELEASE_TYPE(DocumentView);
}
void DocumentView::applyColor(cairo_t* cr, Stroke* s)
{
if (s->getToolType() == STROKE_TOOL_HIGHLIGHTER)
{
applyColor(cr, s, 120);
}
else
{
applyColor(cr, (Element*) s);
}
}
void DocumentView::applyColor(cairo_t* cr, Element* e, int alpha)
{
applyColor(cr, e->getColor(), alpha);
}
void DocumentView::applyColor(cairo_t* cr, int c, int alpha)
{
double r = ((c >> 16) & 0xff) / 255.0;
double g = ((c >> 8) & 0xff) / 255.0;
double b = (c & 0xff) / 255.0;
cairo_set_source_rgba(cr, r, g, b, alpha / 255.0);
}
void DocumentView::drawEraseableStroke(cairo_t* cr, Stroke* s)
{
XOJ_CHECK_TYPE(DocumentView);
EraseableStroke* e = s->getEraseable();
e->draw(cr, this->lX, this->lY, this->width, this->height);
}
void DocumentView::drawStroke(cairo_t* cr, Stroke* s, int startPoint, double scaleFactor, bool changeSource)
{
XOJ_CHECK_TYPE(DocumentView);
ArrayIterator<Point> points = s->pointIterator();
if (!points.hasNext())
{
// Should not happen
g_warning("DocumentView::drawStroke empty stroke...");
return;
}
if (changeSource)
{
if (s->getToolType() == STROKE_TOOL_HIGHLIGHTER ||
(s->getAudioFilename().length() == 0 && currentToolType == TOOL_PLAY_OBJECT))
{
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
// Set the color
applyColor(cr, s, 120);
}
else
{
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
// Set the color
applyColor(cr, s);
}
}
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
// don't render eraseable for previews
if (s->getEraseable() && !this->dontRenderEditingStroke)
{
drawEraseableStroke(cr, s);
return;
}
int count = 1;
double width = s->getWidth();
// No pressure sensitivity, easy draw a line...
if (!s->hasPressure())
{
// Set width
cairo_set_line_width(cr, width * scaleFactor);
while (points.hasNext())
{
Point p = points.next();
if (startPoint <= count++)
{
cairo_line_to(cr, p.x, p.y);
}
else
{
cairo_move_to(cr, p.x, p.y);
}
}
cairo_stroke(cr);
return;
}
///////////////////////////////////////////////////////
// Presure sensitiv stroken
///////////////////////////////////////////////////////
Point lastPoint1(-1, -1);
lastPoint1 = points.next();
while (points.hasNext())
{
Point p = points.next();
if (startPoint <= count)
{
if (lastPoint1.z != Point::NO_PRESURE)
{
width = lastPoint1.z;
}
// Set width
cairo_set_line_width(cr, width * scaleFactor);
cairo_move_to(cr, lastPoint1.x, lastPoint1.y);
cairo_line_to(cr, p.x, p.y);
cairo_stroke(cr);
}
count++;
lastPoint1 = p;
}
cairo_stroke(cr);
}
void DocumentView::drawText(cairo_t* cr, Text* t)
{
XOJ_CHECK_TYPE(DocumentView);
if (t->isInEditing())
{
return;
}
applyColor(cr, t);
TextView::drawText(cr, t);
}
void DocumentView::drawImage(cairo_t* cr, Image* i)
{
XOJ_CHECK_TYPE(DocumentView);
cairo_matrix_t defaultMatrix = { 0 };
cairo_get_matrix(cr, &defaultMatrix);
cairo_surface_t* img = i->getImage();
int width = cairo_image_surface_get_width(img);
int height = cairo_image_surface_get_height(img);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
double xFactor = i->getElementWidth() / width;
double yFactor = i->getElementHeight() / height;
cairo_scale(cr, xFactor, yFactor);
cairo_set_source_surface(cr, img, i->getX() / xFactor, i->getY() / yFactor);
cairo_paint(cr);
cairo_set_matrix(cr, &defaultMatrix);
}
void DocumentView::drawTexImage(cairo_t* cr, TexImage* i)
{
XOJ_CHECK_TYPE(DocumentView);
cairo_matrix_t defaultMatrix = { 0 };
cairo_get_matrix(cr, &defaultMatrix);
cairo_surface_t* img = i->getImage();
int width = cairo_image_surface_get_width(img);
int height = cairo_image_surface_get_height(img);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
double xFactor = i->getElementWidth() / width;
double yFactor = i->getElementHeight() / height;
cairo_scale(cr, xFactor, yFactor);
cairo_set_source_surface(cr, img, i->getX() / xFactor, i->getY() / yFactor);
cairo_paint(cr);
cairo_set_matrix(cr, &defaultMatrix);
}
void DocumentView::drawElement(cairo_t* cr, Element* e)
{
XOJ_CHECK_TYPE(DocumentView);
if (e->getType() == ELEMENT_STROKE)
{
drawStroke(cr, (Stroke*) e);
}
else if (e->getType() == ELEMENT_TEXT)
{
drawText(cr, (Text*) e);
}
else if (e->getType() == ELEMENT_IMAGE)
{
drawImage(cr, (Image*) e);
}
else if (e->getType() == ELEMENT_TEXIMAGE)
{
drawTexImage(cr, (TexImage*) e);
}
}
/**
* Draw a single layer
* @param cr Draw to thgis context
* @param l The layer to draw
*/
void DocumentView::drawLayer(cairo_t* cr, Layer* l)
{
XOJ_CHECK_TYPE(DocumentView);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
#ifdef DEBUG_SHOW_REPAINT_BOUNDS
int drawed = 0;
int notDrawed = 0;
#endif // DEBUG_SHOW_REPAINT_BOUNDS
for (Element* e : *l->getElements())
{
#ifdef DEBUG_SHOW_ELEMENT_BOUNDS
cairo_set_source_rgb(cr, 0, 1, 0);
cairo_set_line_width(cr, 1);
cairo_rectangle(cr, e->getX(), e->getY(), e->getElementWidth(), e->getElementHeight());
cairo_stroke(cr);
#endif // DEBUG_SHOW_REPAINT_BOUNDS
//cairo_new_path(cr);
if (this->lX != -1)
{
if (e->intersectsArea(this->lX, this->lY, this->width, this->height))
{
drawElement(cr, e);
#ifdef DEBUG_SHOW_REPAINT_BOUNDS
drawed++;
#endif // DEBUG_SHOW_REPAINT_BOUNDS
}
#ifdef DEBUG_SHOW_REPAINT_BOUNDS
else
{
notDrawed++;
}
#endif // DEBUG_SHOW_REPAINT_BOUNDS
}
else
{
#ifdef DEBUG_SHOW_REPAINT_BOUNDS
drawed++;
#endif // DEBUG_SHOW_REPAINT_BOUNDS
drawElement(cr, e);
}
}
#ifdef DEBUG_SHOW_REPAINT_BOUNDS
cout << bl::format("DBG:DocumentView: draw {1} / not draw {2}") % drawed % notDrawed << endl;
#endif // DEBUG_SHOW_REPAINT_BOUNDS
}
void DocumentView::paintBackgroundImage()
{
XOJ_CHECK_TYPE(DocumentView);
GdkPixbuf* pixbuff = page->getBackgroundImage().getPixbuf();
if (pixbuff)
{
cairo_matrix_t matrix = { 0 };
cairo_get_matrix(cr, &matrix);
int width = gdk_pixbuf_get_width(pixbuff);
int height = gdk_pixbuf_get_height(pixbuff);
double sx = page->getWidth() / width;
double sy = page->getHeight() / height;
cairo_scale(cr, sx, sy);
gdk_cairo_set_source_pixbuf(cr, pixbuff, 0, 0);
cairo_paint(cr);
cairo_set_matrix(cr, &matrix);
}
}
void DocumentView::drawSelection(cairo_t* cr, ElementContainer* container)
{
XOJ_CHECK_TYPE(DocumentView);
for (Element* e : *container->getElements())
{
drawElement(cr, e);
}
}
void DocumentView::limitArea(double x, double y, double width, double height)
{
XOJ_CHECK_TYPE(DocumentView);
this->lX = x;
this->lY = y;
this->lWidth = width;
this->lHeight = height;
}
/**
* Drawing first step
* @param page The page to draw
* @param cr Draw to thgis context
* @param dontRenderEditingStroke false to draw currently drawing stroke
*/
void DocumentView::initDrawing(PageRef page, cairo_t* cr, bool dontRenderEditingStroke)
{
XOJ_CHECK_TYPE(DocumentView);
this->cr = cr;
this->page = page;
this->width = page->getWidth();
this->height = page->getHeight();
this->dontRenderEditingStroke = dontRenderEditingStroke;
}
/**
* Last step in drawing
*/
void DocumentView::finializeDrawing()
{
XOJ_CHECK_TYPE(DocumentView);
#ifdef DEBUG_SHOW_REPAINT_BOUNDS
if (this->lX != -1)
{
cout << "DBG:repaint area" << endl;
cairo_set_source_rgb(cr, 1, 0, 0);
cairo_set_line_width(cr, 1);
cairo_rectangle(cr, this->lX + 3, this->lY + 3, this->lWidth - 6, this->lHeight - 6);
cairo_stroke(cr);
}
else
{
cout << "DBG:repaint complete" << endl;
}
#endif // DEBUG_SHOW_REPAINT_BOUNDS
this->lX = -1;
this->lY = -1;
this->lWidth = -1;
this->lHeight = -1;
this->page = NULL;
this->cr = NULL;
}
/**
* Draw the background
*/
void DocumentView::drawBackground()
{
PageType pt = page->getBackgroundType();
if (pt.isPdfPage())
{
// Handled in PdfView
}
else if (pt.isImagePage())
{
paintBackgroundImage();
}
else
{
backgroundPainter->paint(pt, cr, page);
}
}
/**
* Draw the full page, usually you would like to call this method
* @param page The page to draw
* @param cr Draw to thgis context
* @param dontRenderEditingStroke false to draw currently drawing stroke
* @param hideBackground true to hide the background
*/
void DocumentView::drawPage(PageRef page, cairo_t* cr, bool dontRenderEditingStroke, bool hideBackground)
{
XOJ_CHECK_TYPE(DocumentView);
initDrawing(page, cr, dontRenderEditingStroke);
if (!hideBackground)
{
drawBackground();
}
int layer = 0;
for (Layer* l : *page->getLayers())
{
if (l == NULL)
{
break;
}
if (layer >= page->getSelectedLayerId())
{
break;
}
drawLayer(cr, l);
layer++;
}
finializeDrawing();
}