~ubuntu-branches/ubuntu/precise/ipe/precise

« back to all changes in this revision

Viewing changes to src/ipeqtcanvas/ipeqtcanvas.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2009-12-11 21:22:35 UTC
  • mfrom: (4.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20091211212235-5iio4nzpra64snab
Tags: 7.0.10-1
* New upstream.  Closes: #551192.
  - New build-depends: libcairo2-dev, liblua5.1-0-dev, gsfonts
  - patches/config.diff: Remove.  Upstream build system replaced.
  - Runtime lib package changed to libipe7.0.10 from libipe1c2a
  - Devel package renamed to libipe-dev (from libipe1-dev)
  - Package ipe depends on lua5.1 due to ipe-update-master.

* rules: Re-write to use dh.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// --------------------------------------------------------------------
 
2
// ipeqt::Canvas
 
3
// --------------------------------------------------------------------
 
4
/*
 
5
 
 
6
    This file is part of the extensible drawing editor Ipe.
 
7
    Copyright (C) 1993-2009  Otfried Cheong
 
8
 
 
9
    Ipe is free software; you can redistribute it and/or modify it
 
10
    under the terms of the GNU General Public License as published by
 
11
    the Free Software Foundation; either version 3 of the License, or
 
12
    (at your option) any later version.
 
13
 
 
14
    As a special exception, you have permission to link Ipe with the
 
15
    CGAL library and distribute executables, as long as you follow the
 
16
    requirements of the Gnu General Public License in regard to all of
 
17
    the software in the executable aside from CGAL.
 
18
 
 
19
    Ipe is distributed in the hope that it will be useful, but WITHOUT
 
20
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
21
    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 
22
    License for more details.
 
23
 
 
24
    You should have received a copy of the GNU General Public License
 
25
    along with Ipe; if not, you can find it at
 
26
    "http://www.gnu.org/copyleft/gpl.html", or write to the Free
 
27
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
28
 
 
29
*/
 
30
 
 
31
#include "ipeqtcanvas.h"
 
32
#include "ipetool.h"
 
33
 
 
34
#include "ipecairopainter.h"
 
35
 
 
36
#include <QPainter>
 
37
#include <QPaintEvent>
 
38
 
 
39
using namespace ipe;
 
40
using namespace ipeqt;
 
41
 
 
42
// --------------------------------------------------------------------
 
43
 
 
44
/*! \namespace ipeqt
 
45
  \brief Ipe canvas library namespace
 
46
 
 
47
  This namespace is used for the components of Ipe that are dependent
 
48
  on the Qt toolkit.
 
49
*/
 
50
 
 
51
/*! \defgroup qtcanvas Ipe Qt canvas
 
52
  \brief A Qt widget that displays an Ipe document page.
 
53
 
 
54
  This module contains the classes needed to display and edit Ipe
 
55
  objects using the Qt toolkit.
 
56
 
 
57
  These classes are not in Ipelib, but in a separate library
 
58
  libipeqtcanvas.
 
59
*/
 
60
 
 
61
// --------------------------------------------------------------------
 
62
 
 
63
class IpeQtPainter : public Painter {
 
64
public:
 
65
  IpeQtPainter(const Cascade *sheet, QPainter *painter);
 
66
  virtual ~IpeQtPainter();
 
67
 
 
68
protected:
 
69
  virtual void doNewPath();
 
70
  virtual void doMoveTo(const Vector &v);
 
71
  virtual void doLineTo(const Vector &v);
 
72
  virtual void doCurveTo(const Vector &v1, const Vector &v2,
 
73
                         const Vector &v3);
 
74
  virtual void doClosePath();
 
75
 
 
76
  virtual void doDrawPath(TPathMode mode);
 
77
 
 
78
private:
 
79
  QPainter *iQP;
 
80
  QPainterPath iPP;
 
81
};
 
82
 
 
83
IpeQtPainter::IpeQtPainter(const Cascade *sheet, QPainter *painter)
 
84
  : Painter(sheet)
 
85
{
 
86
  iQP = painter;
 
87
}
 
88
 
 
89
IpeQtPainter::~IpeQtPainter()
 
90
{
 
91
  // nothing
 
92
}
 
93
 
 
94
void IpeQtPainter::doNewPath()
 
95
{
 
96
  iPP = QPainterPath();
 
97
}
 
98
 
 
99
void IpeQtPainter::doMoveTo(const Vector &v)
 
100
{
 
101
  iPP.moveTo(QPt(v));
 
102
}
 
103
 
 
104
void IpeQtPainter::doLineTo(const Vector &v)
 
105
{
 
106
  iPP.lineTo(QPt(v));
 
107
}
 
108
 
 
109
void IpeQtPainter::doCurveTo(const Vector &v1, const Vector &v2,
 
110
               const Vector &v3)
 
111
{
 
112
  iPP.cubicTo(QPt(v1), QPt(v2), QPt(v3));
 
113
}
 
114
 
 
115
void IpeQtPainter::doClosePath()
 
116
{
 
117
  iPP.closeSubpath();
 
118
}
 
119
 
 
120
void IpeQtPainter::doDrawPath(TPathMode mode)
 
121
{
 
122
  if (mode >= EStrokedAndFilled) {
 
123
    QBrush qbrush(QIpe(fill()));
 
124
    iQP->fillPath(iPP, qbrush);
 
125
  }
 
126
  if (mode <= EStrokedAndFilled) {
 
127
    QPen qpen(QIpe(stroke()));
 
128
    qpen.setWidthF(pen().toDouble());
 
129
    iQP->strokePath(iPP, qpen);
 
130
  }
 
131
}
 
132
 
 
133
// --------------------------------------------------------------------
 
134
 
 
135
/*! \class ipeqt::Canvas
 
136
  \ingroup qtcanvas
 
137
  \brief A Qt widget that displays an Ipe document page.
 
138
*/
 
139
 
 
140
//! Construct a new canvas.
 
141
Canvas::Canvas(QWidget* parent, Qt::WFlags f)
 
142
  : QWidget(parent, f)
 
143
{
 
144
  setAttribute(Qt::WA_NoBackground);
 
145
  setMouseTracking(true);
 
146
  setFocusPolicy(Qt::ClickFocus);
 
147
 
 
148
  iTool = 0;
 
149
  iPage = 0;
 
150
  iCascade = 0;
 
151
  iSurface = 0;
 
152
  iPan = Vector::ZERO;
 
153
  iZoom = 1.0;
 
154
  iDimmed = false;
 
155
  iWidth = 0;   // not yet known (canvas is not yet mapped)
 
156
  iHeight = 0;
 
157
  iRepaintObjects = false;
 
158
  iFonts = 0;
 
159
  iAutoSnap = false;
 
160
  iFifiVisible = false;
 
161
 
 
162
  iStyle.paperColor = Color(1000,1000,1000);
 
163
  iStyle.pretty = false;
 
164
  iStyle.classicGrid = false;
 
165
  iStyle.thinLine = 0.2;
 
166
  iStyle.thickLine = 0.9;
 
167
 
 
168
  iSnap.iSnap = 0;
 
169
  iSnap.iGridVisible = false;
 
170
  iSnap.iGridSize = 8;
 
171
  iSnap.iAngleSize = M_PI / 6.0;
 
172
  iSnap.iSnapDistance = 10;
 
173
  iSnap.iWithAxes = false;
 
174
  iSnap.iOrigin = Vector::ZERO;
 
175
  iSnap.iDir = 0;
 
176
}
 
177
 
 
178
//! destructor.
 
179
Canvas::~Canvas()
 
180
{
 
181
  if (iSurface)
 
182
    cairo_surface_destroy(iSurface);
 
183
  delete iFonts;
 
184
  delete iTool;
 
185
}
 
186
 
 
187
QSize Canvas::sizeHint() const
 
188
{
 
189
  return QSize(640, 480);
 
190
}
 
191
 
 
192
// --------------------------------------------------------------------
 
193
 
 
194
//! set information about Latex fonts (from ipe::Document)
 
195
void Canvas::setFontPool(const FontPool *fontPool)
 
196
{
 
197
  delete iFonts;
 
198
  iFonts = Fonts::New(fontPool);
 
199
}
 
200
 
 
201
// --------------------------------------------------------------------
 
202
 
 
203
//! Set the page to be displayed.
 
204
/*! Doesn't take ownership of any argument. */
 
205
void Canvas::setPage(const Page *page, int view, const Cascade *sheet)
 
206
{
 
207
  iPage = page;
 
208
  iView = view;
 
209
  iCascade = sheet;
 
210
}
 
211
 
 
212
//! Set style of canvas drawing.
 
213
/*! Includes paper color, pretty text, and grid. */
 
214
void Canvas::setCanvasStyle(const Style &style)
 
215
{
 
216
  iStyle = style;
 
217
}
 
218
 
 
219
//! Determine whether pretty display should be used.
 
220
/*! In pretty display, no dashed lines are drawn around text objects,
 
221
  and if Latex font data is not available, no text is drawn at all. */
 
222
void Canvas::setPretty(bool pretty)
 
223
{
 
224
  iStyle.pretty = pretty;
 
225
}
 
226
 
 
227
//! Set current pan position.
 
228
/*! The pan position is the user coordinate that is displayed at
 
229
  the very center of the canvas. */
 
230
void Canvas::setPan(const Vector &v)
 
231
{
 
232
  iPan = v;
 
233
}
 
234
 
 
235
//! Set current zoom factor.
 
236
/*! The zoom factor maps user coordinates to screen pixel coordinates. */
 
237
void Canvas::setZoom(double zoom)
 
238
{
 
239
  iZoom = zoom;
 
240
}
 
241
 
 
242
//! Set the snapping information.
 
243
void Canvas::setSnap(const Snap &s)
 
244
{
 
245
  iSnap = s;
 
246
}
 
247
 
 
248
//! Dim whole canvas, except for the Tool.
 
249
/*! This mode will be reset when the Tool finishes. */
 
250
void Canvas::setDimmed(bool dimmed)
 
251
{
 
252
  iDimmed = dimmed;
 
253
}
 
254
 
 
255
//! Enable automatic angular snapping with this origin.
 
256
void Canvas::setAutoOrigin(const Vector &v)
 
257
{
 
258
  iAutoOrigin = v;
 
259
  iAutoSnap = true;
 
260
}
 
261
 
 
262
//! Mark for update with redrawing of objects.
 
263
void Canvas::update()
 
264
{
 
265
  iRepaintObjects = true;
 
266
  QWidget::update();
 
267
}
 
268
 
 
269
//! Mark for update with redrawing of tool only.
 
270
void Canvas::updateTool()
 
271
{
 
272
  QWidget::update();
 
273
}
 
274
 
 
275
//! Convert canvas (device) coordinates to user coordinates.
 
276
Vector Canvas::devToUser(const Vector &arg) const
 
277
{
 
278
  Vector v = arg - center();
 
279
  v.x /= iZoom;
 
280
  v.y /= -iZoom;
 
281
  v += iPan;
 
282
  return v;
 
283
}
 
284
 
 
285
//! Convert user coordinates to canvas (device) coordinates.
 
286
Vector Canvas::userToDev(const Vector &arg) const
 
287
{
 
288
  Vector v = arg - iPan;
 
289
  v.x *= iZoom;
 
290
  v.y *= -iZoom;
 
291
  v += center();
 
292
  return v;
 
293
}
 
294
 
 
295
//! Matrix mapping user coordinates to canvas coordinates
 
296
Matrix Canvas::canvasTfm() const
 
297
{
 
298
  return Matrix(center()) *
 
299
    Linear(iZoom, 0, 0, -iZoom) *
 
300
    Matrix(-iPan);
 
301
}
 
302
 
 
303
// --------------------------------------------------------------------
 
304
 
 
305
void Canvas::drawAxes(cairo_t *cc)
 
306
{
 
307
  double alpha = 0.0;
 
308
  double ep = (iWidth + iHeight) / iZoom;
 
309
 
 
310
  cairo_save(cc);
 
311
  cairo_set_source_rgb(cc, 0.0, 1.0, 0.0);
 
312
  cairo_set_line_width(cc, 2.0 / iZoom);
 
313
  while (alpha < IpeTwoPi) {
 
314
    double beta = iSnap.iDir + alpha;
 
315
    cairo_move_to(cc, iSnap.iOrigin.x, iSnap.iOrigin.y);
 
316
    Vector dir(beta);
 
317
    cairo_rel_line_to(cc, ep * dir.x, ep * dir.y);
 
318
    if (alpha == 0.0) {
 
319
      cairo_stroke(cc);
 
320
      cairo_set_line_width(cc, 1.0 / iZoom);
 
321
    }
 
322
    alpha += iSnap.iAngleSize;
 
323
  }
 
324
  cairo_stroke(cc);
 
325
  cairo_restore(cc);
 
326
}
 
327
 
 
328
void Canvas::drawGrid(cairo_t *cc)
 
329
{
 
330
  int step = iSnap.iGridSize;
 
331
  double pixstep = step * iZoom;
 
332
  if (pixstep < 3.0)
 
333
    return;
 
334
 
 
335
  int vfactor = 1;
 
336
  int vstep = step * vfactor;
 
337
 
 
338
  Rect paper = iCascade->findLayout()->paper();
 
339
  Vector ll = paper.bottomLeft();
 
340
  Vector ur = paper.topRight();
 
341
 
 
342
  int left = step * int(ll.x / step);
 
343
  if (left < ll.x)
 
344
    ++left;
 
345
  int bottom = step * int(ll.y / step);
 
346
  if (bottom < ll.y)
 
347
    ++bottom;
 
348
 
 
349
  // only draw lines that intersect canvas
 
350
  Vector screenUL = devToUser(Vector::ZERO);
 
351
  Vector screenLR = devToUser(Vector(iWidth, iHeight));
 
352
 
 
353
  cairo_save(cc);
 
354
  cairo_set_source_rgb(cc, 0.3, 0.3, 0.3);
 
355
 
 
356
  if (iStyle.classicGrid) {
 
357
    double lw = iStyle.thinLine / iZoom;
 
358
    cairo_set_line_width(cc, lw);
 
359
    for (int y = bottom; y < ur.y; y += vstep) {
 
360
      if (screenLR.y <= y && y <= screenUL.y) {
 
361
        for (int x = left; x < ur.x; x += vstep) {
 
362
          if (screenUL.x <= x && x <= screenLR.x) {
 
363
            cairo_move_to(cc, x, y - 0.5 * lw);
 
364
            cairo_line_to(cc, x, y + 0.5 * lw);
 
365
            cairo_stroke(cc);
 
366
          }
 
367
        }
 
368
      }
 
369
    }
 
370
  } else {
 
371
    double thinLine = iStyle.thinLine / iZoom;
 
372
    double thickLine = iStyle.thickLine / iZoom;
 
373
    int thickStep = 4 * step;
 
374
 
 
375
    // draw horizontal lines
 
376
    for (int y = bottom; y < ur.y; y += vstep) {
 
377
      if (screenLR.y <= y && y <= screenUL.y) {
 
378
        cairo_set_line_width(cc, (y % thickStep) ? thinLine : thickLine);
 
379
        cairo_move_to(cc, ll.x, y);
 
380
        cairo_line_to(cc, ur.x, y);
 
381
        cairo_stroke(cc);
 
382
      }
 
383
    }
 
384
 
 
385
    // draw vertical lines
 
386
    for (int x = left; x < ur.x; x += vstep) {
 
387
      if (screenUL.x <= x && x <= screenLR.x) {
 
388
        cairo_set_line_width(cc, (x % thickStep) ? thinLine : thickLine);
 
389
        cairo_move_to(cc, x, ll.y);
 
390
        cairo_line_to(cc, x, ur.y);
 
391
        cairo_stroke(cc);
 
392
      }
 
393
    }
 
394
  }
 
395
 
 
396
  cairo_restore(cc);
 
397
}
 
398
 
 
399
void Canvas::drawPaper(cairo_t *cc)
 
400
{
 
401
  const Layout *l = iCascade->findLayout();
 
402
  cairo_rectangle(cc, -l->iOrigin.x, -l->iOrigin.y,
 
403
                  l->iPaperSize.x, l->iPaperSize.y);
 
404
  cairo_set_source_rgb(cc, iStyle.paperColor.iRed.toDouble(),
 
405
                       iStyle.paperColor.iGreen.toDouble(),
 
406
                       iStyle.paperColor.iBlue.toDouble());
 
407
  cairo_fill(cc);
 
408
}
 
409
 
 
410
void Canvas::drawFrame(cairo_t *cc)
 
411
{
 
412
  const Layout *l = iCascade->findLayout();
 
413
  cairo_set_source_rgb(cc, 0.5, 0.5, 0.5);
 
414
  cairo_save(cc);
 
415
  double dashes[2] = {3.0 / iZoom, 7.0 / iZoom};
 
416
  cairo_set_dash(cc, dashes, 2, 0.0);
 
417
  cairo_set_line_width(cc, 2.5 / iZoom);
 
418
  cairo_move_to(cc, 0.0, 0.0);
 
419
  cairo_line_to(cc, 0.0, l->iFrameSize.y);
 
420
  cairo_line_to(cc, l->iFrameSize.x, l->iFrameSize.y);
 
421
  cairo_line_to(cc, l->iFrameSize.x, 0);
 
422
  cairo_close_path(cc);
 
423
  cairo_stroke(cc);
 
424
  cairo_restore(cc);
 
425
}
 
426
 
 
427
void Canvas::drawObjects(cairo_t *cc)
 
428
{
 
429
  if (!iPage)
 
430
    return;
 
431
 
 
432
  CairoPainter painter(iCascade, iFonts, cc, iZoom, iStyle.pretty);
 
433
  painter.setDimmed(iDimmed);
 
434
  // painter.Transform(CanvasTfm());
 
435
  painter.pushMatrix();
 
436
 
 
437
  const Symbol *background =
 
438
    iCascade->findSymbol(Attribute::BACKGROUND());
 
439
  if (background && iPage->findLayer("BACKGROUND") < 0)
 
440
    background->iObject->draw(painter);
 
441
 
 
442
  const Text *title = iPage->titleText();
 
443
  if (title)
 
444
    title->draw(painter);
 
445
 
 
446
  for (int i = 0; i < iPage->count(); ++i) {
 
447
    if (iPage->objectVisible(iView, i))
 
448
      iPage->object(i)->draw(painter);
 
449
  }
 
450
  painter.popMatrix();
 
451
}
 
452
 
 
453
// --------------------------------------------------------------------
 
454
 
 
455
//! Draw the current canvas tool.
 
456
/*! If no tool is set, it draws the selected objects. */
 
457
void Canvas::drawTool(Painter &painter)
 
458
{
 
459
  if (iTool) {
 
460
    iTool->draw(painter);
 
461
  } else {
 
462
    for (int i = 0; i < iPage->count(); ++i) {
 
463
      if (iPage->objectVisible(iView, i)) {
 
464
        if (iPage->select(i) == EPrimarySelected) {
 
465
          painter.setStroke(Attribute(Color(1000, 0, 0)));
 
466
          painter.setPen(Attribute(Fixed(2)));
 
467
          iPage->object(i)->drawSimple(painter);
 
468
        } else if (iPage->select(i) == ESecondarySelected) {
 
469
          painter.setStroke(Attribute(Color(1000, 0, 1000)));
 
470
          painter.setPen(Attribute(Fixed(1)));
 
471
          iPage->object(i)->drawSimple(painter);
 
472
        }
 
473
      }
 
474
    }
 
475
  }
 
476
}
 
477
 
 
478
//! Set a new tool.
 
479
/*! Emits toolChanged() signal. */
 
480
void Canvas::setTool(Tool *tool)
 
481
{
 
482
  assert(tool);
 
483
  iTool = tool;
 
484
  updateTool();
 
485
  emit toolChanged(true);
 
486
}
 
487
 
 
488
// Current tool has done its job.
 
489
/* Tool is deleted, canvas fully updated, and cursor reset.
 
490
   Emits toolChanged() signal. */
 
491
void Canvas::finishTool()
 
492
{
 
493
  delete iTool;
 
494
  iTool = 0;
 
495
  iDimmed = false;
 
496
  iAutoSnap = false;
 
497
  update();
 
498
  unsetCursor();
 
499
  emit toolChanged(false);
 
500
}
 
501
 
 
502
// --------------------------------------------------------------------
 
503
 
 
504
bool Canvas::snapToPaperAndFrame()
 
505
{
 
506
  double snapDist = iSnap.iSnapDistance / iZoom;
 
507
  double d = snapDist;
 
508
  Vector fifi = iMousePos;
 
509
  const Layout *layout = iCascade->findLayout();
 
510
  Rect paper = layout->paper();
 
511
  Rect frame(Vector::ZERO, layout->iFrameSize);
 
512
 
 
513
  // vertices
 
514
  if (iSnap.iSnap & Snap::ESnapVtx) {
 
515
    paper.bottomLeft().snap(iMousePos, fifi, d);
 
516
    paper.topRight().snap(iMousePos, fifi, d);
 
517
    paper.topLeft().snap(iMousePos, fifi, d);
 
518
    paper.bottomRight().snap(iMousePos, fifi, d);
 
519
    frame.bottomLeft().snap(iMousePos, fifi, d);
 
520
    frame.topRight().snap(iMousePos, fifi, d);
 
521
    frame.topLeft().snap(iMousePos, fifi, d);
 
522
    frame.bottomRight().snap(iMousePos, fifi, d);
 
523
  }
 
524
 
 
525
  // Return if snapping has occurred
 
526
  if (d < snapDist) {
 
527
    iMousePos = fifi;
 
528
    return true;
 
529
  }
 
530
 
 
531
  // boundary
 
532
  if (iSnap.iSnap & Snap::ESnapBd) {
 
533
    Segment(paper.bottomLeft(), paper.bottomRight()).snap(iMousePos, fifi, d);
 
534
    Segment(paper.bottomRight(), paper.topRight()).snap(iMousePos, fifi, d);
 
535
    Segment(paper.topRight(), paper.topLeft()).snap(iMousePos, fifi, d);
 
536
    Segment(paper.topLeft(), paper.bottomLeft()).snap(iMousePos, fifi, d);
 
537
    Segment(frame.bottomLeft(), frame.bottomRight()).snap(iMousePos, fifi, d);
 
538
    Segment(frame.bottomRight(), frame.topRight()).snap(iMousePos, fifi, d);
 
539
    Segment(frame.topRight(), frame.topLeft()).snap(iMousePos, fifi, d);
 
540
    Segment(frame.topLeft(), frame.bottomLeft()).snap(iMousePos, fifi, d);
 
541
  }
 
542
 
 
543
  if (d < snapDist) {
 
544
    iMousePos = fifi;
 
545
    return true;
 
546
  }
 
547
 
 
548
  return true;
 
549
}
 
550
 
 
551
// --------------------------------------------------------------------
 
552
 
 
553
/*! Stores the mouse position in iUnsnappedMousePos, computes Fifi if
 
554
  snapping is enabled, and stores snapped position in iMousePos. */
 
555
void Canvas::computeFifi(double x, double y)
 
556
{
 
557
  iUnsnappedMousePos = devToUser(Vector(x, y));
 
558
  iMousePos = iUnsnappedMousePos;
 
559
 
 
560
  if (!iPage)
 
561
    return;
 
562
 
 
563
  int mask = iAutoSnap ? 0 : Snap::ESnapAuto;
 
564
  if (iSnap.iSnap & ~mask) {
 
565
    if (!iSnap.snap(iMousePos, iPage, iSnap.iSnapDistance / iZoom,
 
566
                    (iAutoSnap ? &iAutoOrigin : 0)))
 
567
      snapToPaperAndFrame();
 
568
 
 
569
    // convert fifi coordinates back into device space
 
570
    Vector fifi = userToDev(iMousePos);
 
571
    if (iFifiVisible && fifi != iOldFifi) {
 
572
      QWidget::update(QRect(int(iOldFifi.x - 10), int(iOldFifi.y - 10),
 
573
                            21, 21));
 
574
      QWidget::update(QRect(int(fifi.x - 10), int(fifi.y - 10), 21, 21));
 
575
    }
 
576
  } else if (iFifiVisible) {
 
577
    // remove old fifi
 
578
    QWidget::update(QRect(int(iOldFifi.x - 10), int(iOldFifi.y - 10), 21, 21));
 
579
    iFifiVisible = false;
 
580
  }
 
581
}
 
582
 
 
583
//! Set whether Fifi should be shown.
 
584
/*! Fifi will only be shown if a snapping mode is active. */
 
585
void Canvas::setFifiVisible(bool visible)
 
586
{
 
587
  iFifiVisible = visible;
 
588
  if (!visible)
 
589
    updateTool(); // when making visible, wait for position update
 
590
}
 
591
 
 
592
//! Return snapped mouse position without angular snapping.
 
593
Vector Canvas::simpleSnapPos() const
 
594
{
 
595
  Vector pos = iUnsnappedMousePos;
 
596
  iSnap.simpleSnap(pos, iPage, iSnap.iSnapDistance / iZoom);
 
597
  return pos;
 
598
}
 
599
 
 
600
// --------------------------------------------------------------------
 
601
 
 
602
void Canvas::keyPressEvent(QKeyEvent *ev)
 
603
{
 
604
  String s = IpeQ(ev->text());
 
605
  if (iTool && iTool->key(ev->key(), ev->modifiers(), s))
 
606
    ev->accept();
 
607
  else
 
608
    ev->ignore();
 
609
}
 
610
 
 
611
void Canvas::mousePressEvent(QMouseEvent *ev)
 
612
{
 
613
  iGlobalPos = Vector(ev->globalPos().x(), ev->globalPos().y());
 
614
  computeFifi(ev->x(), ev->y());
 
615
  if (iTool)
 
616
    iTool->mouseButton(ev->button() | ev->modifiers(), true);
 
617
  else
 
618
    emit mouseAction(ev->button() | ev->modifiers());
 
619
}
 
620
 
 
621
void Canvas::mouseReleaseEvent(QMouseEvent *ev)
 
622
{
 
623
  iGlobalPos = Vector(ev->globalPos().x(), ev->globalPos().y());
 
624
  computeFifi(ev->x(), ev->y());
 
625
  if (iTool)
 
626
    iTool->mouseButton(ev->button(), false);
 
627
}
 
628
 
 
629
void Canvas::mouseMoveEvent(QMouseEvent *ev)
 
630
{
 
631
  computeFifi(ev->x(), ev->y());
 
632
  if (iTool)
 
633
    iTool->mouseMove(ev->buttons());
 
634
  emit positionChanged();
 
635
}
 
636
 
 
637
void Canvas::tabletEvent(QTabletEvent *ev)
 
638
{
 
639
  Vector globalPos(ev->hiResGlobalPos().x(), ev->hiResGlobalPos().y());
 
640
  QPointF hiPos = ev->hiResGlobalPos() - (ev->globalPos() - ev->pos());
 
641
  ev->accept();
 
642
 
 
643
  switch (ev->type()) {
 
644
  case QEvent::TabletPress:
 
645
    if (ev->pointerType() == QTabletEvent::Eraser)
 
646
      return; // not yet implemented
 
647
    iGlobalPos = globalPos;
 
648
    computeFifi(hiPos.x(), hiPos.y());
 
649
    if (iTool)
 
650
      iTool->mouseButton(Qt::LeftButton, true);
 
651
    else
 
652
      emit mouseAction(Qt::LeftButton);
 
653
    break;
 
654
  case QEvent::TabletMove:
 
655
    if (ev->pressure() > 0.01) {
 
656
      computeFifi(hiPos.x(), hiPos.y());
 
657
      if (iTool)
 
658
        iTool->mouseMove(Qt::LeftButton);
 
659
      emit positionChanged();
 
660
      break;
 
661
    }
 
662
    // else fall through and consider it a release event
 
663
  case QEvent::TabletRelease:
 
664
    iGlobalPos = globalPos;
 
665
    computeFifi(hiPos.x(), hiPos.y());
 
666
    if (iTool)
 
667
      iTool->mouseButton(Qt::LeftButton, false);
 
668
    break;
 
669
  default:
 
670
    ipeDebug("Unknown tablet event");
 
671
    break;
 
672
  }
 
673
}
 
674
 
 
675
void Canvas::wheelEvent(QWheelEvent *ev)
 
676
{
 
677
  emit wheelMoved(ev->delta());
 
678
  ev->accept();
 
679
}
 
680
 
 
681
void Canvas::paintEvent(QPaintEvent * ev)
 
682
{
 
683
  QSize s = size();
 
684
  if (s.width() != iWidth || s.height() != iHeight) {
 
685
    // size has changed
 
686
    // ipeDebug("size has changed to %d x %d", s.width(), s.height());
 
687
    if (iSurface)
 
688
      cairo_surface_destroy(iSurface);
 
689
    iSurface = 0;
 
690
    iWidth = s.width();
 
691
    iHeight = s.height();
 
692
    iRepaintObjects = true;
 
693
  }
 
694
  if (iRepaintObjects) {
 
695
    iRepaintObjects = false;
 
696
    if (!iSurface)
 
697
      iSurface =
 
698
        cairo_image_surface_create(CAIRO_FORMAT_RGB24, iWidth, iHeight);
 
699
    cairo_t *cc = cairo_create(iSurface);
 
700
    // background
 
701
    cairo_set_source_rgb(cc, 0.4, 0.4, 0.4);
 
702
    cairo_rectangle(cc, 0, 0, iWidth, iHeight);
 
703
    cairo_fill(cc);
 
704
 
 
705
    cairo_translate(cc, 0.5 * iWidth, 0.5 * iHeight);
 
706
    cairo_scale(cc, iZoom, -iZoom);
 
707
    cairo_translate(cc, -iPan.x, -iPan.y);
 
708
 
 
709
    if (iPage) {
 
710
      drawPaper(cc);
 
711
      if (!iStyle.pretty)
 
712
        drawFrame(cc);
 
713
      if (iSnap.iGridVisible)
 
714
        drawGrid(cc);
 
715
      if (iSnap.iWithAxes)
 
716
        drawAxes(cc);
 
717
      drawObjects(cc);
 
718
    }
 
719
    cairo_surface_flush(iSurface);
 
720
    cairo_destroy(cc);
 
721
  }
 
722
  // -----------------------------------
 
723
  QPainter qPainter;
 
724
  qPainter.begin(this);
 
725
  QRect r = ev->rect();
 
726
  QImage bits(cairo_image_surface_get_data(iSurface),
 
727
              iWidth, iHeight, QImage::Format_RGB32);
 
728
  qPainter.drawImage(r.left(), r.top(), bits,
 
729
                     r.left(), r.top(), r.width(), r.height());
 
730
  qPainter.translate(-1, -1);
 
731
  if (iFifiVisible) {
 
732
    Vector p = userToDev(iMousePos);
 
733
    qPainter.setPen(QColor(255, 0, 0, 255));
 
734
    qPainter.drawLine(QPt(p - Vector(8, 0)), QPt(p + Vector(8, 0)));
 
735
    qPainter.drawLine(QPt(p - Vector(0, 8)), QPt(p + Vector(0, 8)));
 
736
    iOldFifi = p;
 
737
  }
 
738
  // -----------------------------------
 
739
  if (iPage) {
 
740
    IpeQtPainter qp(iCascade, &qPainter);
 
741
    qp.transform(canvasTfm());
 
742
    qp.pushMatrix();
 
743
    drawTool(qp);
 
744
    qp.popMatrix();
 
745
  }
 
746
  qPainter.end();
 
747
}
 
748
 
 
749
// --------------------------------------------------------------------