Jypeli  5
The simple game programming library
PushButton.cs
Siirry tämän tiedoston dokumentaatioon.
1 #region MIT License
2 /*
3  * Copyright (c) 2009-2011 University of Jyväskylä, Department of Mathematical
4  * Information Technology.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #endregion
25 
26 /*
27  * Authors: Tomi Karppinen, Tero Jäntti
28  */
29 
30 using System;
31 using Jypeli.Controls;
32 using Jypeli.WP7;
33 using Microsoft.Xna.Framework;
34 
35 namespace Jypeli.Widgets
36 {
40  public class PushButton : Label
41  {
42  private enum State
43  {
44  Released,
45  Hover,
46  LeftPressed,
47  RightPressed
48  }
49 
50  private ShapeCache leftSideShape;
51  private ShapeCache topSideShape;
52  private ShapeCache RightSideShape;
53  private ShapeCache BottomSideShape;
54 
55  private ShapeCache leftSidePressedShape;
56  private ShapeCache topSidePressedShape;
57  private ShapeCache RightSidePressedShape;
58  private ShapeCache BottomSidePressedShape;
59 
60  private Image imageReleased;
61  private Image imagePressed;
62  private Image imageHover;
63 
64  private State state = State.Released;
65 
66  private bool isPressed { get { return state == State.LeftPressed || state == State.RightPressed; } }
67 
68  private Color releasedColor;
69  private Color hoverColor;
70  private Color pressedColor;
71 
75  public Image ImageReleased
76  {
77  get { return imageReleased; }
78  set
79  {
80  imageReleased = value;
81  if ( ! isPressed && !Game.Controls.Mouse.IsCursorOn(this) )
82  Image = value;
83  }
84  }
85 
89  public Image ImagePressed
90  {
91  get { return imagePressed; }
92  set
93  {
94  imagePressed = value;
95  if ( isPressed )
96  Image = value;
97  }
98  }
99 
103  public Image ImageHover
104  {
105  get { return imageHover; }
106  set
107  {
108  imageHover = value;
109  if ( !isPressed && Game.Controls.Mouse.IsCursorOn( this ) )
110  Image = value;
111  }
112  }
113 
114  public override Vector Size
115  {
116  get
117  {
118  return base.Size;
119  }
120  set
121  {
122  base.Size = value;
123  InitializeShape();
124  }
125  }
126 
127  public override Color Color
128  {
129  get
130  {
131  return base.Color;
132  }
133  set
134  {
135  releasedColor = value;
136  hoverColor = Color.Lighter( value, 20 );
137  pressedColor = Color.Darker( value, 20 );
138  base.Color = value;
139  }
140  }
141 
145  public event Action Clicked;
146 
150  public event Action Pressed;
151 
155  public event Action Released;
156 
160  public event Action Down;
161 
165  public event Action RightClicked;
166 
167 
168 #if WINDOWS_PHONE
169  State firstState = State.Released;
170 
171  void TouchPress( Touch touch )
172  {
173  if ( Pressed != null && (state == State.Hover || state == State.Released) )
174  Pressed();
175 
176  firstState = State.LeftPressed;
177  SetState( State.LeftPressed );
178  }
179 
180  void TouchHover( Touch touch )
181  {
182  double touchX = touch.PositionOnScreen.X;
183  double touchY = touch.PositionOnScreen.Y;
184 
185  if ( touchX >= Left && touchX <= Right && touchY >= Bottom && touchY <= Top )
186  {
187  if ( firstState == State.Released )
188  firstState = State.Hover;
189 
190  if ( state != firstState )
191  SetState( firstState );
192  }
193  else if ( Game.TouchPanel.NumTouches == 1 )
194  {
195  SetState( State.Released );
196  }
197  }
198 
199  void TouchRelease( Touch touch )
200  {
201  if ( Game.TouchPanel.NumTouches > 1 || firstState == State.Released )
202  return;
203 
204  firstState = State.Released;
205  SetState( State.Released );
206 
207  if ( Released != null )
208  Released();
209  }
210 
211  void TouchClick( Touch touch )
212  {
213  Click();
214  }
215 #endif
216 
217  public PushButton( string text )
218  : base(text)
219  {
220  Initialize();
221  }
222 
223  public PushButton( Image image )
224  : base( image )
225  {
226  Initialize();
227  this.Image = image;
228  }
229 
235  public PushButton( double width, double height )
236  : base( width, height )
237  {
238  Initialize();
239  }
240 
241  private void Initialize()
242  {
243  InitializeMargins();
244  InitializeShape();
245  Color = new Color( 70, 130, 180, 230 );
246  TextColor = new Color( 250, 250, 250, 240 );
247  AddedToGame += InitializeControls;
248  }
249 
250  private void InitializeMargins()
251  {
252  XMargin = 15;
253  YMargin = 10;
254  }
255 
262  public PushButton( double width, double height, Image image )
263  : this( width, height )
264  {
265  this.Image = image;
266  }
267 
274  public PushButton( double width, double height, string text )
275  : base( width, height, text )
276  {
277  Initialize();
278  }
279 
280  private void InitializeControls()
281  {
282  Game.Controls.Mouse.ListenOn( this, MouseButton.Left, ButtonState.Pressed, Press, null, MouseButton.Left ).InContext( this );
283  Game.Controls.Mouse.Listen( MouseButton.Left, ButtonState.Released, Release, null ).InContext( this );
284 
285  Game.Controls.Mouse.ListenOn( this, MouseButton.Right, ButtonState.Pressed, Press, null, MouseButton.Right ).InContext( this );
286  Game.Controls.Mouse.Listen( MouseButton.Right, ButtonState.Released, Release, null ).InContext( this );
287 
288  // workaround for ButtonState.Release not always working inside a window
289  Game.Controls.Mouse.ListenOn( this, MouseButton.Left, ButtonState.Released, Release, null ).InContext( this );
290 
291  Game.Controls.Mouse.ListenMovement( 1.0, CheckHover, null ).InContext( this );
292 
293 #if WINDOWS_PHONE
294  Game.Instance.TouchPanel.ListenOn( this, ButtonState.Pressed, TouchPress, null ).InContext( this );
295  Game.Instance.TouchPanel.Listen( ButtonState.Down, TouchHover, null ).InContext( this );
296  Game.Instance.TouchPanel.ListenOn( this, ButtonState.Released, TouchRelease, null ).InContext( this );
297  Game.Instance.TouchPanel.Listen( ButtonState.Released, TouchRelease, null ).InContext( this );
298  Game.Instance.TouchPanel.ListenOn( this, ButtonState.Released, TouchClick, null ).InContext( this );
299 #endif
300  }
301 
302  private void InitializeShape()
303  {
304  //double edgeSize = Math.Min( Width, Height ) / 5;
305  double edgeSize = 5;
306  double relativeHorizontalSize = edgeSize / Width;
307  double relativeVerticalSize = edgeSize / Height;
308 
309  Vector topLeftOuter = new Vector( -0.5, 0.5 );
310  Vector topLeftInner = new Vector( -0.5 + relativeHorizontalSize, 0.5 - relativeVerticalSize );
311  Vector bottomLeftOuter = new Vector( -0.5, -0.5 );
312  Vector bottomLeftInner = new Vector( -0.5 + relativeHorizontalSize, -0.5 + relativeVerticalSize );
313  Vector topRightOuter = new Vector( 0.5, 0.5 );
314  Vector topRightInner = new Vector( 0.5 - relativeHorizontalSize, 0.5 - relativeVerticalSize );
315  Vector bottomRightOuter = new Vector( 0.5, -0.5 );
316  Vector bottomRightInner = new Vector( 0.5 - relativeHorizontalSize, -0.5 + relativeVerticalSize );
317 
318  IndexTriangle[] triangles = { new IndexTriangle(0, 1, 2), new IndexTriangle(1, 3, 2), };
319 
320  Vector[] leftSideVertices = { topLeftOuter, topLeftInner, bottomLeftOuter, bottomLeftInner, };
321  Vector[] topSideVertices = { topLeftOuter, topRightOuter, topLeftInner, topRightInner, };
322  Vector[] rightSideVertices = { topRightOuter, bottomRightOuter, topRightInner, bottomRightInner, };
323  Vector[] bottomSideVertices = { bottomRightOuter, bottomLeftOuter, bottomRightInner, bottomLeftInner, };
324 
325  leftSideShape = new ShapeCache( leftSideVertices, triangles );
326  topSideShape = new ShapeCache( topSideVertices, triangles );
327  RightSideShape = new ShapeCache( rightSideVertices, triangles );
328  BottomSideShape = new ShapeCache( bottomSideVertices, triangles );
329 
330  const double scale = 1.4;
331 
332  topLeftOuter = new Vector( -0.5, 0.5 );
333  topLeftInner = new Vector( -0.5 + relativeHorizontalSize / scale, 0.5 - relativeVerticalSize / scale );
334  bottomLeftOuter = new Vector( -0.5, -0.5 );
335  bottomLeftInner = new Vector( -0.5 + relativeHorizontalSize / scale, -0.5 + relativeVerticalSize * scale );
336  topRightOuter = new Vector( 0.5, 0.5 );
337  topRightInner = new Vector( 0.5 - relativeHorizontalSize * scale, 0.5 - relativeVerticalSize / scale );
338  bottomRightOuter = new Vector( 0.5, -0.5 );
339  bottomRightInner = new Vector( 0.5 - relativeHorizontalSize * scale, -0.5 + relativeVerticalSize * scale );
340 
341  Vector[] leftSidePressedVertices = { topLeftOuter, topLeftInner, bottomLeftOuter, bottomLeftInner, };
342  Vector[] topSidePressedVertices = { topLeftOuter, topRightOuter, topLeftInner, topRightInner, };
343  Vector[] rightSidePressedVertices = { topRightOuter, bottomRightOuter, topRightInner, bottomRightInner, };
344  Vector[] bottomSidePressedVertices = { bottomRightOuter, bottomLeftOuter, bottomRightInner, bottomLeftInner, };
345 
346  leftSidePressedShape = new ShapeCache( leftSidePressedVertices, triangles );
347  topSidePressedShape = new ShapeCache( topSidePressedVertices, triangles );
348  RightSidePressedShape = new ShapeCache( rightSidePressedVertices, triangles );
349  BottomSidePressedShape = new ShapeCache( bottomSidePressedVertices, triangles );
350  }
351 
352  private void SetState( State state )
353  {
354  this.state = state;
355 
356  switch ( state )
357  {
358  case State.Hover:
359  base.Color = hoverColor;
360  if ( ImageHover != null )
361  Image = ImageHover;
362  break;
363  case State.RightPressed:
364  case State.LeftPressed:
365  base.Color = pressedColor;
366  if ( ImagePressed != null )
367  ImagePressed = ImagePressed;
368  break;
369  default:
370  base.Color = releasedColor;
371  if ( ImageReleased != null )
372  Image = ImageReleased;
373  break;
374  }
375  }
376 
377  public void Click()
378  {
379  if ( Clicked != null )
380  Clicked();
381  }
382 
383  public void RightClick()
384  {
385  if ( RightClicked != null )
386  RightClicked();
387  }
388 
393  public void AddShortcut( Key key )
394  {
395  Jypeli.Game.Instance.Keyboard.Listen( key, ButtonState.Pressed, Click, null ).InContext( this );
396  }
397 
402  public void AddShortcut( Button button )
403  {
404  for ( int i = 0; i < Jypeli.Game.Controls.GameControllers.Length; i++ )
405  AddShortcut( i, button );
406  }
407 
413  public void AddShortcut( int player, Button button )
414  {
415  Jypeli.Game.Controls.GameControllers[player].Listen( button, ButtonState.Pressed, Click, null ).InContext( this );
416  }
417 
418  private void Press( MouseButton button )
419  {
420  if ( state != State.Hover && state != State.Released )
421  return;
422 
423  if ( button == MouseButton.Left )
424  SetState( State.LeftPressed );
425  else if ( button == MouseButton.Right )
426  SetState( State.RightPressed );
427 
428  if ( Pressed != null )
429  Pressed();
430  }
431 
432  private void Release()
433  {
434  if ( state != State.LeftPressed && state != State.RightPressed )
435  return;
436 
437  bool wasLeft = state == State.LeftPressed;
438  bool wasRight = state == State.RightPressed;
439  bool cursorOn = Game.Controls.Mouse.IsCursorOn( this );
440 
441  if ( cursorOn )
442  {
443  SetState(State.Hover);
444 
445  if ( wasLeft ) Click();
446  else if ( wasRight ) RightClick();
447  }
448  else
449  {
450  SetState( State.Released );
451  }
452 
453  if ( Released != null )
454  Released();
455  }
456 
457  private void CheckHover( AnalogState state )
458  {
459  if ( isPressed )
460  return;
461 
462  SetState( Game.Controls.Mouse.IsCursorOn( this ) ? State.Hover : State.Released );
463  }
464 
465  protected override void Draw( Matrix parentTransformation, Matrix transformation )
466  {
467  base.Draw( parentTransformation, transformation );
468 
469  if ( Image == null )
470  {
471  Color color1 = Color.Lighter( Color, 20 );
472  Color color2 = Color.Darker( Color, 20 );
473 
474  ShapeCache left = leftSideShape;
475  ShapeCache top = topSideShape;
476  ShapeCache right = RightSideShape;
477  ShapeCache bottom = BottomSideShape;
478 
479  if ( isPressed )
480  {
481  color1 = Color.Darker( Color, 20 );
482  color2 = Color.Lighter( Color, 20 );
483  left = leftSidePressedShape;
484  top = topSidePressedShape;
485  right = RightSidePressedShape;
486  bottom = BottomSidePressedShape;
487  }
488 
489  Renderer.DrawFilledShape( left, ref transformation, color1 );
490  Renderer.DrawFilledShape( top, ref transformation, color1 );
491  Renderer.DrawFilledShape( right, ref transformation, color2 );
492  Renderer.DrawFilledShape( bottom, ref transformation, color2 );
493  }
494  }
495 
496  public override void Update( Time time )
497  {
498  if ( Down != null && ( state == State.LeftPressed || state == State.RightPressed ) )
499  {
500  Down();
501  }
502 
503  base.Update( time );
504  }
505  }
506 }
Vector PositionOnScreen
Kosketuksen paikka ruudulla.
Definition: Touch.cs:31
Action RightClicked
Tapahtuu kun nappia on painettu oikealla hiirenpainikkeella.
Definition: PushButton.cs:165
Action Released
Tapahtuu kun nappi päästetään irti.
Definition: PushButton.cs:155
bool IsCursorOn(IGameObject obj)
Onko hiiren kursori annetun olion päällä.
Definition: Mouse.cs:284
override void Update(Time time)
Peliolion päivitys. Tätä kutsutaan, kun IsUpdated-ominaisuuden arvoksi on asetettu true ja olio on li...
Definition: PushButton.cs:496
Listener ListenMovement(double trigger, AnalogHandler handler, string helpText)
Kuuntelee hiiren liikettä.
Definition: Mouse.cs:344
static Color Darker(Color c, int howMuch)
Antaa tummemman värin. Vähentaa jokaista kolmea osaväriä arvon howMuch verran.
Definition: Color.cs:407
void AddShortcut(int player, Button button)
Lisää pikanäppäimen yhdelle ohjaimelle.
Definition: PushButton.cs:413
Listener ListenOn(IGameObject o, ButtonState state, TouchHandler handler, String helpText)
Definition: TouchPanel.cs:334
Nappi on alhaalla.
Listener Listen(Button button, ButtonState state, Handler handler, string helpText)
Definition: GamePad.cs:415
PushButton(double width, double height, string text)
Luo uuden painonapin.
Definition: PushButton.cs:274
Action Pressed
Tapahtuu kun nappi painetaan pohjaan.
Definition: PushButton.cs:150
Kosketuspaneelin kosketus.
Definition: Touch.cs:16
Nappi nostetaan ylös.
static Jypeli.Controls.Controls Controls
Pelin kontrollit.
Definition: Game.cs:207
Tekstikenttä.
Definition: Label.cs:65
ButtonState
Napin (minkä tahansa) asento.
Definition: ButtonState.cs:37
static Game Instance
Definition: Game.cs:149
MouseButton
Hiiren napit.
Definition: MouseButton.cs:11
void AddShortcut(Key key)
Lisää pikanäppäimen napille.
Definition: PushButton.cs:393
int NumTouches
Kuinka monta kosketusta näytöllä on aktiivisena.
Definition: TouchPanel.cs:66
Sisältää tiedon ajasta, joka on kulunut pelin alusta ja viime päivityksestä.
Definition: Time.cs:13
Kuva.
Definition: Image.cs:24
PushButton(double width, double height, Image image)
Luo uuden painonapin omalla kuvalla.
Definition: PushButton.cs:262
Sisältää valmiiksi lasketut kolmiot, joiden avulla piirtäminen on suoraviivaista. ...
Definition: Shapes.cs:577
double Y
Definition: Vector.cs:275
Peliluokka reaaliaikaisille peleille.
Definition: DebugScreen.cs:10
static Image Color(Image image, Color color)
Värittää kuvan.
Definition: Image.cs:894
Listener InContext(ListenContext context)
Kuuntelee tapahtumaa vain tietyssä kontekstissa.
Definition: Listeners.cs:239
GamePad [] GameControllers
Peliohjaimet 1-4.
Definition: Controls.cs:180
Parametrit analogisen ohjauksen (hiiren tai ohjaustikun) tapahtumalle.
Definition: AnalogState.cs:35
Button
Definition: Button.cs:34
Nappi painetaan alas.
Listener Listen(ButtonState state, TouchHandler handler, string helpText)
Definition: TouchPanel.cs:295
Keyboard Keyboard
Näppäimistö.
Definition: Game.cs:248
double X
Definition: Vector.cs:274
TouchPanel TouchPanel
Kosketusnäyttö. Vain kännykässä.
Definition: Game.cs:258
Listener Listen(Key k, ButtonState state, Handler handler, String helpText)
Definition: Keyboard.cs:292
Väri.
Definition: Color.cs:13
override void Draw(Matrix parentTransformation, Matrix transformation)
Definition: PushButton.cs:465
Luokka, joka sisältää metodeita kuvioiden ja tekstuurien piirtämiseen 2D-tasossa. ...
Definition: Renderer.cs:51
Listener Listen(MouseButton b, ButtonState state, Handler handler, string helpText)
Kuuntelee hiiren nappulan painalluksia.
Definition: Mouse.cs:303
Key
Näppäimistön näppäin.
Definition: Key.cs:37
2D-vektori.
Definition: Vector.cs:56
PushButton(double width, double height)
Luo uuden painonapin.
Definition: PushButton.cs:235
Muotojen määrityksessä käytettävä kolmio.
Definition: Shapes.cs:547
void AddShortcut(Button button)
Lisää pikanäppäimen kaikille ohjaimille.
Definition: PushButton.cs:402
static Color Lighter(Color c, int howMuch)
Antaa kirkkaamman värin. Kasvattaa jokaista kolmea osaväriä arvon howMuch verran. ...
Definition: Color.cs:426
Action Down
Tapahtuu kun nappi on pohjassa.
Definition: PushButton.cs:160
Action Clicked
Tapahtuu kun nappia on painettu.
Definition: PushButton.cs:145
Listener ListenOn(IGameObject obj, MouseButton b, ButtonState state, Handler handler, String helpText)
Kuuntelee hiirenpainalluksia annetun peliolion päällä.
Definition: Mouse.cs:324
Mouse Mouse
Hiiri.
Definition: Controls.cs:158