Implemented drag and drop.
[kaya.git] / lib / board / board.rb
blobf9cecabd1b0fd98b98be7c751431411c2338922e
1 require 'board/square_tag.rb'
2 require 'observer'
3 require 'board/point_converter.rb'
4 require 'item'
5 require 'board/item_bag'
7 class Board < Qt::GraphicsItemGroup
8   include TaggableSquares
9   include Observable
10   include PointConverter
11   include ItemBag
12   include ItemUtils
14   attr_reader :scene, :items, :unit, :rect, :theme
15   attr_accessor :movable
16   square_tag :selection
17   square_tag :last_move_src, :highlight
18   square_tag :last_move_dst, :highlight
20   def initialize(scene, theme, game)
21     super(nil, scene)
22     @scene = scene
23     @scene.add_element(self)
24     @theme = theme
25     @items = {}
26     
27     @game = game
28     
29     @flipped = false
30     @movable = lambda { true }
31   end
32   
33   def flipped?
34     @flipped
35   end
36   
37   def flip!(value = nil)
38     old = @flipped
39     if value.nil?
40       @flipped = !@flipped
41     else
42       @flipped = value
43     end
44     redraw if old != @flipped
45   end
46   
47   def redraw(names = nil)
48     unless names
49       names = @items.inject({}) do |res, data|
50         p, item = data
51         res[p] = item.name if item
52         res
53       end
54     end
55     
56     @items.each {|item| remove_item(item) }
58     names.each do |key, name|
59       reload_item(key, name)
60     end
61   end
62   
63   def reset(board)
64     pieces = board.to_enum(:each_square).inject({}) do |res, p|
65       res[p] = board[p] if board[p]
66       res
67     end
68     pieces[:background] = nil
69     
70     if @unit
71       redraw pieces
72     else
73       @pieces_to_draw = pieces
74     end
75   end
76   
77   def reload_item(key, name)
78     case key
79     when Point # piece
80       add_item key,
81                @theme.pieces.pixmap(name, @unit),
82                :pos => to_real(key),
83                :name => name
84     when :background # background
85       add_item key,
86                @theme.board.pixmap(@unit),
87                :z => BACKGROUND_ZVALUE
88     when Symbol # tag
89       # force redraw by setting tag again
90       set_tag(key, tag(key))
91     end
92   end
93   
94   def set_geometry(rect)
95     @rect = rect
96     side = [@rect.width / @game.size.x, @rect.height / @game.size.y].min.floor
97     @unit = Qt::Point.new(side, side)
98     base = Qt::Point.new(((@rect.width - side * @game.size.x) / 2.0).to_i,
99                         ((@rect.height - side * @game.size.y) / 2.0).to_i)
101     self.pos = (base + @rect.top_left).to_f
103     redraw @pieces_to_draw
104     @pieces_to_draw = nil
105   end
106   
107   def add_piece(p, piece, opts = {})
108     opts = opts.merge :pos => to_real(p),
109                       :name => piece
110     add_item p, @theme.pieces.pixmap(piece, @unit), opts
111   end
112   
113   def create_piece(piece, opts = {})
114     opts = opts.merge :name => piece
115     create_item p, @theme.pieces.pixmap(piece, @unit), opts
116   end
117   
118   def on_click(pos, press_pos)
119     p = to_logical(pos)
120     p2 = to_logical(press_pos)
121     
122     if p == p2
123       fire :click => p
124     end
125   end
126   
127   def on_drag(pos)
128     p = to_logical(pos)
129     item = items[p]
130     if item
131       fire :drag => { :src => p, 
132                       :item => item,
133                       :size => @unit }
134     end
135   end
136   
137   def on_drop(old_pos, pos, data)
138     if data[:item]
139       src = if old_pos
140         to_logical(old_pos)
141       end
142       dst = if pos
143         to_logical(pos)
144       end
145       fire :drop => data.merge(:src => src, :dst => dst)
146     end
147   end
148   
149   def highlight(move)
150     if move
151       self.last_move_src = move.src
152       self.last_move_dst = move.dst
153     else
154       self.last_move_src = nil
155       self.last_move_dst = nil
156     end
157   end