1 require 'observer_utils'
3 class Scene < Qt::GraphicsScene
4 MINIMAL_DRAG_DISTANCE = 3
9 self.background_brush = $qApp.palette.brush(Qt::Palette::Window)
13 def add_clickable_element(element)
17 def mousePressEvent(e)
18 if e.button == Qt::LeftButton
19 pos = e.scene_pos.to_i
21 @drag_data = { :pos => pos }
26 def mouseReleaseEvent(e)
27 if e.button == Qt::LeftButton
29 old_pos = @drag_data[:pos]
30 item = @drag_data[:item]
34 pos = e.scene_pos.to_i
35 element_src = find_element(old_pos)
36 element_dst = find_element(pos)
39 # normal drag and drop
42 # if the drop is in a blank area,
43 # notify the source of the drop
44 notify(element_src, :drop, [old_pos, nil], data)
46 src = if element_src == element_dst
49 # if the drag and drop is close and there's no
50 # dragged item, notify a click instead
52 same_square(element_dst, src, pos) and
54 notify(element_dst, :click, [pos])
56 notify(element_dst, :drop, [src, pos], data)
59 elsif element_src == element_dst
60 # close drag and drop == click, unless
61 # old_pos and pos fall on different squares
62 if same_square(element_src, old_pos, pos)
63 notify(element_dst, :click, [pos])
66 # a rapid drag and drop between different elements
67 # is never considered a click
68 notify(element_src, :drag, [old_pos])
69 notify(element_src, :drop, [nil, pos], data)
77 pos = e.scene_pos.to_i
78 if !@drag_data[:dragging]
79 dx = (@drag_data[:pos].x - pos.x).abs
80 dy = (@drag_data[:pos].y - pos.y).abs
81 if dx >= MINIMAL_DRAG_DISTANCE ||
82 dy >= MINIMAL_DRAG_DISTANCE
83 @drag_data[:dragging] = true
84 notify(find_element(pos), :drag, [@drag_data[:pos]])
91 @drag_data[:item].pos = (pos - @drag_data[:size] / 2).to_f
97 @elements.detect do |element|
98 element.rect.contains(pos)
102 def notify(element, event, pos, *args)
104 relpos = pos.map{|p| rel(element, p) }
105 element.send("on_#{event}", *(relpos + args))
109 def rel(element, pos)
111 pos - element.rect.top_left
115 def same_square(element, pos1, pos2)
116 element.to_logical(rel(element, pos1)) ==
117 element.to_logical(rel(element, pos2))
120 # invoked by the controller when one of the elements
124 @drag_data = @drag_data.merge(data)
128 def remove_element(item)
129 @elements.delete(item)