1 require 'observer_utils'
3 class Scene < Qt::GraphicsScene
4 MINIMAL_DRAG_DISTANCE = 3
13 def add_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 notify(element_dst, :drop, [src, pos], data)
51 elsif element_src == element_dst
52 # close drag and drop == click
53 # the element will decide how to handle it based on the distance
54 # between the coordinates
55 notify(element_dst, :click, [old_pos, pos])
57 # a rapid drag and drop between different elements
58 # is never considered a click
59 notify(element_src, :drag, [old_pos])
60 notify(element_src, :drop, [nil, pos], data)
68 pos = e.scene_pos.to_i
69 if !@drag_data[:dragging]
70 dx = (@drag_data[:pos].x - pos.x).abs
71 dy = (@drag_data[:pos].y - pos.y).abs
72 if dx >= MINIMAL_DRAG_DISTANCE ||
73 dy >= MINIMAL_DRAG_DISTANCE
74 @drag_data[:dragging] = true
75 notify(find_element(pos), :drag, [@drag_data[:pos]])
82 @drag_data[:item].pos = (pos - @drag_data[:size] / 2).to_f
88 @elements.detect do |element|
89 element.rect.contains(pos)
93 def notify(element, event, pos, *args)
95 relpos = pos.map{|p| rel(element, p) }
96 element.send("on_#{event}", *(relpos + args))
100 def rel(element, pos)
102 pos - element.rect.top_left
106 # invoked by the controller when one of the elements
110 @drag_data = @drag_data.merge(data)