view src/net/kryshen/charamega/field.mirah @ 2:1e64a109812f

Field has preferred size.
author Mikhail Kryshen <mikhail@kryshen.net>
date Sat, 14 Jul 2012 06:53:41 +0400
parents 91ecd24948de
children 2efb0973ab83
line source
1 #
2 # Copyright 2012 Mikhail Kryshen <mikhail@kryshen.net>
3 #
4 # This file is part of Charamega.
5 #
6 # Charamega is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # Charamega is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with Charamega. If not, see <http://www.gnu.org/licenses/>.
18 #
20 package net.kryshen.charamega
22 import java.awt.*
23 import java.awt.geom.*
24 import java.awt.event.*
25 import javax.swing.*
26 import java.util.List
28 class Field < JComponent
30 def initialize(game:Game)
31 @field_color = Color.WHITE
32 @border_color = Color.GRAY
33 @active_border_color = Color.DARK_GRAY
34 @symbol_color = Color.BLACK
35 @back_color = Color.LIGHT_GRAY
36 @face_color = Color.new(0xFFFDDD)
38 @game = game
40 setOpaque true
41 setDoubleBuffered true
42 setPreferredSize Dimension.new(790, 500)
44 begin
45 source = getClass.getResource("DejaVuSans.ttf").openStream
46 font = Font.createFont(Font.TRUETYPE_FONT, source)
47 ensure
48 source.close unless source.nil?
49 end
50 setFont font
52 enableEvents AWTEvent.MOUSE_EVENT_MASK
53 enableEvents AWTEvent.MOUSE_MOTION_EVENT_MASK
54 end
56 def processMouseEvent(event)
57 if isEnabled
58 if event.getID == MouseEvent.MOUSE_PRESSED
60 @hold = hit(event.getX, event.getY)
62 elsif event.getID == MouseEvent.MOUSE_RELEASED and
63 !@hold.nil? and @hold == hit(event.getX, event.getY)
65 @game.open @hold
66 repaint
67 elsif event.getID == MouseEvent.MOUSE_EXITED and
68 !@hovered.nil?
70 @hovered = nil
71 repaint
72 end
73 end
75 super
76 end
78 def processMouseMotionEvent(event)
79 if isEnabled
80 h = hit(event.getX, event.getY)
82 if event.getID == MouseEvent.MOUSE_DRAGGED
83 if h == @hold and h != @hovered
84 @hovered = h
85 repaint
86 end
88 if h != @hold and @hold == @hovered
89 @hovered = nil
90 repaint
91 end
93 elsif h != @hovered
94 @hovered = h
95 repaint
96 end
97 end
99 super
100 end
102 def paintComponent(g1)
103 g = Graphics2D(g1)
105 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
106 RenderingHints.VALUE_ANTIALIAS_ON)
107 g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
108 RenderingHints.VALUE_FRACTIONALMETRICS_ON)
110 w = getWidth
111 h = getHeight
113 g.setColor @field_color
114 g.fillRect 0, 0, w, h
116 insets = getInsets
117 w -= insets.left + insets.right
118 h -= insets.top + insets.bottom
120 layout = @game.layout(w, h)
121 time = System.nanoTime
123 max_cols = Math.ceil(double(@game.cards.size) / layout.size)
124 rh = double(h) / layout.size
125 card_size = Math.min(rh, double(w) / max_cols) / 1.4
126 font_size = card_size
127 font = g.getFont.deriveFont(float(font_size))
128 frc = g.getFontRenderContext
130 rm_scale = 2.0
132 outer = Rectangle2D.Double.new
133 inner = Rectangle2D.Double.new
134 border = Path2D.Double.new(Path2D.WIND_EVEN_ODD)
136 save_t = g.getTransform
138 y = rh / 2 + insets.top
139 layout.each do |row|
140 cw = double(w) / List(row).size
141 x = cw / 2 + insets.left
143 List(row).each do |e|
144 card = Card(e)
146 v = card.visible_state(time)
148 # Compute area potentially affected by the card.
149 if v < 1.0
150 paint_x = int(Math.floor(x - cw * rm_scale / 2 - 1))
151 paint_y = int(Math.floor(y - rh * rm_scale / 2 - 1))
152 paint_w = int(Math.ceil(cw * rm_scale + 2))
153 paint_h = int(Math.ceil(rh * rm_scale + 2))
154 else
155 paint_x = int(Math.floor(x - cw / 2 - 1))
156 paint_y = int(Math.floor(y - rh / 2 - 1))
157 paint_w = int(Math.ceil(cw + 2))
158 paint_h = int(Math.ceil(rh + 2))
159 end
161 if v > 0.0 and g.hitClip(paint_x, paint_y, paint_w, paint_h)
162 f = card.flip_state(time)
164 if v < 1.0 or (f > -1.0 and f < 1.0)
165 # Animation is in progress.
166 repaint 30, paint_x, paint_y, paint_w, paint_h
167 end
169 g.translate x, y
171 v_scale = rm_scale - Math.sqrt(v) * rm_scale
172 g.scale Math.abs(f) + v_scale, 1.0 + v_scale
174 g.rotate card.angle * v
176 outer.setRect(-card_size / 2, -card_size / 2,
177 card_size, card_size)
178 inner.setRect(1 - card_size / 2, 1 - card_size / 2,
179 card_size - 2, card_size - 2)
180 border.reset
181 border.append outer, false
182 border.append inner, false
184 if f > 0
185 g.setColor with_alpha(@face_color, v)
186 else
187 g.setColor with_alpha(@back_color, v)
188 end
190 g.fill inner
192 if f > 0
193 g.setColor with_alpha(@symbol_color, Math.sqrt(v))
195 gv = font.createGlyphVector(frc, String.valueOf(card.symbol))
196 sb = gv.getVisualBounds
198 # Scale down if the glyph does not fit.
199 tolerance = 0.95
200 scale = Math.min(inner.getWidth * tolerance / sb.getWidth,
201 inner.getHeight * tolerance / sb.getHeight)
202 save_t_2 = g.getTransform
203 g.scale scale, scale if scale < 1.0
205 g.drawGlyphVector(gv,
206 -float(sb.getX + sb.getWidth / 2),
207 -float(sb.getY + sb.getHeight / 2))
209 g.setTransform save_t_2
210 end
212 if card == @hovered
213 g.setColor with_alpha(@active_border_color, v)
214 else
215 g.setColor with_alpha(@border_color, v)
216 end
218 g.fill border
220 g.setTransform save_t
221 end
223 x += cw
224 end
226 y += rh
227 end
228 end
230 private
232 def hit(x:int, y:int)
233 insets = getInsets
234 size = getSize
235 @game.hit(x - insets.left,
236 y - insets.top,
237 size.width - insets.left - insets.right,
238 size.height - insets.top - insets.bottom)
239 end
241 def with_alpha(c:Color, alpha:double)
242 Color.new c.getRed, c.getGreen, c.getBlue, int(alpha * 255)
243 end
244 end