2 * This file is part of NumptyPhysics
3 * Copyright (C) 2008 Tim Edmonds
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 3 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
28 extern Rect FULLSCREEN_RECT
;
30 class OverlayBase
: public Overlay
33 OverlayBase( GameControl
& game
, int x
=10, int y
=10, bool dragging_allowed
=true )
39 m_dragging_allowed(dragging_allowed
),
42 virtual ~OverlayBase()
55 return Rect(m_x
,m_y
,m_x
+m_canvas
->width()-1,m_y
+m_canvas
->height()-1);
61 virtual void onShow() { dirty(); }
62 virtual void onHide() {}
63 virtual void onTick( int tick
) {}
65 virtual void draw( Canvas
& screen
, const Rect
& area
)
68 screen
.drawImage( m_canvas
, m_x
, m_y
);
73 virtual bool handleEvent( SDL_Event
& ev
)
76 case SDL_MOUSEBUTTONDOWN
:
77 //printf("overlay click\n");
78 if ( ev
.button
.button
== SDL_BUTTON_LEFT
79 && ev
.button
.x
>= m_x
&& ev
.button
.x
<= m_x
+ m_canvas
->width()
80 && ev
.button
.y
>= m_y
&& ev
.button
.y
<= m_y
+ m_canvas
->height() ) {
83 m_prevx
= ev
.button
.x
;
84 m_prevy
= ev
.button
.y
;
89 case SDL_MOUSEBUTTONUP
:
90 if ( ev
.button
.button
== SDL_BUTTON_LEFT
) {
93 onDragStop( ev
.button
.x
-m_x
, ev
.button
.y
-m_y
);
94 } else if ( Abs(ev
.button
.x
-m_orgx
) < CLICK_TOLERANCE
95 && Abs(ev
.button
.y
-m_orgy
) < CLICK_TOLERANCE
){
96 onClick( m_orgx
-m_x
, m_orgy
-m_y
);
101 case SDL_MOUSEMOTION
:
104 && m_dragging_allowed
105 && ( Abs(ev
.button
.x
-m_orgx
) >= CLICK_TOLERANCE
106 || Abs(ev
.button
.y
-m_orgy
) >= CLICK_TOLERANCE
) ) {
108 onDragStart( ev
.button
.x
-m_x
, ev
.button
.y
-m_y
);
109 } else if ( m_dragging
) {
110 onDrag( ev
.button
.x
- m_prevx
, ev
.button
.y
- m_prevy
);
111 m_prevx
= ev
.button
.x
;
112 m_prevy
= ev
.button
.y
;
116 return onKey( ev
.key
.keysym
.sym
);
130 void dirty( const Rect
& r
)
135 virtual bool onKey( int k
)
139 virtual bool onDragStart( int x
, int y
)
143 virtual bool onDragStop( int x
, int y
)
147 virtual bool onDrag( int dx
, int dy
)
151 m_game
.m_refresh
= true;
155 virtual bool onClick( int x
, int y
) {
156 for ( int i
=m_hotSpots
.size()-1; i
>=0; i
-- ) {
157 if ( m_hotSpots
[i
].rect
.contains( Vec2(x
,y
) ) ) {
158 if ( m_hotSpots
[i
].c
) {
159 m_hotSpots
[i
].c(m_hotSpots
[i
].o
,m_hotSpots
[i
].f
);
161 } else if ( onHotSpot( m_hotSpots
[i
].id
) ) {
169 virtual bool onHotSpot( int id
) { return false; }
171 void addHotSpot( const Rect
& r
, int id
)
173 HotSpot hs
= { r
, id
, NULL
, NULL
, NULL
};
174 m_hotSpots
.append( hs
);
178 void addHotSpot( const Rect
& r
, void (C::*func
)() )
181 static void call( void* o
, void (Overlay::*f
)() ) {
182 return (((C
*)o
)->*(void (C::*)())f
)();
185 HotSpot hs
= { r
, -1, this, (void (Overlay::*)())func
, Caller::call
};
186 m_hotSpots
.append( hs
);
194 void (Overlay::*f
)();
195 void (*c
)(void*,void (Overlay::*)());
202 int m_prevx
, m_prevy
;
205 bool m_dragging_allowed
;
207 Array
<HotSpot
> m_hotSpots
;
211 class IconOverlay
: public OverlayBase
213 std::string m_filename
;
215 IconOverlay(GameControl
& game
, const char* file
, int x
=100,int y
=20, bool dragging_allowed
=true)
216 : OverlayBase(game
,x
,y
,dragging_allowed
),
219 m_canvas
= new Image( m_filename
.c_str() );
224 class UiOverlay
: public OverlayBase
227 UiOverlay(GameControl
& game
, const Rect
& pos
)
228 : OverlayBase( game
, pos
.tl
.x
, pos
.tl
.y
, true )
229 , m_bgColour(0xf0f0a0)
233 m_canvas
= new Canvas( pos
.width(), pos
.height() );
234 m_canvas
->setBackground( m_bgColour
);
235 m_canvas
->drawRect( 0, 0, pos
.width(), pos
.height(),
236 m_canvas
->makeColour(0xffffff) );
237 m_canvas
->drawRect( 3, 3, pos
.width()-6, pos
.height()-6,
238 m_canvas
->makeColour(m_bgColour
) );
241 void moveTo( const Vec2
& dest
)
243 if ( dest
!= Vec2(m_x
,m_y
) ) {
249 void onTick( int tick
)
251 if ( m_motion
> 0 ) {
259 m_game
.m_refresh
= 1;
264 void addButton( const char* icon
, const Rect
& r
, void (C::*func
)() )
266 if ( Config::findFile(icon
) != icon
) {
267 Image
*i
= new Image(icon
);
268 m_canvas
->drawImage( i
, r
.tl
.x
, r
.tl
.y
);
272 if ( p
.size() > 1 ) {
273 p
.translate( r
.tl
- p
.bbox().tl
);
274 m_canvas
->drawPath( p
, m_fgColour
, false );
276 Font::headingFont()->drawCenter( m_canvas
, r
.centroid(),
280 addHotSpot( r
, func
);
290 class ListOverlay
: public UiOverlay
293 ListOverlay( GameControl
& game
,
294 ListProvider
* provider
,
297 : UiOverlay(game
,Rect(x
,y
,x
+w
,y
+h
)),
298 m_provider( provider
),
305 m_listarea( m_hgap
, m_vgap
, w
-m_hgap
, h
-m_vgap
)
307 Canvas
*first
= m_provider
->provideItem( m_first
, NULL
);
308 m_itemh
= first
->height();
309 m_numvis
= m_listarea
.height() / (m_itemh
+ m_vgap
) + 2;
311 if ( m_numvis
<= m_provider
->countItems() ) {
312 m_allowscroll
= false;
314 m_allowscroll
= true;
315 m_listarea
.tl
.y
+= 20;
316 m_listarea
.br
.y
-= 20;
317 m_numvis
= m_listarea
.height() / (m_itemh
+ m_vgap
);
318 addButton( "Back", Rect(0,0,w
,20), &ListOverlay::doBack
);
319 addButton( "Forward", Rect(0,y
-20,w
,20), &ListOverlay::doForward
);
322 m_items
= (Canvas
**)calloc( sizeof(Canvas
*), m_numvis
);
325 for ( int i
=1; i
<m_numvis
; i
++ ) {
326 m_items
[i
] = m_provider
->provideItem( i
, NULL
);
333 for ( int i
=0; i
<m_numvis
; i
++ ) {
335 m_provider
->releaseItem( m_items
[0] );
342 m_canvas
->clear( m_listarea
);
343 for ( int i
=0; i
< m_numvis
; i
++ ) {
345 if ( q
< m_provider
->countItems() ) {
346 m_canvas
->drawImage( m_items
[q
%m_numvis
],
347 m_listarea
.tl
.x
+ m_offset
.x
,
348 m_listarea
.tl
.y
+ m_offset
.y
+ (m_itemh
+m_vgap
)*i
);
350 if ( q
== m_current
) {
351 m_canvas
->drawRect( m_listarea
.tl
.x
-1 + m_offset
.x
,
352 m_listarea
.tl
.y
+ (m_itemh
+m_vgap
)*i
- 1 + m_offset
.y
,
353 m_items
[q
%m_numvis
]->width()+2,
354 m_items
[q
%m_numvis
]->height()+2,
362 void onTick( int tick
)
364 UiOverlay::onTick( tick
);
365 if ( m_velocity
.y
) {
366 m_offset
+= m_velocity
;
367 while ( m_offset
.y
< -m_itemh
-m_vgap
) {
368 m_offset
.y
+= m_itemh
+m_vgap
;
371 while ( m_offset
.y
>= m_itemh
+m_vgap
) {
372 m_offset
.y
-= m_itemh
+m_vgap
;
375 if ( m_velocity
.y
> 0 ) m_velocity
.y
--;
376 if ( m_velocity
.y
< 0 ) m_velocity
.y
++;
382 virtual bool onClick( int x
, int y
)
384 int i
= m_first
+ (y
- m_vgap
) / (m_itemh
+ m_vgap
);
385 if ( i
>= 0 && i
< m_provider
->countItems() ) {
387 m_provider
->onSelection( m_current
,
389 y
- m_listarea
.tl
.y
- (m_itemh
+m_vgap
)*i
);
394 virtual bool onKey( int k
)
398 if ( m_current
> 0 ) {
400 if ( m_current
< m_first
) {
407 if ( m_current
< m_provider
->countItems()-1 ) {
409 if ( m_current
>= m_first
+m_numvis
-1 ) {
419 bool onDrag( int dx
, int dy
)
429 m_items
[m_first
%m_numvis
] = m_provider
->provideItem( m_first
,
430 m_items
[m_first
%m_numvis
] );
436 int last
= m_first
+ m_numvis
- 1;
437 if ( last
< m_provider
->countItems() ) {
439 last
= m_first
+ m_numvis
- 1;
440 m_items
[last
%m_numvis
] = m_provider
->provideItem( last
, m_items
[last
%m_numvis
] );
445 ListProvider
*m_provider
;
459 class MenuOverlay
: public UiOverlay
462 MenuOverlay(GameControl
& game
)
463 : UiOverlay(game
,Rect(100,100,400,200))
465 addButton( "48,18 47,25 48,25 47,27 48,27 47,29 48,29 47,31 48,33 47,34 48,35 47,40 48,45 49,43 48,43 49,41 48,39 49,38 48,37 47,36 50,34 49,31 44,31 42,30 40,30 36,32 37,33 36,38 35,45 34,47 35,53 34,54 36,56 37,58 38,59 41,59 42,61 43,62 45,62 47,63 49,63 51,64 59,64 61,62 63,62 64,60 66,60 68,58 69,54 70,52 69,52 68,46 67,46 66,42 63,36 62,36 61,34 60,33 59,33 58,32 54,32 53,31 50,31 54,31 53,33", Rect(10,10,90,90), &MenuOverlay::doPause
);
468 m_game
.gotoLevel( m_game
.m_level
+ 1 );
471 void onShow() { moveTo(Vec2(200,200)); }
475 class NextLevelOverlay
: public UiOverlay
478 NextLevelOverlay( GameControl
& game
, int winner
)
479 : UiOverlay(game
,Rect(FULLSCREEN_RECT
.centroid().x
-200,
480 FULLSCREEN_RECT
.centroid().y
-120,
481 FULLSCREEN_RECT
.centroid().x
+200,
482 FULLSCREEN_RECT
.centroid().y
+120 ) ),
490 snprintf(text
, 15, "BRAVO!");
494 snprintf(text
, 15, "Player %d wins!", winner
+1);
497 Font::titleFont()->drawCenter( m_canvas
, Vec2(200,32), text
, 0 );
499 addHotSpot( Rect(0, 0,100,180), &NextLevelOverlay::doPrevLevel
);
500 addHotSpot( Rect(300, 0,400,180), &NextLevelOverlay::doNextLevel
);
502 addButton( "<<", Rect(3,120,40,160),
503 &NextLevelOverlay::doPrevLevel
);
504 addButton( "Action Replay", Rect(0,180,200,240),
505 &NextLevelOverlay::doActionReplay
);
506 addButton( "Continue", Rect(200,180,400,240),
507 &NextLevelOverlay::doContinue
);
513 virtual void onShow()
516 m_game
.m_refresh
= true; //for fullscreen fade
517 m_game
.m_fade
= true;
518 m_selectedLevel
= m_game
.m_level
+1;
520 virtual void onHide()
523 m_game
.m_refresh
= true; //for fullscreen fade
524 m_game
.m_fade
= false;
526 virtual void draw( Canvas
& screen
, const Rect
& area
)
528 UiOverlay::draw( screen
, area
);
530 Font::blurbFont()->drawCenter( &screen
, Vec2(m_x
+200,m_y
+70),
531 m_game
.levels().levelName(m_selectedLevel
), 0 );
532 screen
.drawImage( m_icon
, m_x
+100, m_y
+75 );
539 if (m_selectedLevel
>0) {
549 void doActionReplay()
551 m_game
.gotoLevel( m_game
.m_level
,true );
555 m_game
.gotoLevel( m_selectedLevel
);
560 if ( m_icon
==NULL
|| m_levelIcon
!= m_selectedLevel
) {
562 //Worker w( NULL, 1, 100, 200 );
566 if ( m_selectedLevel
< m_game
.levels().numLevels() ) {
567 Canvas
temp( SCREEN_WIDTH
, SCREEN_HEIGHT
);
568 if ( m_game
.renderScene( temp
, m_selectedLevel
) ) {
569 m_icon
= temp
.scale( ICON_SCALE_FACTOR
);
572 m_icon
= new Image("theend.png");
573 m_caption
= "no more levels!";
574 m_selectedLevel
= m_game
.levels().numLevels();
576 m_levelIcon
= m_selectedLevel
;
584 std::string m_caption
;
589 class EditOverlay
: public IconOverlay
591 int m_saving
, m_sending
;
593 EditOverlay( GameControl
& game
)
594 : IconOverlay(game
,"edit.png"),
595 m_saving(0), m_sending(0)
598 for ( int i
=0; i
<18; i
++ ) {
599 addHotSpot( pos(i
), i
);
601 for ( int i
=0; i
<NUM_BRUSHES
; i
++ ) {
602 m_canvas
->drawRect( pos(i
), m_canvas
->makeColour(brushColours
[i
]), true );
607 int c
= i
%3, r
= i
/3;
608 return Rect( c
*28+13, r
*28+33, c
*28+33, r
*28+53 );
610 int index( int x
, int y
)
614 if ( r
<0 || c
<0 || c
>2 ) return -1;
617 void outline( Canvas
& screen
, int i
, int c
)
619 Rect r
= pos(i
) + Vec2(m_x
,m_y
);
620 r
.tl
.x
-=2; r
.tl
.y
-=2;
621 r
.br
.x
+=2; r
.br
.y
+=2;
622 screen
.drawRect( r
, c
, false );
624 virtual void draw( Canvas
& screen
, const Rect
& area
)
626 IconOverlay::draw( screen
, area
);
627 outline( screen
, m_game
.m_colour
, 0 );
628 if ( m_game
.m_strokeFixed
) outline( screen
, 12, 0 );
629 if ( m_game
.m_strokeSleep
) outline( screen
, 13, 0 );
630 if ( m_game
.m_strokeDecor
) outline( screen
, 14, 0 );
631 if ( m_sending
) outline( screen
, 16, screen
.makeColour((m_sending
--)<<9) );
632 if ( m_saving
) outline( screen
, 17, screen
.makeColour((m_saving
--)<<9) );
633 if ( m_saving
|| m_sending
) dirty();
635 virtual bool onHotSpot( int i
)
638 case 12: m_game
.m_strokeFixed
= ! m_game
.m_strokeFixed
; break;
639 case 13: m_game
.m_strokeSleep
= ! m_game
.m_strokeSleep
; break;
640 case 14: m_game
.m_strokeDecor
= ! m_game
.m_strokeDecor
; break;
641 case 16: if ( m_game
.send() ) m_sending
=10; break;
642 case 17: if ( m_game
.save() ) m_saving
=10; break;
643 default: if (i
<NUM_BRUSHES
) m_game
.m_colour
= i
; else return false;
653 Overlay
* createIconOverlay( GameControl
& game
, const char* file
,
655 bool dragging_allowed
)
657 return new IconOverlay( game
, file
, x
, y
, dragging_allowed
);
660 Overlay
* createEditOverlay( GameControl
& game
)
662 return new EditOverlay( game
);
665 Overlay
* createNextLevelOverlay( GameControl
& game
, int winner
)
667 return new NextLevelOverlay( game
, winner
);
670 Overlay
* createListOverlay( GameControl
& game
,
671 ListProvider
* provider
,
675 return new ListOverlay( game
, provider
, x
, y
, w
, h
);
678 Overlay
* createMenuOverlay( GameControl
& game
)
680 return new MenuOverlay( game
);