~ubuntu-branches/ubuntu/quantal/mysql-workbench/quantal

« back to all changes in this revision

Viewing changes to library/canvas/src/mdc_canvas_item.cpp

  • Committer: Package Import Robot
  • Author(s): Dmitry Smirnov
  • Date: 2012-03-01 21:57:30 UTC
  • Revision ID: package-import@ubuntu.com-20120301215730-o7y8av8y38n162ro
Tags: upstream-5.2.38+dfsg
ImportĀ upstreamĀ versionĀ 5.2.38+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License as
 
6
 * published by the Free Software Foundation; version 2 of the
 
7
 * License.
 
8
 * 
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
12
 * GNU General Public License for more details.
 
13
 * 
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 
17
 * 02110-1301  USA
 
18
 */
 
19
 
 
20
#include "stdafx.h"
 
21
 
 
22
#ifndef _WIN32
 
23
#include <stdexcept>
 
24
#endif
 
25
 
 
26
#include <string.h>
 
27
 
 
28
#include "mdc_canvas_item.h"
 
29
#include "mdc_algorithms.h"
 
30
#include "mdc_canvas_view.h"
 
31
#include "mdc_layer.h"
 
32
#include "mdc_draw_util.h"
 
33
#include "mdc_box_handle.h"
 
34
#include "mdc_interaction_layer.h"
 
35
#include "mdc_selection.h"
 
36
#include "mdc_magnet.h"
 
37
#include "mdc_bounds_magnet.h"
 
38
 
 
39
 
 
40
#define MAGNET_STICK_DISTANCE 5
 
41
 
 
42
using namespace mdc;
 
43
using namespace MySQL::Geometry;
 
44
using namespace MySQL::Drawing;
 
45
 
 
46
int mdc_live_item_count = 0;
 
47
 
 
48
CanvasItem::CanvasItem(Layer *layer)
 
49
  : _layer(layer), _parent(0)
 
50
{
 
51
  mdc_live_item_count++;
 
52
  _pos.x= 0.0f;
 
53
  _pos.y= 0.0f;
 
54
  _focused= 0;
 
55
  _selected= 0;
 
56
  _accepts_focus= 0;
 
57
  _accepts_selection= 0;
 
58
  _draws_hover= 0;
 
59
  _hovering= 0;
 
60
  _disabled= 0;
 
61
  
 
62
  _auto_sizing= 1;
 
63
  _needs_render= 1;
 
64
  _visible= 1;
 
65
  _min_size_invalid= 1;
 
66
  _cache_toplevel_content= 0;
 
67
  _has_shadow= 0;
 
68
  _draggable= 0;
 
69
  _dragging= 0;
 
70
  _highlighted= 0;
 
71
  _highlight_color= 0;
 
72
 
 
73
  _disable_state_drawing= 0;
 
74
 
 
75
  _xpadding= 0;
 
76
  _ypadding= 0;
 
77
 
 
78
  _hresizeable= 1;
 
79
  _vresizeable= 1;
 
80
 
 
81
  _content_cache= 0;
 
82
  _content_texture= 0;
 
83
  _display_list= 0;
 
84
 
 
85
  _fixed_min_size= Size(-1, -1);
 
86
  _fixed_size= Size(-1, -1);
 
87
 
 
88
  _bounds_changed_signal.connect(boost::bind(&CanvasItem::update_handles, this));
 
89
 
 
90
  scoped_connect(layer->get_view()->signal_zoom_changed(),boost::bind(&CanvasItem::invalidate_cache, this));
 
91
}
 
92
 
 
93
 
 
94
CanvasItem::~CanvasItem()
 
95
{
 
96
  --mdc_live_item_count;
 
97
  delete _highlight_color;
 
98
  
 
99
  if (_parent)
 
100
  {
 
101
    //if (!_parent->_destroyed)
 
102
    {
 
103
      Layouter *l= dynamic_cast<Layouter*>(_parent);
 
104
      if (l)
 
105
        l->remove(this);
 
106
    }
 
107
    _parent= 0;
 
108
  }
 
109
  get_layer()->remove_item(this);
 
110
 
 
111
  destroy_handles();
 
112
 
 
113
  for (std::vector<Magnet*>::iterator iter= _magnets.begin(); iter != _magnets.end(); ++iter)
 
114
    delete *iter;
 
115
 
 
116
  if (_content_cache)
 
117
    cairo_surface_destroy(_content_cache);
 
118
  
 
119
  if (_display_list != 0)
 
120
    glDeleteLists(_display_list, 1);
 
121
 
 
122
  if (_content_texture != 0)
 
123
    glDeleteTextures(1, &_content_texture);
 
124
}
 
125
 
 
126
 
 
127
mdc::CanvasItem *CanvasItem::find_item_with_tag(const std::string &tag)
 
128
{
 
129
  if (tag == _tag)
 
130
    return this;
 
131
  return 0;
 
132
}
 
133
 
 
134
 
 
135
void CanvasItem::set_bounds(const Rect &rect)
 
136
{
 
137
  Rect obounds= get_bounds();
 
138
  
 
139
  if (obounds != rect)
 
140
  {
 
141
    _pos= rect.pos;
 
142
    _size= rect.size;
 
143
  
 
144
  //  _bounds_changed_signal.emit(obounds);
 
145
  
 
146
    update_handles();
 
147
  }
 
148
}
 
149
 
 
150
 
 
151
 
 
152
void CanvasItem::set_position(const Point &pos)
 
153
{
 
154
  if (_pos != pos)
 
155
  {
 
156
    Rect obounds= get_bounds();
 
157
  
 
158
    _pos= pos.round();
 
159
  
 
160
    _bounds_changed_signal(obounds);
 
161
  
 
162
    update_handles();
 
163
  }
 
164
}
 
165
 
 
166
 
 
167
void CanvasItem::set_size(const Size &size)
 
168
{
 
169
  if (_size != size)
 
170
  { 
 
171
    Rect obounds= get_bounds();
 
172
 
 
173
    _size= size;
 
174
 
 
175
    _bounds_changed_signal(obounds);
 
176
  
 
177
    update_handles();
 
178
  }
 
179
}
 
180
 
 
181
 
 
182
Rect CanvasItem::get_root_bounds() const
 
183
{
 
184
  return Rect(get_root_position(), get_size());
 
185
}
 
186
 
 
187
 
 
188
Rect CanvasItem::get_padded_root_bounds() const
 
189
{
 
190
  Rect bounds(get_root_bounds());
 
191
 
 
192
  bounds.pos.x-= LEFT_OUTER_PAD;
 
193
  bounds.pos.y-= TOP_OUTER_PAD;
 
194
  bounds.size.width+= RIGHT_OUTER_PAD+LEFT_OUTER_PAD;
 
195
  bounds.size.height+= BOTTOM_OUTER_PAD+TOP_OUTER_PAD;
 
196
 
 
197
  return bounds;
 
198
}
 
199
 
 
200
 
 
201
Rect CanvasItem::get_bounds() const
 
202
{
 
203
  return Rect(get_position(), get_size());
 
204
}
 
205
 
 
206
 
 
207
Point CanvasItem::get_root_position() const
 
208
{
 
209
  return convert_point_to(Point(0,0), 0);
 
210
}
 
211
 
 
212
 
 
213
bool CanvasItem::intersects(const Rect &bounds) const
 
214
{
 
215
  return bounds_intersect(bounds, get_bounds());
 
216
}
 
217
 
 
218
 
 
219
bool CanvasItem::contains_point(const Point &point) const
 
220
{
 
221
  return bounds_contain_point(get_bounds(), point.x, point.y);  
 
222
}
 
223
 
 
224
 
 
225
void CanvasItem::set_fixed_min_size(const Size &size)
 
226
{
 
227
  _min_size_invalid= true;
 
228
  _fixed_min_size= size;
 
229
}
 
230
 
 
231
 
 
232
Size CanvasItem::calc_min_size()
 
233
{
 
234
  return Size(_xpadding*2, _ypadding*2);
 
235
}
 
236
 
 
237
 
 
238
Size CanvasItem::get_min_size()
 
239
{
 
240
  if (_min_size_invalid)
 
241
  {
 
242
    Size size= Size(-1,-1);//_fixed_size;
 
243
    Size msize;
 
244
    
 
245
    if (size.width < 0)
 
246
      size.width= _fixed_min_size.width;
 
247
    if (size.height < 0)
 
248
      size.height= _fixed_min_size.height;
 
249
 
 
250
    if (size.width >= 0 && size.height >= 0)
 
251
      _min_size= size;
 
252
    else
 
253
    {
 
254
      msize= calc_min_size();
 
255
      
 
256
      if (size.width < 0)
 
257
        size.width= msize.width;
 
258
      
 
259
      if (size.height < 0)
 
260
        size.height= msize.height;
 
261
      
 
262
      _min_size= size;
 
263
    }
 
264
    _min_size_invalid= false;
 
265
  }
 
266
 
 
267
  return _min_size;
 
268
}
 
269
 
 
270
 
 
271
void CanvasItem::set_padding(double xpad, double ypad)
 
272
{
 
273
  _xpadding= xpad;
 
274
  _ypadding= ypad;
 
275
 
 
276
  set_needs_relayout();
 
277
}
 
278
 
 
279
 
 
280
void CanvasItem::resize_to(const Size &size)
 
281
{
 
282
  if (_size != size)
 
283
  {
 
284
  set_size(size);
 
285
  set_needs_render();
 
286
  }
 
287
}
 
288
 
 
289
 
 
290
void CanvasItem::move_to(const Point &pos)
 
291
{
 
292
  set_position(pos);
 
293
 
 
294
  if (is_toplevel())
 
295
    set_needs_repaint();
 
296
  else
 
297
    set_needs_render();
 
298
//  _layer->set_needs_repaint();
 
299
}
 
300
 
 
301
 
 
302
void CanvasItem::set_fixed_size(const Size &size)
 
303
{
 
304
  Rect obounds(get_bounds());
 
305
 
 
306
  _min_size_invalid= true;
 
307
  _fixed_size= size;
 
308
  _size= size;
 
309
  _bounds_changed_signal(obounds);
 
310
  set_needs_relayout();
 
311
}
 
312
 
 
313
 
 
314
 
 
315
void CanvasItem::parent_bounds_changed(const Rect &obounds, CanvasItem *item)
 
316
{
 
317
  _parent_bounds_changed_signal(item, obounds);
 
318
  
 
319
  update_handles();
 
320
}
 
321
 
 
322
 
 
323
void CanvasItem::grand_parent_bounds_changed(CanvasItem *item, const Rect &obounds)
 
324
{
 
325
  _parent_bounds_changed_signal(item, obounds);
 
326
  
 
327
  update_handles();
 
328
}
 
329
 
 
330
 
 
331
void CanvasItem::set_parent(CanvasItem *parent)
 
332
{
 
333
  if (parent != 0 && _parent != 0 && parent != _parent)
 
334
    throw std::logic_error("setting parent to already parented item");
 
335
 
 
336
  _parent= parent;
 
337
 
 
338
  if (parent)
 
339
  {
 
340
    _reparent_signal();
 
341
 
 
342
    _parent_bounds_con= parent->signal_bounds_changed()->connect(boost::bind(&CanvasItem::parent_bounds_changed, this, _1, parent));
 
343
 
 
344
    _grand_parent_bounds_con= parent->signal_parent_bounds_changed()->connect(boost::bind(&CanvasItem::grand_parent_bounds_changed, this, _1, _2));
 
345
  }
 
346
}
 
347
 
 
348
 
 
349
void CanvasItem::remove_from_parent()
 
350
{
 
351
  if (_parent)
 
352
    dynamic_cast<Layouter*>(_parent)->remove(this);
 
353
}
 
354
 
 
355
 
 
356
CanvasView *CanvasItem::get_view() const
 
357
{
 
358
  if (_layer)
 
359
    return _layer->get_view();
 
360
  return 0;
 
361
}
 
362
 
 
363
 
 
364
void CanvasItem::set_accepts_focus(bool flag)
 
365
{
 
366
  _accepts_focus= flag;
 
367
}
 
368
 
 
369
 
 
370
void CanvasItem::set_accepts_selection(bool flag)
 
371
{
 
372
  _accepts_selection= flag;
 
373
}
 
374
 
 
375
 
 
376
void CanvasItem::set_draws_hover(bool flag)
 
377
{
 
378
  if (_draws_hover != flag)
 
379
  {
 
380
    _draws_hover= flag;
 
381
    set_needs_render();
 
382
  }
 
383
}
 
384
 
 
385
void CanvasItem::set_highlighted(bool flag)
 
386
{
 
387
  if (_highlighted != flag)
 
388
  {
 
389
    _highlighted= flag;
 
390
    set_needs_render();
 
391
  }
 
392
}
 
393
 
 
394
 
 
395
void CanvasItem::set_highlight_color(const Color *color)
 
396
{
 
397
  if (_highlight_color)
 
398
    delete _highlight_color;
 
399
  
 
400
  if (color)
 
401
    _highlight_color= new Color(*color);
 
402
  else
 
403
    _highlight_color= 0;
 
404
  
 
405
  if (_highlighted)
 
406
    set_needs_render();
 
407
}
 
408
 
 
409
 
 
410
void CanvasItem::set_selected(bool flag)
 
411
{
 
412
  if (_selected != flag)
 
413
  {
 
414
    _selected= flag;
 
415
    if (!_selected)
 
416
      get_layer()->get_view()->focus_item(0);
 
417
 
 
418
    set_needs_render();
 
419
  }
 
420
}
 
421
 
 
422
 
 
423
void CanvasItem::set_focused(bool flag)
 
424
{
 
425
  if (_focused != flag)
 
426
  {
 
427
    _focused= flag;
 
428
    set_needs_render();
 
429
    
 
430
    _focus_changed_signal(flag);
 
431
  }
 
432
}
 
433
 
 
434
 
 
435
void CanvasItem::set_allowed_resizing(bool horizontal, bool vertical)
 
436
{
 
437
  _hresizeable= horizontal;
 
438
  _vresizeable= vertical;
 
439
}
 
440
 
 
441
 
 
442
void CanvasItem::set_draggable(bool flag)
 
443
{
 
444
  _draggable= flag;
 
445
}
 
446
 
 
447
 
 
448
void CanvasItem::set_auto_sizing(bool flag)
 
449
{
 
450
  _auto_sizing= flag;
 
451
  _min_size_invalid= true;
 
452
  set_needs_relayout();
 
453
}
 
454
 
 
455
//------------------------------------------------------------------------------
 
456
 
 
457
void CanvasItem::set_cache_toplevel_contents(bool flag)
 
458
{
 
459
  _cache_toplevel_content= flag;
 
460
}
 
461
 
 
462
 
 
463
void CanvasItem::invalidate_cache()
 
464
{
 
465
  if (_content_cache)
 
466
  {
 
467
    _layer->get_view()->bookkeep_cache_mem(-cairo_image_surface_get_stride(_content_cache) * cairo_image_surface_get_height(_content_cache));
 
468
    cairo_surface_destroy(_content_cache);
 
469
  }
 
470
  _content_cache= 0;
 
471
  set_needs_render();
 
472
}
 
473
 
 
474
 
 
475
void CanvasItem::set_has_shadow(bool flag)
 
476
{
 
477
  if (_has_shadow != flag)
 
478
  {
 
479
    _has_shadow= flag;
 
480
    set_needs_render();
 
481
  }
 
482
}
 
483
 
 
484
 
 
485
void CanvasItem::set_visible(bool flag)
 
486
{
 
487
  if (_visible != flag)
 
488
  {
 
489
    _visible= flag;
 
490
    set_needs_relayout();
 
491
  }
 
492
}
 
493
 
 
494
 
 
495
bool CanvasItem::get_parents_visible() const
 
496
{
 
497
  CanvasItem *item= get_parent();
 
498
 
 
499
  while (item && !item->is_toplevel())
 
500
  {
 
501
    if (!item->get_visible())
 
502
      return false;
 
503
    item= item->get_parent();
 
504
  }
 
505
  return true;
 
506
}
 
507
 
 
508
 
 
509
void CanvasItem::set_needs_repaint()
 
510
{
 
511
  Rect bounds(get_root_bounds());
 
512
 
 
513
  bounds.pos.x-= LEFT_OUTER_PAD;
 
514
  bounds.pos.y-= TOP_OUTER_PAD;
 
515
  bounds.size.width+= LEFT_OUTER_PAD+RIGHT_OUTER_PAD;
 
516
  bounds.size.height+= TOP_OUTER_PAD+BOTTOM_OUTER_PAD;
 
517
 
 
518
  if (bounds.pos.x < 0) bounds.pos.x= 0;
 
519
  if (bounds.pos.y < 0) bounds.pos.y= 0;
 
520
 
 
521
  if (_old_bounds != bounds)
 
522
  {
 
523
    if (_old_bounds.width() > 0 && _old_bounds.height() > 0)
 
524
      _layer->queue_repaint(_old_bounds);
 
525
    _old_bounds= bounds;
 
526
  }
 
527
  _layer->queue_repaint(_old_bounds);
 
528
}
 
529
 
 
530
 
 
531
void CanvasItem::set_needs_render()
 
532
{
 
533
  /*
 
534
  if (!_needs_render)
 
535
  {
 
536
    if (_parent && !is_toplevel())
 
537
      _parent->set_needs_render();
 
538
    else
 
539
    {
 
540
      _needs_render= true;
 
541
      _layer->set_needs_repaint();//get_bounds();
 
542
    }
 
543
  }*/
 
544
 
 
545
 
 
546
  if (_parent && !is_toplevel())
 
547
    _parent->set_needs_render();
 
548
  else if (!_needs_render)
 
549
  {
 
550
    _needs_render= true;
 
551
 
 
552
    set_needs_repaint();
 
553
  }
 
554
}
 
555
 
 
556
 
 
557
void CanvasItem::set_needs_relayout()
 
558
{
 
559
  _min_size_invalid= 1;
 
560
  // propagate the relayout request up until the last parent, which will
 
561
  // be a toplevel item. the toplevel will in its turn, add itself to the layers
 
562
  // relayout queue, which will be flushed on the next redraw oportunity
 
563
  if (_parent && !is_toplevel())
 
564
    _parent->set_needs_relayout();
 
565
  else
 
566
  {
 
567
    CanvasItem *toplevel= get_toplevel();
 
568
    if (toplevel)
 
569
      _layer->queue_relayout(toplevel);
 
570
  }
 
571
  set_needs_render();
 
572
}
 
573
 
 
574
 
 
575
void CanvasItem::auto_size()
 
576
{
 
577
  Size size= _fixed_size;
 
578
  Size minsize= get_min_size();
 
579
 
 
580
  minsize.width+= _xpadding*2;
 
581
  minsize.height+= _ypadding*2;
 
582
 
 
583
  if (size.width < 0)
 
584
    size.width= minsize.width;
 
585
  if (size.height < 0)
 
586
    size.height= minsize.height;
 
587
  
 
588
  resize_to(size);
 
589
}
 
590
 
 
591
 
 
592
void CanvasItem::relayout()
 
593
{
 
594
  // called by layer only
 
595
  if (_auto_sizing)
 
596
    auto_size();
 
597
  else
 
598
  {
 
599
    Size size= get_fixed_size();
 
600
 
 
601
    if (size.width < 0)
 
602
      size.width= _size.width;
 
603
    if (size.height < 0)
 
604
      size.height= _size.height;
 
605
    
 
606
    resize_to(size);
 
607
  }
 
608
}
 
609
 
 
610
 
 
611
bool CanvasItem::is_toplevel() const
 
612
{
 
613
  if (dynamic_cast<Group*>(_parent))
 
614
    return true;
 
615
  return false;
 
616
}
 
617
 
 
618
 
 
619
CanvasItem *CanvasItem::get_toplevel() const
 
620
{
 
621
  if (_parent)
 
622
  {
 
623
    if (is_toplevel())
 
624
      return (CanvasItem*)this;
 
625
    return _parent->get_toplevel();
 
626
  }
 
627
  return 0;
 
628
}
 
629
 
 
630
 
 
631
CanvasItem::State CanvasItem::get_state()
 
632
{
 
633
  if (_disabled)
 
634
    return Disabled;
 
635
  else if (_hovering && _draws_hover)
 
636
    return Hovering;
 
637
  else if (_highlighted)
 
638
    return Highlighted;
 
639
  else if (_selected)
 
640
    return Selected;
 
641
  return Normal;
 
642
}
 
643
 
 
644
 
 
645
void CanvasItem::set_state_drawing(bool flag)
 
646
{
 
647
  _disable_state_drawing= !flag;
 
648
}
 
649
 
 
650
//--------------------------------------------------------------------------------------------------
 
651
 
 
652
void CanvasItem::draw_state(CairoCtx *cr)
 
653
{
 
654
  if (!get_view()->is_printout() && !_disable_state_drawing)
 
655
  {    
 
656
    switch (get_state())
 
657
    {
 
658
    case Disabled:
 
659
      break;
 
660
 
 
661
    case Hovering:
 
662
      draw_outline_ring(cr, get_view()->get_hover_color());
 
663
      break;
 
664
 
 
665
    case Highlighted:
 
666
      draw_outline_ring(cr, _highlight_color ? *_highlight_color : get_view()->get_highlight_color());
 
667
      break;
 
668
 
 
669
    case Selected:
 
670
      draw_outline_ring(cr, get_view()->get_selection_color());
 
671
      break;
 
672
 
 
673
    case Normal:
 
674
      break;
 
675
    }
 
676
  }
 
677
}
 
678
 
 
679
//--------------------------------------------------------------------------------------------------
 
680
 
 
681
void CanvasItem::draw_state_gl()
 
682
{
 
683
  if (!get_view()->is_printout() && !_disable_state_drawing)
 
684
  {    
 
685
    switch (get_state())
 
686
    {
 
687
      case Disabled:
 
688
        break;
 
689
        
 
690
      case Hovering:
 
691
        draw_outline_ring_gl(get_view()->get_hover_color());
 
692
        break;
 
693
        
 
694
      case Highlighted:
 
695
        draw_outline_ring_gl(_highlight_color ? *_highlight_color : get_view()->get_highlight_color());
 
696
        break;
 
697
        
 
698
      case Selected:
 
699
        draw_outline_ring_gl(get_view()->get_selection_color());
 
700
        break;
 
701
        
 
702
      case Normal:
 
703
        break;
 
704
    }
 
705
  }
 
706
}
 
707
 
 
708
//--------------------------------------------------------------------------------------------------
 
709
 
 
710
void CanvasItem::draw_outline_ring(CairoCtx *cr, const Color &color)
 
711
{
 
712
  cr->save();
 
713
  
 
714
  cr->set_color(color, color.alpha);
 
715
  cr->set_line_width(2);
 
716
  stroke_outline(cr, 1);
 
717
  cr->stroke();
 
718
  
 
719
  cr->set_color(color, color.alpha * 0.3);
 
720
  cr->set_line_width(4);
 
721
  stroke_outline(cr, 2);
 
722
  cr->stroke();
 
723
  
 
724
  cr->restore();
 
725
}
 
726
 
 
727
//--------------------------------------------------------------------------------------------------
 
728
 
 
729
void CanvasItem::draw_outline_ring_gl(const Color &color)
 
730
{
 
731
  gl_setcolor(color);
 
732
  glLineWidth(2);
 
733
  stroke_outline_gl(1);
 
734
  
 
735
  Color blended= Color(color.red, color.green, color.blue, 0.3 * color.alpha);
 
736
  gl_setcolor(blended);
 
737
  glLineWidth(4);
 
738
  stroke_outline_gl(1);
 
739
  glLineWidth(1);
 
740
}
 
741
 
 
742
//--------------------------------------------------------------------------------------------------
 
743
 
 
744
void CanvasItem::render(CairoCtx *cr)
 
745
{
 
746
}
 
747
 
 
748
 
 
749
void CanvasItem::render_gl(CairoCtx *cr)
 
750
{
 
751
}
 
752
 
 
753
 
 
754
void CanvasItem::render_to_surface(cairo_surface_t *surf, bool use_padding)
 
755
{
 
756
  CairoCtx cr(surf);
 
757
  
 
758
  cr.scale(_layer->get_view()->get_zoom(), _layer->get_view()->get_zoom());
 
759
  if (use_padding)
 
760
    cr.translate(floor(LEFT_OUTER_PAD - _pos.x), floor(TOP_OUTER_PAD - _pos.y));
 
761
  else
 
762
    cr.translate(floor(-_pos.x), floor(-_pos.y));
 
763
 
 
764
  render(&cr);
 
765
}
 
766
 
 
767
 
 
768
 
 
769
void CanvasItem::repaint_gl(const Rect &clipArea)
 
770
{
 
771
  CairoCtx *ccr= _layer->get_view()->cairoctx();
 
772
  
 
773
  // 1st check if we can directly render as gl
 
774
  if (can_render_gl())
 
775
  {
 
776
    render_gl(ccr);
 
777
    return;
 
778
  }
 
779
 
 
780
  // if direct gl render wasn't available, then use the cache as a texture and render
 
781
  // that instead
 
782
  bool generate_display_list= _display_list == 0;
 
783
 
 
784
  // Check if we need to regenerate the cache. if so, do it and load it as a texture.
 
785
  Size texture_size= get_texture_size(Size(0, 0));
 
786
  if (_needs_render || _content_texture == 0)
 
787
  {
 
788
    generate_display_list= true;
 
789
 
 
790
    // _content_cache is the bitmap with image data, we load that as a texture and release it.
 
791
    regenerate_cache(texture_size);
 
792
 
 
793
    if (!_content_cache)
 
794
    {
 
795
#ifndef WIN32
 
796
      g_warning("failed to paint canvas item into a memory buffer");
 
797
#endif
 
798
      return;
 
799
    }
 
800
 
 
801
    if (_content_texture == 0)
 
802
      glGenTextures(1, &_content_texture);
 
803
 
 
804
    // setup the texture
 
805
    glBindTexture(GL_TEXTURE_2D, _content_texture);
 
806
   
 
807
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
808
 
 
809
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
810
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 
811
    // don't tile the image
 
812
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
 
813
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
 
814
 
 
815
    // load the texture into opengl
 
816
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
 
817
      (int) texture_size.width,  (int) texture_size.height, 0,
 
818
                 GL_BGRA, GL_UNSIGNED_BYTE, //GL_UNSIGNED_INT_8_8_8_8_REV, // <-- optimal format
 
819
                 cairo_image_surface_get_data(_content_cache));
 
820
 
 
821
    // Once we transferred the pixel data we don't need the cache anymore.
 
822
    _layer->get_view()->bookkeep_cache_mem(-cairo_image_surface_get_stride(_content_cache) * cairo_image_surface_get_height(_content_cache));
 
823
    cairo_surface_destroy(_content_cache);
 
824
    _content_cache= 0;
 
825
  }
 
826
 
 
827
  glMatrixMode(GL_MODELVIEW);
 
828
  glPushMatrix();
 
829
 
 
830
  Rect bounds(get_bounds());
 
831
 
 
832
  bounds.pos.x-= LEFT_OUTER_PAD;
 
833
  bounds.pos.y-= TOP_OUTER_PAD;
 
834
  bounds.size.width+= RIGHT_OUTER_PAD+LEFT_OUTER_PAD;
 
835
  bounds.size.height+= BOTTOM_OUTER_PAD+TOP_OUTER_PAD;
 
836
 
 
837
  glTranslated(bounds.left(), bounds.top(), 0);
 
838
 
 
839
  if (generate_display_list)
 
840
  {
 
841
    if (_display_list == 0)
 
842
      _display_list= glGenLists(1);
 
843
 
 
844
 
 
845
    glNewList(_display_list, GL_COMPILE);
 
846
 
 
847
    glEnable(GL_TEXTURE_2D);
 
848
    
 
849
      // Render the texture.
 
850
    glBindTexture(GL_TEXTURE_2D, _content_texture);
 
851
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
 
852
    glBegin(GL_QUADS);
 
853
 
 
854
    // Due to round-up to power of two the actual texture coordinates are usually somewhere within the actual texture.
 
855
    // Box coordinates must be scaled too, as the texture size depends on the zoom factor, however the box size does not.
 
856
    double width= bounds.width();
 
857
    double height= bounds.height();
 
858
    cairo_user_to_device_distance(_layer->get_view()->cairoctx()->get_cr(), &width, &height);
 
859
    double max_x_coordinate= width / texture_size.width;
 
860
    double max_y_coordinate= height / texture_size.height;
 
861
 
 
862
    glTexCoord2d(0, 0);
 
863
    glVertex2d(0, 0);
 
864
 
 
865
    glTexCoord2d(max_x_coordinate, 0);
 
866
    glVertex2d(bounds.width(), 0);
 
867
 
 
868
    glTexCoord2d(max_x_coordinate, max_y_coordinate);
 
869
    glVertex2d(bounds.width(), bounds.height());
 
870
 
 
871
    glTexCoord2d(0, max_y_coordinate);
 
872
    glVertex2d(0, bounds.height());
 
873
 
 
874
    glEnd();
 
875
    glDisable(GL_TEXTURE_2D);
 
876
 
 
877
    glEndList();
 
878
  }
 
879
 
 
880
  glCallList(_display_list);
 
881
  
 
882
  glPopMatrix();
 
883
}
 
884
 
 
885
 
 
886
void CanvasItem::repaint(const Rect &clipArea, bool direct)
 
887
{
 
888
  // Don't render OpenGL commands if "direct" is true, which means we are rendering to off-screen bitmap
 
889
  // (for printing, png/pdf export or similar).
 
890
  if (_layer->get_view()->has_gl() && !direct)
 
891
    repaint_gl(clipArea);
 
892
  else
 
893
  {
 
894
    if (direct)
 
895
      repaint_direct();
 
896
    else
 
897
      repaint_cached();
 
898
  }
 
899
}
 
900
 
 
901
 
 
902
void CanvasItem::repaint_direct()
 
903
{
 
904
  CairoCtx *ccr= _layer->get_view()->cairoctx();
 
905
  
 
906
  ccr->save();
 
907
 
 
908
  render(ccr);
 
909
 
 
910
  ccr->restore();
 
911
}
 
912
 
 
913
//----------------------------------------------------------------------------------------------------------------------
 
914
 
 
915
/**
 
916
 * Returns the size we need to use for allocating the cache and the final texture. Depends on padding, zoom
 
917
 * and other factors.
 
918
 *
 
919
 * @param size The base size to use to compute the right texture size (must be a power of 2). Can be 0 in which
 
920
 *             case the item's entire size is used.
 
921
 */
 
922
Size CanvasItem::get_texture_size(Size size)
 
923
{
 
924
  if (size.width == 0 || size.height == 0)
 
925
  {
 
926
    size= get_size();
 
927
 
 
928
    size.width += LEFT_OUTER_PAD + RIGHT_OUTER_PAD;
 
929
    size.height += TOP_OUTER_PAD + BOTTOM_OUTER_PAD;
 
930
  }
 
931
 
 
932
  cairo_user_to_device_distance(_layer->get_view()->cairoctx()->get_cr(), &size.width, &size.height);
 
933
 
 
934
  // Make the size a power of two, as required by OpenGL (at least for versions < 2.0) for textures.
 
935
  size.width= 1 << int(ceil(log(size.width) / M_LN2));
 
936
  size.height= 1 << int(ceil(log(size.height) / M_LN2));
 
937
 
 
938
  return size;
 
939
}
 
940
 
 
941
//----------------------------------------------------------------------------------------------------------------------
 
942
 
 
943
void CanvasItem::regenerate_cache(Size size)
 
944
{
 
945
  if (!_content_cache 
 
946
      || ((int)size.width != cairo_image_surface_get_width(_content_cache) || (int)size.height != cairo_image_surface_get_height(_content_cache)))
 
947
  {
 
948
    if (_content_cache)
 
949
    {
 
950
      _layer->get_view()->bookkeep_cache_mem(-cairo_image_surface_get_stride(_content_cache) * cairo_image_surface_get_height(_content_cache));
 
951
      cairo_surface_destroy(_content_cache);
 
952
    }
 
953
 
 
954
    _content_cache= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (unsigned int) size.width, (unsigned int) size.height);
 
955
 
 
956
    _layer->get_view()->bookkeep_cache_mem(cairo_image_surface_get_stride(_content_cache) * cairo_image_surface_get_height(_content_cache));
 
957
 
 
958
#ifndef WIN32
 
959
    if (_layer->get_view()->debug_enabled())
 
960
      g_message("creating cached image for %p (%i)", this,
 
961
                cairo_image_surface_get_stride(_content_cache) * cairo_image_surface_get_height(_content_cache));
 
962
#endif
 
963
  }
 
964
  memset(cairo_image_surface_get_data(_content_cache), 0,
 
965
         cairo_image_surface_get_stride(_content_cache) * cairo_image_surface_get_height(_content_cache));
 
966
 
 
967
  render_to_surface(_content_cache);
 
968
  _needs_render= false;
 
969
}
 
970
 
 
971
 
 
972
void CanvasItem::repaint_cached()
 
973
{
 
974
  // during zooming, the cache must be rendered with scaling enabled,
 
975
  // but the blitting of the rendered image must be done with no zooming
 
976
 
 
977
  if ((_needs_render || !_content_cache) && _cache_toplevel_content)
 
978
  {
 
979
    Size size= get_texture_size(Size(0, 0));
 
980
    regenerate_cache(size);
 
981
  }
 
982
 
 
983
  _needs_render= false;
 
984
 
 
985
  if (_content_cache)
 
986
  {
 
987
#ifndef WIN32
 
988
    if (_layer->get_view()->debug_enabled())
 
989
      g_message("paint cache data for %p", this);
 
990
#endif
 
991
    // paint the image to the canvas
 
992
    _layer->get_view()->paint_item_cache(_layer->get_view()->cairoctx(),
 
993
            _pos.x - LEFT_OUTER_PAD, _pos.y - TOP_OUTER_PAD,
 
994
            _content_cache);
 
995
  }
 
996
  else
 
997
  {
 
998
    // render directly into canvas
 
999
    CairoCtx *ccr= _layer->get_view()->cairoctx();
 
1000
 
 
1001
    ccr->save();
 
1002
    render(ccr);
 
1003
    ccr->restore();
 
1004
  }
 
1005
}
 
1006
 
 
1007
 
 
1008
CanvasItem *CanvasItem::get_common_ancestor(CanvasItem *item) const
 
1009
{
 
1010
  const CanvasItem *my_ancestor, *other_ancestor;
 
1011
  
 
1012
  for (my_ancestor= this; my_ancestor != NULL; 
 
1013
       my_ancestor= my_ancestor->get_parent())
 
1014
  {
 
1015
    for (other_ancestor= item; other_ancestor != NULL;
 
1016
         other_ancestor= other_ancestor->get_parent())
 
1017
    {
 
1018
      if (my_ancestor == other_ancestor)
 
1019
        return (CanvasItem*)my_ancestor;
 
1020
    }
 
1021
  }
 
1022
  return 0;
 
1023
}
 
1024
 
 
1025
 
 
1026
Point CanvasItem::convert_point_from(const Point &pt, CanvasItem *item) const
 
1027
{
 
1028
  CanvasItem *ancestor= 0;
 
1029
  const CanvasItem *it;
 
1030
  Point point= pt;
 
1031
 
 
1032
  if (item)
 
1033
  {
 
1034
    ancestor= get_common_ancestor(item);
 
1035
 
 
1036
    // add offset from item to the common ancestor
 
1037
    for (it= item; it != ancestor; it= it->get_parent())
 
1038
      point= point + it->get_position();
 
1039
  }
 
1040
 
 
1041
  // sub offset from us to the common ancestor
 
1042
  for (it= this; it != ancestor; it= it->get_parent())
 
1043
    point= point - it->get_position();
 
1044
 
 
1045
  return point;
 
1046
}
 
1047
 
 
1048
 
 
1049
Point CanvasItem::convert_point_to(const Point &pt, CanvasItem *item) const
 
1050
{  
 
1051
  CanvasItem *ancestor= item ? get_common_ancestor(item) : 0;
 
1052
  const CanvasItem *it;
 
1053
  Point point= pt;
 
1054
 
 
1055
  // add offset from us to the common ancestor
 
1056
  for (it= this; it != ancestor; it= it->get_parent())
 
1057
    point= point + it->get_position();
 
1058
 
 
1059
  if (item)
 
1060
  {
 
1061
    // sub offset from item to the common ancestor
 
1062
    for (it= item; it != ancestor; it= it->get_parent())
 
1063
      point= point - it->get_position();
 
1064
  }
 
1065
  return point;
 
1066
}
 
1067
 
 
1068
 
 
1069
 
 
1070
Point CanvasItem::get_intersection_with_line_to(const Point &p)
 
1071
{
 
1072
  Rect bounds(get_root_bounds());
 
1073
  Point p1;
 
1074
  Point p2;
 
1075
 
 
1076
  if (intersect_rect_to_line(bounds, bounds.center(), p, p1, p2))
 
1077
  {
 
1078
    return p1;
 
1079
  }
 
1080
 
 
1081
  return p;
 
1082
  //throw std::logic_error("bounds intersection function has failed"); 
 
1083
}
 
1084
 
 
1085
 
 
1086
 
 
1087
//--------------------------------------------------------------------------------
 
1088
 
 
1089
 
 
1090
void CanvasItem::destroy_handles()
 
1091
{
 
1092
  for (std::vector<ItemHandle*>::iterator i= _handles.begin(); i != _handles.end(); ++i)
 
1093
  {
 
1094
    delete *i;
 
1095
  }
 
1096
  _handles.clear();
 
1097
}
 
1098
 
 
1099
 
 
1100
void CanvasItem::create_handles(InteractionLayer *ilayer)
 
1101
{
 
1102
  ItemHandle *hdl;
 
1103
  struct {
 
1104
    int tag;
 
1105
    float x, y;
 
1106
  } pos[]= {
 
1107
  {HDL_TL, 0, 0},
 
1108
  {HDL_T, 0.5, 0},
 
1109
  {HDL_TR, 1, 0},
 
1110
  {HDL_L, 0, 0.5},
 
1111
  {HDL_R, 1, 0.5},
 
1112
  {HDL_BL, 0, 1},
 
1113
  {HDL_B, 0.5, 1},
 
1114
  {HDL_BR, 1, 1}
 
1115
  };
 
1116
  Size size= get_size();
 
1117
 
 
1118
  for (int i= 0; i < 8; i++)
 
1119
  {
 
1120
    Point pt= convert_point_to(Point(ceil(size.width*pos[i].x),
 
1121
                                     ceil(size.height*pos[i].y)), 0);
 
1122
 
 
1123
    hdl= new BoxHandle(ilayer, this, pt);
 
1124
    hdl->set_draggable(_vresizeable || _hresizeable);
 
1125
    hdl->set_tag(pos[i].tag);
 
1126
    ilayer->add_handle(hdl);
 
1127
    _handles.push_back(hdl);
 
1128
  }
 
1129
}
 
1130
 
 
1131
 
 
1132
void CanvasItem::update_handles()
 
1133
{
 
1134
  if (!_handles.empty())
 
1135
  {
 
1136
    Size size= get_size();
 
1137
    struct {
 
1138
      int tag;
 
1139
      float x, y;
 
1140
    } pos[]= {
 
1141
    {HDL_TL, 0, 0},
 
1142
    {HDL_T, 0.5, 0},
 
1143
    {HDL_TR, 1, 0},
 
1144
    {HDL_L, 0, 0.5},
 
1145
    {HDL_R, 1, 0.5},
 
1146
    {HDL_BL, 0, 1},
 
1147
    {HDL_B, 0.5, 1},
 
1148
    {HDL_BR, 1, 1}
 
1149
    };
 
1150
 
 
1151
    for (int i= 0; i < 8; i++)
 
1152
    {
 
1153
      Point pt= convert_point_to(Point(ceil(size.width*pos[i].x),
 
1154
                                       ceil(size.height*pos[i].y)), 0);
 
1155
      _handles[i]->move(pt);
 
1156
    }
 
1157
  }
 
1158
}
 
1159
 
 
1160
 
 
1161
 
 
1162
void CanvasItem::magnetize_bounds()
 
1163
{
 
1164
  add_magnet(new BoundsMagnet(this));
 
1165
}
 
1166
 
 
1167
 
 
1168
void CanvasItem::add_magnet(Magnet *magnet)
 
1169
{
 
1170
  _magnets.push_back(magnet);
 
1171
}
 
1172
 
 
1173
 
 
1174
BoundsMagnet *CanvasItem::get_bounds_magnet()
 
1175
{
 
1176
  for (std::vector<Magnet*>::const_iterator iter= _magnets.begin();
 
1177
       iter != _magnets.end(); ++iter)
 
1178
  {
 
1179
    if (dynamic_cast<BoundsMagnet*>(*iter))
 
1180
      return dynamic_cast<BoundsMagnet*>(*iter);
 
1181
  }
 
1182
  return 0;
 
1183
}
 
1184
 
 
1185
 
 
1186
 
 
1187
mdc::Magnet *CanvasItem::get_closest_magnet(const Point &point)
 
1188
{
 
1189
  Point lpos= convert_point_from(point, 0);
 
1190
  double d, bestd= MAGNET_STICK_DISTANCE;
 
1191
  Magnet *best= 0;
 
1192
  Magnet *bmagnet= 0;
 
1193
 
 
1194
  for (std::vector<Magnet*>::const_iterator iter= _magnets.begin();
 
1195
       iter != _magnets.end(); ++iter)
 
1196
  {
 
1197
    if (dynamic_cast<BoundsMagnet*>(*iter))
 
1198
      bmagnet= *iter;
 
1199
 
 
1200
    d= points_distance(lpos, (*iter)->get_position_for_connector(0, Point()));
 
1201
    if (d < bestd)
 
1202
    {
 
1203
      bestd= d;
 
1204
      best= *iter;
 
1205
    }
 
1206
  }
 
1207
 
 
1208
  if (!best)
 
1209
    return bmagnet;
 
1210
 
 
1211
  return best;
 
1212
}
 
1213
 
 
1214
 
 
1215
void CanvasItem::set_drag_handle_constrainer(const boost::function<void (ItemHandle*,Size&)> &slot)
 
1216
{
 
1217
  _drag_handle_constrainer= slot;
 
1218
}
 
1219
 
 
1220
//------------------------------------------------------------------------------
 
1221
 
 
1222
bool CanvasItem::on_drag_handle(ItemHandle *handle, const Point &pos, bool dragging)
 
1223
{
 
1224
  Rect oframe= get_root_bounds();
 
1225
  Point npos= get_position();
 
1226
  Size nsize= get_size();
 
1227
  Point local_pos= pos - get_parent()->get_root_position();
 
1228
  Size max_size= get_parent()->get_size();
 
1229
  Size min_size= get_min_size();
 
1230
 
 
1231
  if (_hresizeable)
 
1232
  {
 
1233
    if ((handle->get_tag() & HDL_LR_MASK) == HDL_RIGHT)
 
1234
    {
 
1235
      nsize.width= pos.x - oframe.left();
 
1236
      if (min_size.width > 0 && nsize.width < min_size.width)
 
1237
        nsize.width= min_size.width;
 
1238
      else if (nsize.width > max_size.width - npos.x)
 
1239
        nsize.width= max_size.width - npos.x;
 
1240
      else if (nsize.width <= 0)
 
1241
        nsize.width= 1;
 
1242
    }
 
1243
    else if ((handle->get_tag() & HDL_LR_MASK) == HDL_LEFT)
 
1244
    {
 
1245
      npos.x= local_pos.x;
 
1246
      nsize.width= oframe.width() + (oframe.left() - pos.x);
 
1247
      
 
1248
      if (min_size.width > 0 && nsize.width < min_size.width)
 
1249
      {
 
1250
        double dx= min_size.width - nsize.width;
 
1251
        npos.x-= dx;
 
1252
        nsize.width= min_size.width;
 
1253
      }
 
1254
      else if (npos.x < 0)
 
1255
      {
 
1256
        nsize.width+= npos.x;
 
1257
        npos.x= 0;
 
1258
      }
 
1259
    }
 
1260
  }
 
1261
  if (_vresizeable)
 
1262
  {
 
1263
    if ((handle->get_tag() & HDL_TB_MASK) == HDL_BOTTOM)
 
1264
    {
 
1265
      nsize.height= pos.y - oframe.top();
 
1266
      if (min_size.height > 0 && nsize.height < min_size.height)
 
1267
        nsize.height= min_size.height;
 
1268
      else if (nsize.height > max_size.height - npos.y)
 
1269
        nsize.height= max_size.height - npos.y;
 
1270
      else if (nsize.height <= 0)
 
1271
        nsize.height= 1;
 
1272
    }
 
1273
    else if ((handle->get_tag() & HDL_TB_MASK) == HDL_TOP)
 
1274
    {
 
1275
      npos.y= local_pos.y;
 
1276
      nsize.height= oframe.height() + (oframe.top() - pos.y);
 
1277
      if (min_size.height > 0 && nsize.height < min_size.height)
 
1278
      {
 
1279
        double dy= min_size.height - nsize.height;
 
1280
        npos.y-= dy;
 
1281
        nsize.height= min_size.height;
 
1282
      }
 
1283
      else if (npos.y < 0)
 
1284
      {
 
1285
        nsize.height+= npos.y;
 
1286
        npos.y= 0;
 
1287
      }
 
1288
    }
 
1289
  }
 
1290
 
 
1291
  if (_drag_handle_constrainer)
 
1292
    _drag_handle_constrainer(handle, nsize);
 
1293
 
 
1294
 
 
1295
  Point npos2(npos);
 
1296
  npos= get_view()->snap_to_grid(npos).round();
 
1297
 
 
1298
  // adjustment
 
1299
  nsize.width+= npos2.x - npos.x;
 
1300
  nsize.height+= npos2.y - npos.y;
 
1301
 
 
1302
  nsize= get_view()->snap_to_grid(nsize).round();
 
1303
 
 
1304
  if (nsize.width <= 0)
 
1305
    throw;
 
1306
 
 
1307
  if (npos != get_position())
 
1308
    move_to(npos);
 
1309
  if (nsize != get_size())
 
1310
    resize_to(nsize);
 
1311
 
 
1312
  update_handles();
 
1313
 
 
1314
  return true;
 
1315
}
 
1316
 
 
1317
//--------------------------------------------------------------------------------------------------
 
1318
 
 
1319
bool CanvasItem::on_click(CanvasItem *target, const Point &point, MouseButton button, EventState state)
 
1320
{
 
1321
  if (button == ButtonLeft && !_dragged)
 
1322
  {
 
1323
    CanvasView *view= get_layer()->get_view();
 
1324
    
 
1325
    // if we're a toplevel, focus and select ourselves
 
1326
    if (is_toplevel())
 
1327
    {
 
1328
      if (accepts_focus())
 
1329
      {
 
1330
        if (state & SControlMask)
 
1331
        {
 
1332
          // focus is handled by elsewhere now
 
1333
          //if (get_focused() || !get_selected())
 
1334
          //  view->focus_item(0);
 
1335
          //else
 
1336
          //  view->focus_item(this);
 
1337
        }
 
1338
        else
 
1339
        {
 
1340
          if ((state & SModifierMask) == 0)
 
1341
            view->get_selection()->set(this);
 
1342
          //view->focus_item(this);
 
1343
        }
 
1344
      }
 
1345
      return true;
 
1346
    }
 
1347
    else // a child item
 
1348
    {
 
1349
      // if the parent is focused and we're focusable, then focus ourselves
 
1350
      if (accepts_focus())
 
1351
      {
 
1352
        CanvasItem *parent= get_parent();
 
1353
        // get the 1st parent that accepts focus
 
1354
        while (parent && !parent->accepts_focus())
 
1355
          parent= parent->get_parent();
 
1356
        
 
1357
        // conditions met, set focus
 
1358
        if (parent && parent->accepts_focus())
 
1359
          view->focus_item(this);
 
1360
        
 
1361
        return true;
 
1362
      }
 
1363
    }
 
1364
  }
 
1365
  return false;
 
1366
}
 
1367
 
 
1368
//--------------------------------------------------------------------------------------------------
 
1369
 
 
1370
bool CanvasItem::on_double_click(CanvasItem *target, const Point &point, MouseButton button, EventState state)
 
1371
{
 
1372
  return false;
 
1373
}
 
1374
 
 
1375
//--------------------------------------------------------------------------------------------------
 
1376
 
 
1377
bool CanvasItem::on_button_press(CanvasItem *target, const Point &point, MouseButton button, EventState state)
 
1378
{
 
1379
  _button_press_pos= point;
 
1380
  
 
1381
  // if we're a toplevel, prepare for dragging
 
1382
  if (button == ButtonLeft)
 
1383
  {
 
1384
    _dragged= 0;
 
1385
    if (is_toplevel())// && target->_draggable)
 
1386
    {
 
1387
      CanvasView *view= get_layer()->get_view();
 
1388
 
 
1389
      if (accepts_selection())
 
1390
      {
 
1391
        if (state & (SControlMask|SCommandMask))
 
1392
          view->get_selection()->toggle(this);
 
1393
        else if (state & SShiftMask)
 
1394
          view->get_selection()->add(this);
 
1395
        else
 
1396
        {
 
1397
          // select on click or drag
 
1398
          //          if (!get_selected())
 
1399
          //view->get_selection()->set(this);
 
1400
        }
 
1401
      }
 
1402
 
 
1403
      /*
 
1404
      if (!get_selected())
 
1405
      {
 
1406
        if (accepts_focus())
 
1407
          view->focus_item(this);
 
1408
      }*/
 
1409
 
 
1410
// moved to on_drag
 
1411
//      _dragging= true;
 
1412
//      view->get_selection()->begin_moving(convert_point_to(point, 0));
 
1413
      
 
1414
      return true;
 
1415
    }
 
1416
  }
 
1417
  return false;
 
1418
}
 
1419
 
 
1420
 
 
1421
bool CanvasItem::on_button_release(CanvasItem *target, const Point &point, MouseButton button, EventState state)
 
1422
{
 
1423
  if (button == ButtonLeft)
 
1424
  {
 
1425
    if (is_toplevel())// && target->_draggable)
 
1426
    {
 
1427
      CanvasView *view= get_layer()->get_view();
 
1428
 
 
1429
      if (_dragging)
 
1430
        view->get_selection()->end_moving();
 
1431
      _dragging= false;
 
1432
 
 
1433
      return true;
 
1434
    }
 
1435
  }
 
1436
 
 
1437
  return false;
 
1438
}
 
1439
 
 
1440
 
 
1441
bool CanvasItem::on_drag(CanvasItem *target, const Point &point, EventState state)
 
1442
{
 
1443
  _dragged= 1;
 
1444
 
 
1445
  if (is_toplevel() && (state & SLeftButtonMask))
 
1446
  {
 
1447
    CanvasView *view= get_layer()->get_view();
 
1448
 
 
1449
    if (!get_selected())
 
1450
    {
 
1451
      // if not selected, then select the object and start the drag
 
1452
 
 
1453
      view->get_selection()->set(this);
 
1454
    }
 
1455
 
 
1456
    if (!_dragging)
 
1457
    {
 
1458
      _dragging= true;
 
1459
      view->get_selection()->begin_moving(convert_point_to(_button_press_pos, 0));
 
1460
    }
 
1461
    
 
1462
    if (get_selected())
 
1463
    {
 
1464
      if (target->_draggable || target->get_toplevel()->_draggable)
 
1465
        view->get_selection()->update_move(convert_point_to(point, 0));
 
1466
    }
 
1467
    return true;
 
1468
  }
 
1469
  
 
1470
  return false;
 
1471
}
 
1472
 
 
1473
 
 
1474
bool CanvasItem::on_enter(CanvasItem *target, const Point &point)
 
1475
{
 
1476
  // on_enter and on_leave return true (block propagation)
 
1477
  // by default, unlike other events. 
 
1478
  // the parent items will receive their own crossing events
 
1479
  if (!_hovering)
 
1480
  {
 
1481
    _hovering= 1;
 
1482
    if (_draws_hover)
 
1483
      set_needs_render();
 
1484
  }
 
1485
  return true;
 
1486
}
 
1487
 
 
1488
 
 
1489
bool CanvasItem::on_leave(CanvasItem *target, const Point &point)
 
1490
{
 
1491
  // on_enter and on_leave return true (block propagation)
 
1492
  // by default, unlike other events. 
 
1493
  if (_hovering)
 
1494
  {
 
1495
    _hovering= 0;
 
1496
    if (_draws_hover)
 
1497
      set_needs_render();
 
1498
  }
 
1499
  return true;
 
1500
}