2
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
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
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.
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
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"
40
#define MAGNET_STICK_DISTANCE 5
43
using namespace MySQL::Geometry;
44
using namespace MySQL::Drawing;
46
int mdc_live_item_count = 0;
48
CanvasItem::CanvasItem(Layer *layer)
49
: _layer(layer), _parent(0)
51
mdc_live_item_count++;
57
_accepts_selection= 0;
66
_cache_toplevel_content= 0;
73
_disable_state_drawing= 0;
85
_fixed_min_size= Size(-1, -1);
86
_fixed_size= Size(-1, -1);
88
_bounds_changed_signal.connect(boost::bind(&CanvasItem::update_handles, this));
90
scoped_connect(layer->get_view()->signal_zoom_changed(),boost::bind(&CanvasItem::invalidate_cache, this));
94
CanvasItem::~CanvasItem()
96
--mdc_live_item_count;
97
delete _highlight_color;
101
//if (!_parent->_destroyed)
103
Layouter *l= dynamic_cast<Layouter*>(_parent);
109
get_layer()->remove_item(this);
113
for (std::vector<Magnet*>::iterator iter= _magnets.begin(); iter != _magnets.end(); ++iter)
117
cairo_surface_destroy(_content_cache);
119
if (_display_list != 0)
120
glDeleteLists(_display_list, 1);
122
if (_content_texture != 0)
123
glDeleteTextures(1, &_content_texture);
127
mdc::CanvasItem *CanvasItem::find_item_with_tag(const std::string &tag)
135
void CanvasItem::set_bounds(const Rect &rect)
137
Rect obounds= get_bounds();
144
// _bounds_changed_signal.emit(obounds);
152
void CanvasItem::set_position(const Point &pos)
156
Rect obounds= get_bounds();
160
_bounds_changed_signal(obounds);
167
void CanvasItem::set_size(const Size &size)
171
Rect obounds= get_bounds();
175
_bounds_changed_signal(obounds);
182
Rect CanvasItem::get_root_bounds() const
184
return Rect(get_root_position(), get_size());
188
Rect CanvasItem::get_padded_root_bounds() const
190
Rect bounds(get_root_bounds());
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;
201
Rect CanvasItem::get_bounds() const
203
return Rect(get_position(), get_size());
207
Point CanvasItem::get_root_position() const
209
return convert_point_to(Point(0,0), 0);
213
bool CanvasItem::intersects(const Rect &bounds) const
215
return bounds_intersect(bounds, get_bounds());
219
bool CanvasItem::contains_point(const Point &point) const
221
return bounds_contain_point(get_bounds(), point.x, point.y);
225
void CanvasItem::set_fixed_min_size(const Size &size)
227
_min_size_invalid= true;
228
_fixed_min_size= size;
232
Size CanvasItem::calc_min_size()
234
return Size(_xpadding*2, _ypadding*2);
238
Size CanvasItem::get_min_size()
240
if (_min_size_invalid)
242
Size size= Size(-1,-1);//_fixed_size;
246
size.width= _fixed_min_size.width;
248
size.height= _fixed_min_size.height;
250
if (size.width >= 0 && size.height >= 0)
254
msize= calc_min_size();
257
size.width= msize.width;
260
size.height= msize.height;
264
_min_size_invalid= false;
271
void CanvasItem::set_padding(double xpad, double ypad)
276
set_needs_relayout();
280
void CanvasItem::resize_to(const Size &size)
290
void CanvasItem::move_to(const Point &pos)
298
// _layer->set_needs_repaint();
302
void CanvasItem::set_fixed_size(const Size &size)
304
Rect obounds(get_bounds());
306
_min_size_invalid= true;
309
_bounds_changed_signal(obounds);
310
set_needs_relayout();
315
void CanvasItem::parent_bounds_changed(const Rect &obounds, CanvasItem *item)
317
_parent_bounds_changed_signal(item, obounds);
323
void CanvasItem::grand_parent_bounds_changed(CanvasItem *item, const Rect &obounds)
325
_parent_bounds_changed_signal(item, obounds);
331
void CanvasItem::set_parent(CanvasItem *parent)
333
if (parent != 0 && _parent != 0 && parent != _parent)
334
throw std::logic_error("setting parent to already parented item");
342
_parent_bounds_con= parent->signal_bounds_changed()->connect(boost::bind(&CanvasItem::parent_bounds_changed, this, _1, parent));
344
_grand_parent_bounds_con= parent->signal_parent_bounds_changed()->connect(boost::bind(&CanvasItem::grand_parent_bounds_changed, this, _1, _2));
349
void CanvasItem::remove_from_parent()
352
dynamic_cast<Layouter*>(_parent)->remove(this);
356
CanvasView *CanvasItem::get_view() const
359
return _layer->get_view();
364
void CanvasItem::set_accepts_focus(bool flag)
366
_accepts_focus= flag;
370
void CanvasItem::set_accepts_selection(bool flag)
372
_accepts_selection= flag;
376
void CanvasItem::set_draws_hover(bool flag)
378
if (_draws_hover != flag)
385
void CanvasItem::set_highlighted(bool flag)
387
if (_highlighted != flag)
395
void CanvasItem::set_highlight_color(const Color *color)
397
if (_highlight_color)
398
delete _highlight_color;
401
_highlight_color= new Color(*color);
410
void CanvasItem::set_selected(bool flag)
412
if (_selected != flag)
416
get_layer()->get_view()->focus_item(0);
423
void CanvasItem::set_focused(bool flag)
425
if (_focused != flag)
430
_focus_changed_signal(flag);
435
void CanvasItem::set_allowed_resizing(bool horizontal, bool vertical)
437
_hresizeable= horizontal;
438
_vresizeable= vertical;
442
void CanvasItem::set_draggable(bool flag)
448
void CanvasItem::set_auto_sizing(bool flag)
451
_min_size_invalid= true;
452
set_needs_relayout();
455
//------------------------------------------------------------------------------
457
void CanvasItem::set_cache_toplevel_contents(bool flag)
459
_cache_toplevel_content= flag;
463
void CanvasItem::invalidate_cache()
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);
475
void CanvasItem::set_has_shadow(bool flag)
477
if (_has_shadow != flag)
485
void CanvasItem::set_visible(bool flag)
487
if (_visible != flag)
490
set_needs_relayout();
495
bool CanvasItem::get_parents_visible() const
497
CanvasItem *item= get_parent();
499
while (item && !item->is_toplevel())
501
if (!item->get_visible())
503
item= item->get_parent();
509
void CanvasItem::set_needs_repaint()
511
Rect bounds(get_root_bounds());
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;
518
if (bounds.pos.x < 0) bounds.pos.x= 0;
519
if (bounds.pos.y < 0) bounds.pos.y= 0;
521
if (_old_bounds != bounds)
523
if (_old_bounds.width() > 0 && _old_bounds.height() > 0)
524
_layer->queue_repaint(_old_bounds);
527
_layer->queue_repaint(_old_bounds);
531
void CanvasItem::set_needs_render()
536
if (_parent && !is_toplevel())
537
_parent->set_needs_render();
541
_layer->set_needs_repaint();//get_bounds();
546
if (_parent && !is_toplevel())
547
_parent->set_needs_render();
548
else if (!_needs_render)
557
void CanvasItem::set_needs_relayout()
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();
567
CanvasItem *toplevel= get_toplevel();
569
_layer->queue_relayout(toplevel);
575
void CanvasItem::auto_size()
577
Size size= _fixed_size;
578
Size minsize= get_min_size();
580
minsize.width+= _xpadding*2;
581
minsize.height+= _ypadding*2;
584
size.width= minsize.width;
586
size.height= minsize.height;
592
void CanvasItem::relayout()
594
// called by layer only
599
Size size= get_fixed_size();
602
size.width= _size.width;
604
size.height= _size.height;
611
bool CanvasItem::is_toplevel() const
613
if (dynamic_cast<Group*>(_parent))
619
CanvasItem *CanvasItem::get_toplevel() const
624
return (CanvasItem*)this;
625
return _parent->get_toplevel();
631
CanvasItem::State CanvasItem::get_state()
635
else if (_hovering && _draws_hover)
637
else if (_highlighted)
645
void CanvasItem::set_state_drawing(bool flag)
647
_disable_state_drawing= !flag;
650
//--------------------------------------------------------------------------------------------------
652
void CanvasItem::draw_state(CairoCtx *cr)
654
if (!get_view()->is_printout() && !_disable_state_drawing)
662
draw_outline_ring(cr, get_view()->get_hover_color());
666
draw_outline_ring(cr, _highlight_color ? *_highlight_color : get_view()->get_highlight_color());
670
draw_outline_ring(cr, get_view()->get_selection_color());
679
//--------------------------------------------------------------------------------------------------
681
void CanvasItem::draw_state_gl()
683
if (!get_view()->is_printout() && !_disable_state_drawing)
691
draw_outline_ring_gl(get_view()->get_hover_color());
695
draw_outline_ring_gl(_highlight_color ? *_highlight_color : get_view()->get_highlight_color());
699
draw_outline_ring_gl(get_view()->get_selection_color());
708
//--------------------------------------------------------------------------------------------------
710
void CanvasItem::draw_outline_ring(CairoCtx *cr, const Color &color)
714
cr->set_color(color, color.alpha);
715
cr->set_line_width(2);
716
stroke_outline(cr, 1);
719
cr->set_color(color, color.alpha * 0.3);
720
cr->set_line_width(4);
721
stroke_outline(cr, 2);
727
//--------------------------------------------------------------------------------------------------
729
void CanvasItem::draw_outline_ring_gl(const Color &color)
733
stroke_outline_gl(1);
735
Color blended= Color(color.red, color.green, color.blue, 0.3 * color.alpha);
736
gl_setcolor(blended);
738
stroke_outline_gl(1);
742
//--------------------------------------------------------------------------------------------------
744
void CanvasItem::render(CairoCtx *cr)
749
void CanvasItem::render_gl(CairoCtx *cr)
754
void CanvasItem::render_to_surface(cairo_surface_t *surf, bool use_padding)
758
cr.scale(_layer->get_view()->get_zoom(), _layer->get_view()->get_zoom());
760
cr.translate(floor(LEFT_OUTER_PAD - _pos.x), floor(TOP_OUTER_PAD - _pos.y));
762
cr.translate(floor(-_pos.x), floor(-_pos.y));
769
void CanvasItem::repaint_gl(const Rect &clipArea)
771
CairoCtx *ccr= _layer->get_view()->cairoctx();
773
// 1st check if we can directly render as gl
780
// if direct gl render wasn't available, then use the cache as a texture and render
782
bool generate_display_list= _display_list == 0;
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)
788
generate_display_list= true;
790
// _content_cache is the bitmap with image data, we load that as a texture and release it.
791
regenerate_cache(texture_size);
796
g_warning("failed to paint canvas item into a memory buffer");
801
if (_content_texture == 0)
802
glGenTextures(1, &_content_texture);
805
glBindTexture(GL_TEXTURE_2D, _content_texture);
807
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
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);
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));
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);
827
glMatrixMode(GL_MODELVIEW);
830
Rect bounds(get_bounds());
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;
837
glTranslated(bounds.left(), bounds.top(), 0);
839
if (generate_display_list)
841
if (_display_list == 0)
842
_display_list= glGenLists(1);
845
glNewList(_display_list, GL_COMPILE);
847
glEnable(GL_TEXTURE_2D);
849
// Render the texture.
850
glBindTexture(GL_TEXTURE_2D, _content_texture);
851
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
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;
865
glTexCoord2d(max_x_coordinate, 0);
866
glVertex2d(bounds.width(), 0);
868
glTexCoord2d(max_x_coordinate, max_y_coordinate);
869
glVertex2d(bounds.width(), bounds.height());
871
glTexCoord2d(0, max_y_coordinate);
872
glVertex2d(0, bounds.height());
875
glDisable(GL_TEXTURE_2D);
880
glCallList(_display_list);
886
void CanvasItem::repaint(const Rect &clipArea, bool direct)
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);
902
void CanvasItem::repaint_direct()
904
CairoCtx *ccr= _layer->get_view()->cairoctx();
913
//----------------------------------------------------------------------------------------------------------------------
916
* Returns the size we need to use for allocating the cache and the final texture. Depends on padding, zoom
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.
922
Size CanvasItem::get_texture_size(Size size)
924
if (size.width == 0 || size.height == 0)
928
size.width += LEFT_OUTER_PAD + RIGHT_OUTER_PAD;
929
size.height += TOP_OUTER_PAD + BOTTOM_OUTER_PAD;
932
cairo_user_to_device_distance(_layer->get_view()->cairoctx()->get_cr(), &size.width, &size.height);
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));
941
//----------------------------------------------------------------------------------------------------------------------
943
void CanvasItem::regenerate_cache(Size size)
946
|| ((int)size.width != cairo_image_surface_get_width(_content_cache) || (int)size.height != cairo_image_surface_get_height(_content_cache)))
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);
954
_content_cache= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (unsigned int) size.width, (unsigned int) size.height);
956
_layer->get_view()->bookkeep_cache_mem(cairo_image_surface_get_stride(_content_cache) * cairo_image_surface_get_height(_content_cache));
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));
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));
967
render_to_surface(_content_cache);
968
_needs_render= false;
972
void CanvasItem::repaint_cached()
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
977
if ((_needs_render || !_content_cache) && _cache_toplevel_content)
979
Size size= get_texture_size(Size(0, 0));
980
regenerate_cache(size);
983
_needs_render= false;
988
if (_layer->get_view()->debug_enabled())
989
g_message("paint cache data for %p", this);
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,
998
// render directly into canvas
999
CairoCtx *ccr= _layer->get_view()->cairoctx();
1008
CanvasItem *CanvasItem::get_common_ancestor(CanvasItem *item) const
1010
const CanvasItem *my_ancestor, *other_ancestor;
1012
for (my_ancestor= this; my_ancestor != NULL;
1013
my_ancestor= my_ancestor->get_parent())
1015
for (other_ancestor= item; other_ancestor != NULL;
1016
other_ancestor= other_ancestor->get_parent())
1018
if (my_ancestor == other_ancestor)
1019
return (CanvasItem*)my_ancestor;
1026
Point CanvasItem::convert_point_from(const Point &pt, CanvasItem *item) const
1028
CanvasItem *ancestor= 0;
1029
const CanvasItem *it;
1034
ancestor= get_common_ancestor(item);
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();
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();
1049
Point CanvasItem::convert_point_to(const Point &pt, CanvasItem *item) const
1051
CanvasItem *ancestor= item ? get_common_ancestor(item) : 0;
1052
const CanvasItem *it;
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();
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();
1070
Point CanvasItem::get_intersection_with_line_to(const Point &p)
1072
Rect bounds(get_root_bounds());
1076
if (intersect_rect_to_line(bounds, bounds.center(), p, p1, p2))
1082
//throw std::logic_error("bounds intersection function has failed");
1087
//--------------------------------------------------------------------------------
1090
void CanvasItem::destroy_handles()
1092
for (std::vector<ItemHandle*>::iterator i= _handles.begin(); i != _handles.end(); ++i)
1100
void CanvasItem::create_handles(InteractionLayer *ilayer)
1116
Size size= get_size();
1118
for (int i= 0; i < 8; i++)
1120
Point pt= convert_point_to(Point(ceil(size.width*pos[i].x),
1121
ceil(size.height*pos[i].y)), 0);
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);
1132
void CanvasItem::update_handles()
1134
if (!_handles.empty())
1136
Size size= get_size();
1151
for (int i= 0; i < 8; i++)
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);
1162
void CanvasItem::magnetize_bounds()
1164
add_magnet(new BoundsMagnet(this));
1168
void CanvasItem::add_magnet(Magnet *magnet)
1170
_magnets.push_back(magnet);
1174
BoundsMagnet *CanvasItem::get_bounds_magnet()
1176
for (std::vector<Magnet*>::const_iterator iter= _magnets.begin();
1177
iter != _magnets.end(); ++iter)
1179
if (dynamic_cast<BoundsMagnet*>(*iter))
1180
return dynamic_cast<BoundsMagnet*>(*iter);
1187
mdc::Magnet *CanvasItem::get_closest_magnet(const Point &point)
1189
Point lpos= convert_point_from(point, 0);
1190
double d, bestd= MAGNET_STICK_DISTANCE;
1194
for (std::vector<Magnet*>::const_iterator iter= _magnets.begin();
1195
iter != _magnets.end(); ++iter)
1197
if (dynamic_cast<BoundsMagnet*>(*iter))
1200
d= points_distance(lpos, (*iter)->get_position_for_connector(0, Point()));
1215
void CanvasItem::set_drag_handle_constrainer(const boost::function<void (ItemHandle*,Size&)> &slot)
1217
_drag_handle_constrainer= slot;
1220
//------------------------------------------------------------------------------
1222
bool CanvasItem::on_drag_handle(ItemHandle *handle, const Point &pos, bool dragging)
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();
1233
if ((handle->get_tag() & HDL_LR_MASK) == HDL_RIGHT)
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)
1243
else if ((handle->get_tag() & HDL_LR_MASK) == HDL_LEFT)
1245
npos.x= local_pos.x;
1246
nsize.width= oframe.width() + (oframe.left() - pos.x);
1248
if (min_size.width > 0 && nsize.width < min_size.width)
1250
double dx= min_size.width - nsize.width;
1252
nsize.width= min_size.width;
1254
else if (npos.x < 0)
1256
nsize.width+= npos.x;
1263
if ((handle->get_tag() & HDL_TB_MASK) == HDL_BOTTOM)
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)
1273
else if ((handle->get_tag() & HDL_TB_MASK) == HDL_TOP)
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)
1279
double dy= min_size.height - nsize.height;
1281
nsize.height= min_size.height;
1283
else if (npos.y < 0)
1285
nsize.height+= npos.y;
1291
if (_drag_handle_constrainer)
1292
_drag_handle_constrainer(handle, nsize);
1296
npos= get_view()->snap_to_grid(npos).round();
1299
nsize.width+= npos2.x - npos.x;
1300
nsize.height+= npos2.y - npos.y;
1302
nsize= get_view()->snap_to_grid(nsize).round();
1304
if (nsize.width <= 0)
1307
if (npos != get_position())
1309
if (nsize != get_size())
1317
//--------------------------------------------------------------------------------------------------
1319
bool CanvasItem::on_click(CanvasItem *target, const Point &point, MouseButton button, EventState state)
1321
if (button == ButtonLeft && !_dragged)
1323
CanvasView *view= get_layer()->get_view();
1325
// if we're a toplevel, focus and select ourselves
1328
if (accepts_focus())
1330
if (state & SControlMask)
1332
// focus is handled by elsewhere now
1333
//if (get_focused() || !get_selected())
1334
// view->focus_item(0);
1336
// view->focus_item(this);
1340
if ((state & SModifierMask) == 0)
1341
view->get_selection()->set(this);
1342
//view->focus_item(this);
1347
else // a child item
1349
// if the parent is focused and we're focusable, then focus ourselves
1350
if (accepts_focus())
1352
CanvasItem *parent= get_parent();
1353
// get the 1st parent that accepts focus
1354
while (parent && !parent->accepts_focus())
1355
parent= parent->get_parent();
1357
// conditions met, set focus
1358
if (parent && parent->accepts_focus())
1359
view->focus_item(this);
1368
//--------------------------------------------------------------------------------------------------
1370
bool CanvasItem::on_double_click(CanvasItem *target, const Point &point, MouseButton button, EventState state)
1375
//--------------------------------------------------------------------------------------------------
1377
bool CanvasItem::on_button_press(CanvasItem *target, const Point &point, MouseButton button, EventState state)
1379
_button_press_pos= point;
1381
// if we're a toplevel, prepare for dragging
1382
if (button == ButtonLeft)
1385
if (is_toplevel())// && target->_draggable)
1387
CanvasView *view= get_layer()->get_view();
1389
if (accepts_selection())
1391
if (state & (SControlMask|SCommandMask))
1392
view->get_selection()->toggle(this);
1393
else if (state & SShiftMask)
1394
view->get_selection()->add(this);
1397
// select on click or drag
1398
// if (!get_selected())
1399
//view->get_selection()->set(this);
1404
if (!get_selected())
1406
if (accepts_focus())
1407
view->focus_item(this);
1412
// view->get_selection()->begin_moving(convert_point_to(point, 0));
1421
bool CanvasItem::on_button_release(CanvasItem *target, const Point &point, MouseButton button, EventState state)
1423
if (button == ButtonLeft)
1425
if (is_toplevel())// && target->_draggable)
1427
CanvasView *view= get_layer()->get_view();
1430
view->get_selection()->end_moving();
1441
bool CanvasItem::on_drag(CanvasItem *target, const Point &point, EventState state)
1445
if (is_toplevel() && (state & SLeftButtonMask))
1447
CanvasView *view= get_layer()->get_view();
1449
if (!get_selected())
1451
// if not selected, then select the object and start the drag
1453
view->get_selection()->set(this);
1459
view->get_selection()->begin_moving(convert_point_to(_button_press_pos, 0));
1464
if (target->_draggable || target->get_toplevel()->_draggable)
1465
view->get_selection()->update_move(convert_point_to(point, 0));
1474
bool CanvasItem::on_enter(CanvasItem *target, const Point &point)
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
1489
bool CanvasItem::on_leave(CanvasItem *target, const Point &point)
1491
// on_enter and on_leave return true (block propagation)
1492
// by default, unlike other events.