1     #include <assert.h>
2     #include <SDL.h>
3     #include <SDL_image.h>
4     #include "cube.h"
5     #include "soundDev.h"
6     #include "view.h"
7     #include "controller.h"
8     #include "font.h"
9     #include "help.h"
10     unsigned int NKlein_54321::View::startCoords[
11             NKlein_54321::Cube::DIMENSIONS + 1
12         ][ 2 ] = {
13             { 0, 0 },
14             {
15                 ( 600 - ( BLOCK - GAP ) ) / 2,
16                 ( 600 - ( SQUARE ) ) / 2
17             },
18             {
19                 ( 600 - ( BLOCK - GAP ) ) / 2,
20                 ( 600 - ( BLOCK - GAP ) ) / 2
21             },
22             {
23                 ( 600 - ( NKlein_54321::Cube::SIDE_LENGTH * BLOCK - GAP ) ) / 2,
24                 ( 600 - ( BLOCK - GAP ) ) / 2
25             },
26             {
27                 ( 600 - ( NKlein_54321::Cube::SIDE_LENGTH * BLOCK - GAP ) ) / 2,
28                 ( 600 - ( NKlein_54321::Cube::SIDE_LENGTH * BLOCK - GAP ) ) / 2
29             }
30         };
31         SDL_Rect NKlein_54321::View::bLocation[
32                 NKlein_54321::View::MAX_BUTTON
33             ] =
34         {
35             { SIDEBAR_X + 2, SIDEBAR_Y + 2, 64, 64 },
36             { SIDEBAR_X + 68, SIDEBAR_Y + 2, 64, 64 },
37             { SIDEBAR_X + 134, SIDEBAR_Y + 2, 64, 64 },
38             { SIDEBAR_X + 2, SIDEBAR_Y + 68, 64, 32 },
39             { SIDEBAR_X + 68, SIDEBAR_Y + 68, 64, 32 },
40             { SIDEBAR_X + 134, SIDEBAR_Y + 68, 64, 32 },
41             { SIDEBAR_X + 68, SIDEBAR_Y + 102, 64, 32 },
42             { SIDEBAR_X + 36, SIDEBAR_Y + 180, 128, 64 },
43             { SIDEBAR_X + 36, SIDEBAR_Y + 250, 128, 64 },
44             { SIDEBAR_X + 2, SIDEBAR_Y + 534, 196, 64 }
45         };
View(SDL_Surface * _screen,SoundDev * _sound,Cube * _cube,unsigned int _dims,unsigned int _skillLevel,bool _wrap)46         NKlein_54321::View::View(
47                 SDL_Surface* _screen,
48                 SoundDev* _sound,
49                 Cube* _cube,
50                 unsigned int _dims,
51                 unsigned int _skillLevel,
52                 bool _wrap
53             ) : screen( _screen ), sound( _sound ), cube( _cube ),
54                 dims( _dims ), skillLevel( _skillLevel ), wrap( _wrap ),
55                 help( 0 )
56         {
57             if ( this->screen != 0 ) {
58                 SDL_PixelFormat* fmt = this->screen->format;
59                 this->bgColor = SDL_MapRGB( fmt, 0, 0, 0 );
60             }
61 
62                 this->sidebar = ::IMG_Load( "/usr/local/share/54321/data/panel.png" );
63                 this->overlay = ::IMG_Load( "/usr/local/share/54321/data/overlay.png" );
64                 this->dimButton[ 0 ] = ::IMG_Load( "/usr/local/share/54321/data/dimOff.png" );
65                 this->dimButton[ 1 ] = ::IMG_Load( "/usr/local/share/54321/data/dimOn.png" );
66                 this->setButton[ 0 ] = ::IMG_Load( "/usr/local/share/54321/data/setOff.png" );
67                 this->setButton[ 1 ] = ::IMG_Load( "/usr/local/share/54321/data/setOn.png" );
68                 this->actButton[ 0 ] = ::IMG_Load( "/usr/local/share/54321/data/actOff.png" );
69                 this->actButton[ 1 ] = ::IMG_Load( "/usr/local/share/54321/data/actOn.png" );
70                 this->helpButton[ 0 ] = ::IMG_Load( "/usr/local/share/54321/data/helpOff.png" );
71                 this->helpButton[ 1 ] = ::IMG_Load( "/usr/local/share/54321/data/helpOn.png" );
72                 this->victory = ::IMG_Load( "/usr/local/share/54321/data/victory.png" );
73                 this->losing = ::IMG_Load( "/usr/local/share/54321/data/defeat.png" );
74 
75             this->clickedButton = MAX_BUTTON;
76             this->reset();
77         }
~View(void)78         NKlein_54321::View::~View( void )
79         {
80                 ::SDL_FreeSurface( this->losing );
81                 ::SDL_FreeSurface( this->victory );
82                 ::SDL_FreeSurface( this->helpButton[ 1 ] );
83                 ::SDL_FreeSurface( this->helpButton[ 0 ] );
84                 ::SDL_FreeSurface( this->actButton[ 1 ] );
85                 ::SDL_FreeSurface( this->actButton[ 0 ] );
86                 ::SDL_FreeSurface( this->setButton[ 1 ] );
87                 ::SDL_FreeSurface( this->setButton[ 0 ] );
88                 ::SDL_FreeSurface( this->dimButton[ 1 ] );
89                 ::SDL_FreeSurface( this->dimButton[ 0 ] );
90                 ::SDL_FreeSurface( this->overlay );
91                 ::SDL_FreeSurface( this->sidebar );
92         }
93         void
reset(void)94         NKlein_54321::View::reset( void )
95         {
96             for ( unsigned int ii=0; ii < MAX_BUTTON; ++ii ) {
97                 this->bPressed[ ii ] = false;
98             }
99 
100             this->bPressed[ DIM_2 + dims - 2 ] = true;
101             this->bPressed[ EASY + this->skillLevel ] = true;
102             this->bPressed[ WRAP ] = this->wrap;
103         }
104         bool
handleMouseClick(Controller * control,bool isMouseUp,unsigned int xx,unsigned int yy,unsigned int buttonNumber)105         NKlein_54321::View::handleMouseClick(
106                 Controller* control,
107                 bool isMouseUp,
108                 unsigned int xx,
109                 unsigned int yy,
110                 unsigned int buttonNumber
111             )
112         {
113                 if ( this->help != 0 ) {
114                     bool hit = this->help->handleMouseClick(
115                             isMouseUp, xx, yy, buttonNumber
116                         );
117                     if ( hit ) {
118                         return true;
119                     }
120                 }
121 
122             if ( ! isMouseUp ) {
123                 for ( unsigned int ii=0; ii < MAX_BUTTON; ++ii ) {
124                     if ( this->checkButton( xx, yy, ii ) ) {
125                         this->clickedButton = ii;
126                             this->originalState = this->bPressed[ this->clickedButton ];
127                             if ( ! this->originalState ) {
128                                 this->bPressed[ this->clickedButton ] = true;
129                                 this->drawButton( this->clickedButton );
130                             }
131                         return true;
132                     }
133                 }
134             } else if ( isMouseUp && this->clickedButton < MAX_BUTTON ) {
135                 unsigned int ii = this->clickedButton;
136                 bool inSide = this->checkButton( xx, yy, ii );
137 
138                     this->bPressed[ this->clickedButton ] = this->originalState;
139                     this->clickedButton = MAX_BUTTON;
140 
141                 if ( inSide ) {
142                         if ( this->help != 0 ) {
143                             this->setHelp( 0 );
144                             this->drawButton( ii );
145                             this->drawButton( HELP );
146                             this->redraw();
147                         } else if ( ii >= DIM_2 && ii <= DIM_4 ) {
148                             this->dims = ii + 2 - DIM_2;
149                             control->setDimension( this->dims );
150                         } else if ( ii >= EASY && ii <= HARD ) {
151                             this->skillLevel = ii - EASY;
152                             control->setSkillLevel( this->skillLevel );
153                         } else if ( ii == WRAP ) {
154                             this->wrap = ! this->wrap;
155                             control->setWrap( this->wrap );
156                         } else if ( ii == NEW ) {
157                             control->newGame();
158                         } else if ( ii == BACK ) {
159                             SDL_Event change;
160                             change.type = SDL_USEREVENT;
161                             change.user.code = -1;
162                             ::SDL_PushEvent( &change );
163                         } else if ( ii == HELP ) {
164                             this->setHelp( new Help( this, this->screen ) );
165                         } else {
166                             this->drawButton( ii );
167                         }
168                 } else {
169                     this->drawButton( ii );
170                 }
171 
172                 return true;
173             }
174 
175             return false;
176         }
177         bool
checkButton(unsigned int xx,unsigned int yy,unsigned int ii)178         NKlein_54321::View::checkButton(
179                 unsigned int xx, unsigned int yy,
180                 unsigned int ii
181             )
182         {
183             return ( xx >= this->bLocation[ ii ].x
184                 && xx < this->bLocation[ ii ].x + this->bLocation[ ii ].w
185                 && yy >= this->bLocation[ ii ].y
186                 && yy < this->bLocation[ ii ].y + this->bLocation[ ii ].h
187             );
188         }
189         bool
screenToCell(unsigned int xx,unsigned int yy,unsigned int dims,unsigned int * index)190         NKlein_54321::View::screenToCell(
191                 unsigned int xx, unsigned int yy,
192                 unsigned int dims,
193                 unsigned int* index
194             )
195         {
196             assert( index != 0 );
197             assert( dims <= 4 && dims > 0 );
198 
199                 unsigned int sx = startCoords[ dims ][ 0 ];
200                 unsigned int sy = startCoords[ dims ][ 1 ];
201 
202                 if ( xx < sx || sy < sy ) {
203                     return false;
204                 }
205 
206                 xx -= sx;
207                 yy -= sy;
208                 unsigned int coords[ NKlein_54321::Cube::DIMENSIONS ];
209 
210                 coords[ 2 ] = xx / BLOCK;
211                 coords[ 3 ] = yy / BLOCK;
212 
213                 coords[ 0 ] = ( xx - coords[ 2 ] * BLOCK ) / SQUARE;
214                 coords[ 1 ] = ( yy - coords[ 3 ] * BLOCK ) / SQUARE;
215                 for ( unsigned int ii=0; ii < dims; ++ii ) {
216                     if ( coords[ ii ] >= NKlein_54321::Cube::SIDE_LENGTH ) {
217                         return false;
218                     }
219                 }
220                 for ( unsigned int ii=dims; ii < NKlein_54321::Cube::DIMENSIONS; ++ii ) {
221                     if ( coords[ ii ] > 0 ) {
222                         return false;
223                     }
224                 }
225 
226             NKlein_54321::Cube::vectorToIndex( coords, index );
227             return true;
228         }
229         void
cellToScreen(unsigned int index,unsigned int dims,unsigned int * xx,unsigned int * yy)230         NKlein_54321::View::cellToScreen(
231                 unsigned int index,
232                 unsigned int dims,
233                 unsigned int* xx, unsigned int* yy
234             )
235         {
236             assert( xx != 0 );
237             assert( yy != 0 );
238 
239             unsigned int coords[ NKlein_54321::Cube::DIMENSIONS ];
240             NKlein_54321::Cube::indexToVector( index, coords );
241 
242             *xx = startCoords[ dims ][ 0 ]
243                 + coords[ 0 ] * SQUARE
244                 + coords[ 2 ] * BLOCK
245                 ;
246 
247             *yy = startCoords[ dims ][ 1 ]
248                 + coords[ 1 ] * SQUARE
249                 + coords[ 3 ] * BLOCK
250                 ;
251         }
252         void
redraw(void)253         NKlein_54321::View::redraw( void )
254         {
255             SDL_Rect rect;
256 
257                 rect.x = 0;
258                 rect.y = 0;
259                 rect.w = 600;
260                 rect.h = 600;
261                 ::SDL_FillRect( this->screen, 0, this->bgColor );
262                 if ( this->sidebar != 0 ) {
263                     rect.x = SIDEBAR_X;
264                     rect.y = SIDEBAR_Y;
265                     rect.w = 200;
266                     rect.h = 600;
267                     ::SDL_BlitSurface( this->sidebar, 0, this->screen, &rect );
268                 }
269                 for ( unsigned int ii=0; ii < MAX_BUTTON; ++ii ) {
270                     this->drawButton( ii, false );
271                 }
272                 if ( this->overlay != 0 ) {
273                     rect.x = SIDEBAR_X;
274                     rect.y = SIDEBAR_Y;
275                     rect.w = 200;
276                     rect.h = 600;
277                     ::SDL_BlitSurface( this->overlay, 0, this->screen, &rect );
278                 }
279         }
280         void
drawButton(unsigned int button,bool update)281         NKlein_54321::View::drawButton(
282                 unsigned int button,
283                 bool update
284             )
285         {
286             SDL_Surface** images;
287 
288                 if ( button >= DIM_2 && button <= DIM_4 ) {
289                     images = this->dimButton;
290                 } else if ( button >= EASY && button <= WRAP ) {
291                     images = this->setButton;
292                 } else if ( button >= NEW && button <= BACK ) {
293                     images = this->actButton;
294                 } else if ( button == HELP ) {
295                     images = this->helpButton;
296                 } else {
297                     assert( 0 == 1 );
298                 }
299 
300             if ( this->bPressed[ button ] ) {
301                 ++images;
302             }
303 
304             ::SDL_BlitSurface(
305                     *images, 0,
306                     this->screen, &bLocation[ button ]
307                 );
308 
309             if ( update ) {
310                     SDL_Rect overlayRect;
311                     overlayRect.x = bLocation[ button ].x - SIDEBAR_X;
312                     overlayRect.y = bLocation[ button ].y - SIDEBAR_Y;
313                     overlayRect.w = bLocation[ button ].w;
314                     overlayRect.h = bLocation[ button ].h;
315 
316                     ::SDL_BlitSurface(
317                             this->overlay, &overlayRect,
318                             this->screen, &bLocation[ button ]
319                         );
320                 ::SDL_UpdateRect( this->screen,
321                         bLocation[ button ].x, bLocation[ button ].y,
322                         bLocation[ button ].w, bLocation[ button ].h
323                     );
324             }
325         }
326         void
backgroundMusic(bool stop)327         NKlein_54321::View::backgroundMusic( bool stop )
328         {
329         }
330         void
moveNoise(void)331         NKlein_54321::View::moveNoise( void )
332         {
333             if ( this->sound != 0 ) {
334                 this->sound->ding();
335             } else {
336                 ::SDL_Delay( 250U );
337             }
338         }
339         void
victoryMusic(void)340         NKlein_54321::View::victoryMusic( void )
341         {
342             ::SDL_Delay( 5000U );
343         }
344         void
losingMusic(void)345         NKlein_54321::View::losingMusic( void )
346         {
347             ::SDL_Delay( 3000U );
348         }
349         void
showWinning(unsigned int,unsigned int)350         NKlein_54321::View::showWinning(
351                 unsigned int /*actualMoves*/,
352                 unsigned int /*expectedMoves*/
353             )
354         {
355             if ( this->screen != 0 && this->victory != 0 ) {
356                 SDL_Rect rect;
357                 rect.x = ( 600 - this->victory->w ) / 2;
358                 rect.y = ( 600 - this->victory->h ) / 2;
359                 ::SDL_BlitSurface( this->victory, 0, this->screen, &rect );
360                 ::SDL_UpdateRect(
361                         this->screen,
362                         rect.x, rect.y,
363                         this->victory->w, this->victory->h
364                     );
365             }
366             this->victoryMusic();
367             if ( this->screen != 0 && this->victory != 0 ) {
368                 this->redraw();
369             }
370         }
371         void
showLosing(void)372         NKlein_54321::View::showLosing( void )
373         {
374             if ( this->screen != 0 && this->losing != 0 ) {
375                 SDL_Rect rect;
376                 rect.x = ( 600 - this->losing->w ) / 2;
377                 rect.y = ( 600 - this->losing->h ) / 2;
378                 ::SDL_BlitSurface( this->losing, 0, this->screen, &rect );
379                 ::SDL_UpdateRect(
380                         this->screen,
381                         rect.x, rect.y,
382                         this->losing->w, this->losing->h
383                     );
384             }
385             this->losingMusic();
386             if ( this->screen != 0 && this->losing != 0 ) {
387                 this->redraw();
388             }
389         }
390         void
setHelp(Help * nn)391         NKlein_54321::View::setHelp( Help* nn )
392         {
393             delete this->help;
394             this->help = nn;
395 
396             if ( this->help == 0 ) {
397                 this->bPressed[ HELP ] = false;
398                 this->drawButton( HELP );
399                 this->redraw();
400             }
401         }
402