1\section{The Main Menu View} 2 3The namespace inside the MainMenu view class is a concatenation 4of the general namespace and the name of the MainMenu view 5class. 6<<MainMenuVNameSpace>>= 7<<NameSpace>>::MainMenuView 8@ 9 10The main menu defines all of the games selectable from the main 11menu. This ordering is used in the arrays of images and bounding 12boxes below. The ordering is also used by the main menu controller 13to tell the main loop when to switch to a different game mode. 14<<MainMenu Games>>= 15 enum { 16 FLIPFLOP = 0, 17 BOMBSQUAD, 18 MAZERUNNER, 19 PEGJUMPER, 20 TILESLIDER, 21 MAX_GAME 22 }; 23@ 24 25The Main Menu stores pointers to the images of the sidebar, 26the backdrop, and the button overlay. 27<<MainMenu Images>>= 28 SDL_Surface* sidebar; 29 SDL_Surface* backdrop; 30 SDL_Surface* overlay; 31@ 32 33The Main Menu stores pointers to the images of the game logos 34to use. 35<<MainMenu Images>>= 36 SDL_Surface* logos[ MAX_GAME ]; 37@ 38 39The Main Menu view class also stores the images used as a backdrop 40for the quit button. 41<<MainMenu Images>>= 42 SDL_Surface* quitButton[2]; 43@ 44 45In addition to that, it also keeps track of where the quit button 46is on the screen and whether it is pressed or not. 47<<MainMenu Box Declarations>>= 48 static SDL_Rect quitBox; 49@ 50<<MainMenu Box Definitions>>= 51 SDL_Rect <<MainMenuVNameSpace>>::quitBox = { 52 <<ViewNameSpace>>::SIDEBAR_X + 2, 53 <<ViewNameSpace>>::SIDEBAR_Y + 534, 54 196, 64 55 }; 56@ 57<<MainMenu Quit State>>= 58 bool quitPressed; 59@ 60 61The Main Menu also caches a pointer to the screen. 62<<MainMenu Screen>>= 63 SDL_Surface* screen; 64@ 65 66The Main Menu also tracks the bounding boxes of each of 67the above logos. 68<<MainMenu Box Declarations>>= 69 static SDL_Rect boxes[ MAX_GAME ]; 70@ 71<<MainMenu Box Definitions>>= 72 SDL_Rect <<MainMenuVNameSpace>>::boxes[ MAX_GAME ] = { 73 { 0, 0, 300, 200 }, 74 { 300, 0, 300, 200 }, 75 { 150, 200, 300, 200 }, 76 { 0, 400, 300, 200 }, 77 { 300, 400, 300, 200 }, 78 }; 79@ 80 81%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 82\subsection{The Constructor} 83 84The constructor for the MainMenu view class takes one argument---a 85pointer to the screen. 86<<MainMenuV Constructor Declaration>>= 87 MainMenuView( SDL_Surface* _screen ); 88@ 89 90The constructor for the MainMenu view class loads the images for 91the sidebar and quit button and for each of the games. 92<<MainMenuV Constructor Implementation>>= 93 <<MainMenuVNameSpace>>::MainMenuView( 94 SDL_Surface* _screen 95 ) : quitPressed( false ), screen( _screen ) 96 { 97 <<MainMenuV Load Base Images>> 98 <<MainMenuV Load Logo Images>> 99 } 100@ 101 102There are images for the backdrop of the sidebar, the 103backdrop of the game, the overlay over the sidebar buttons, 104and the quit button in the up and down states. 105<<MainMenuV Load Base Images>>= 106 this->sidebar = ::IMG_Load( "../../data/panel.png" ); 107 this->backdrop = ::IMG_Load( "../../data/backdrop.png" ); 108 this->overlay = ::IMG_Load( "../../data/moverlay.png" ); 109 this->quitButton[ 0 ] = ::IMG_Load( "../../data/helpOff.png" ); 110 this->quitButton[ 1 ] = ::IMG_Load( "../../data/helpOn.png" ); 111@ 112 113There are also logos for each of the games available from 114the main menu. 115<<MainMenuV Load Logo Images>>= 116 this->logos[ FLIPFLOP ] 117 = ::IMG_Load( "../../data/flogo.png" ); 118 this->logos[ BOMBSQUAD ] 119 = ::IMG_Load( "../../data/blogo.png" ); 120 this->logos[ MAZERUNNER ] 121 = ::IMG_Load( "../../data/mlogo.png" ); 122 this->logos[ PEGJUMPER ] 123 = ::IMG_Load( "../../data/plogo.png" ); 124 this->logos[ TILESLIDER ] 125 = ::IMG_Load( "../../data/tlogo.png" ); 126@ 127 128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 129\subsection{The Destructor} 130 131The destructor for the MainMenu view class simply release 132the images loaded above in the constructor. 133<<MainMenuV Destructor Declaration>>= 134 ~MainMenuView( void ); 135@ 136<<MainMenuV Destructor Implementation>>= 137 <<MainMenuVNameSpace>>::~MainMenuView( void ) 138 { 139 <<MainMenuV Release Logo Images>> 140 <<MainMenuV Release Base Images>> 141 } 142@ 143 144Releasing the logo images is easy. We can just loop 145through each of the logos and release them. 146<<MainMenuV Release Logo Images>>= 147 for ( unsigned int ii=0; ii < MAX_GAME; ++ii ) { 148 ::SDL_FreeSurface( this->logos[ ii ] ); 149 } 150@ 151 152Releasing the base images takes a little more effort. We have to 153release each image one by one. 154<<MainMenuV Release Base Images>>= 155 ::SDL_FreeSurface( this->quitButton[ 1 ] ); 156 ::SDL_FreeSurface( this->quitButton[ 0 ] ); 157 ::SDL_FreeSurface( this->overlay ); 158 ::SDL_FreeSurface( this->backdrop ); 159 ::SDL_FreeSurface( this->sidebar ); 160@ 161 162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 163\subsection{The Redraw Methods} 164 165The MainMenu view class has a method which allows one to update 166the entire display area for the game. 167<<MainMenuV Redraw Declarations>>= 168 void redraw( void ) const; 169@ 170 171The redraw function here simply redraws the backdrop and the 172sidebar and each of the game logos. 173<<MainMenuV Redraw Implementations>>= 174 void 175 <<MainMenuVNameSpace>>::redraw( void ) const 176 { 177 SDL_Rect rr; 178 <<MainMenu Redraw Backdrop>> 179 <<MainMenu Redraw Logos>> 180 <<MainMenu Redraw Sidebar>> 181 ::SDL_UpdateRect( this->screen, 0, 0, 0, 0 ); 182 } 183@ 184 185Redrawing the backdrop is simple. We simply have to copy 186the backdrop onto the screen. 187<<MainMenu Redraw Backdrop>>= 188 ::SDL_BlitSurface( this->backdrop, 0, this->screen, 0 ); 189@ 190 191To draw the logos for the games onto the screen, we have to 192copy each of them into their appropriate rectangle. 193<<MainMenu Redraw Logos>>= 194 for ( unsigned int ii=0; ii < MAX_GAME; ++ii ) { 195 rr = boxes[ ii ]; 196 ::SDL_BlitSurface( this->logos[ ii ], 0, this->screen, &rr ); 197 } 198@ 199 200To draw the sidebar, we first draw the backdrop of the sidebar. 201<<MainMenu Redraw Sidebar>>= 202 rr.x = <<ViewNameSpace>>::SIDEBAR_X; 203 rr.y = <<ViewNameSpace>>::SIDEBAR_Y; 204 ::SDL_BlitSurface( this->sidebar, 0, this->screen, &rr ); 205@ 206 207After that, we draw the overlay atop the sidebar. 208<<MainMenu Redraw Sidebar>>= 209 rr.x = <<ViewNameSpace>>::SIDEBAR_X; 210 rr.y = <<ViewNameSpace>>::SIDEBAR_Y; 211 ::SDL_BlitSurface( this->overlay, 0, this->screen, &rr ); 212@ 213 214Then, we redraw the quit button on top of the sidebar. 215<<MainMenu Redraw Sidebar>>= 216 this->redrawQuit( false ); 217@ 218 219The above draw method and the handler for mouse events both need 220to draw the quit button. Rather than duplicating code, we have 221broken it out into its own method. 222<<MainMenuV Redraw Declarations>>= 223 void redrawQuit( bool refresh = true ) const; 224@ 225 226The method simply picks the appropriate bitmap for the current 227state of the button. Then, it draws the button. Then, it copies 228the portion of the overlay that would otherwise have been atop 229the button. Then, if it is supposed to refresh, it updates the 230appropriate rectangle of the screen. 231<<MainMenuV Redraw Implementations>>= 232 void 233 <<MainMenuVNameSpace>>::redrawQuit( bool refresh ) const 234 { 235 unsigned int index = ( ! this->quitPressed ) ? 0 : 1 ; 236 SDL_Surface* button = this->quitButton[ index ]; 237 ::SDL_BlitSurface( button, 0, this->screen, &quitBox ); 238 239 <<MainMenuV Redraw Quit Show Overlay>> 240 241 if ( refresh ) { 242 ::SDL_UpdateRect( 243 this->screen, 244 quitBox.x, quitBox.y, 245 quitBox.w, quitBox.h 246 ); 247 } 248 } 249@ 250 251Because the overlay is the same size as the sidebar, we have to 252take extra care to make sure that we're copying the right portion 253of it onto the button. 254<<MainMenuV Redraw Quit Show Overlay>>= 255 SDL_Rect rr = quitBox; 256 rr.x -= <<ViewNameSpace>>::SIDEBAR_X; 257 rr.y -= <<ViewNameSpace>>::SIDEBAR_Y; 258 ::SDL_BlitSurface( this->overlay, &rr, this->screen, &quitBox ); 259@ 260 261 262%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 263\subsection{Handling Mouse Clicks} 264 265When the Main Menu controller receives a mouse click, it passes it 266on to the [[MainMenuView]] class. The view class is responsible 267for determining if the quit button was clicked. If it was, then 268the quit event is sent out. 269<<MainMenuV Mouse Click Declaration>>= 270 virtual bool handleMouseClick( 271 Controller* controller, 272 bool isMouseUp, 273 unsigned int xx, 274 unsigned int yy, 275 unsigned int buttonNumber 276 ); 277@ 278 279This method checks to see if the event happened inside the quit 280button. If we hit the quit button with a mouse down event, then 281we put the quit button into the ``pressed'' state. Otherwise, 282if the quit button had already been pressed, we put it back 283into the ``unpressed'' state if the event is a mouse up event 284and we actually quit if the mouse up event happened inside of 285the pressed quit button. 286<<MainMenuV Mouse Click Implementation>>= 287 bool 288 <<MainMenuVNameSpace>>::handleMouseClick( 289 Controller* control, 290 bool isMouseUp, 291 unsigned int xx, 292 unsigned int yy, 293 unsigned int buttonNumber 294 ) 295 { 296 <<MainMenuV MouseClick Check Quit Button>> 297 298 if ( hitQuit && ! isMouseUp ) { 299 <<MainMenuV MouseClick Press Quit>> 300 } else if ( this->quitPressed ) { 301 if ( isMouseUp ) { 302 <<MainMenuV MouseClick Unpress Quit>> 303 } 304 if ( hitQuit ) { 305 <<MainMenuV MouseClick Perform Quit>> 306 } 307 } 308 309 return hitQuit; 310 } 311@ 312 313Checking to see if the mouse event happened inside the quit button 314is a straightforward check of the coordinates with the bounds of 315the quit button. 316<<MainMenuV MouseClick Check Quit Button>>= 317 bool hitQuit = ( 318 xx >= quitBox.x && xx < quitBox.x + quitBox.w 319 && yy >= quitBox.y && yy < quitBox.y + quitBox.h 320 ); 321@ 322 323To set the button into the pressed mode, we mark it as 324pressed and redraw it. 325<<MainMenuV MouseClick Press Quit>>= 326 this->quitPressed = true; 327 this->redrawQuit(); 328@ 329 330To set the button into the unpressed mode, we mark it as 331unpressed and redraw it. 332<<MainMenuV MouseClick Unpress Quit>>= 333 this->quitPressed = false; 334 this->redrawQuit(); 335@ 336 337If someone pressed and then released the mouse within the 338quit button, then we actually send off the SDL event to 339signal a quit. 340<<MainMenuV MouseClick Perform Quit>>= 341 SDL_Event quit; 342 quit.type = SDL_QUIT; 343 ::SDL_PushEvent( &quit ); 344@ 345 346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 347\subsection{The Point in Box Method} 348 349The controller uses this method to see if the given point is 350inside a particular game's bounding box. 351<<MainMenu Point In Box Declaration>>= 352 bool pointInBox( 353 unsigned int xx, unsigned int yy, 354 unsigned int game 355 ) const; 356@ 357 358The method itself simply compares the coordinates with those of 359the box in question. 360<<MainMenu Point In Box Implementation>>= 361 bool 362 <<MainMenuVNameSpace>>::pointInBox( 363 unsigned int xx, unsigned int yy, 364 unsigned int game 365 ) const 366 { 367 assert( game < MAX_GAME ); 368 return xx >= boxes[ game ].x 369 && xx < boxes[ game ].x + boxes[ game ].w 370 && yy >= boxes[ game ].y 371 && yy < boxes[ game ].y + boxes[ game ].h; 372 } 373@ 374 375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 376\subsection{The [[MainMenuView]] class} 377 378In this section, we assemble the [[MainMenuView]] class from 379the pieces in the sections above. 380 381We start off the [[MainMenuView]] class with the declaration 382of which games are supported. 383<<MainMenuV Class Definition>>= 384 public: 385 <<MainMenu Games>> 386@ 387 388We include, in the [[MainMenuView]] class, the constructor, 389the destructor, and the redraw methods. 390<<MainMenuV Class Definition>>= 391 public: 392 <<MainMenuV Constructor Declaration>> 393 <<MainMenuV Destructor Declaration>> 394 <<MainMenuV Redraw Declarations>> 395@ 396 397The [[MainMenuView]] class then includes the declaration 398of the method used to see if a particular button was clicked 399and the declaration of the method used to field clicks on the 400quit button. 401<<MainMenuV Class Definition>>= 402 public: 403 <<MainMenu Point In Box Declaration>> 404 <<MainMenuV Mouse Click Declaration>> 405@ 406 407We include the variables that are used in the main menu view class. 408<<MainMenuV Class Definition>>= 409 private: 410 <<MainMenu Images>> 411 <<MainMenu Screen>> 412 <<MainMenu Quit State>> 413 <<MainMenu Box Declarations>> 414@ 415 416Once these declarations are all done, we throw all of these together 417into the class declaration itself. 418<<MainMenuV Class Declaration>>= 419 class MainMenuView { 420 <<MainMenuV Class Definition>> 421 }; 422@ %def MainMenuView 423 424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 425\subsection{The [[mainmenuView.h]] file} 426 427In this section, we assemble the header file for the [[MainMenuView]] 428class. It is really straightforward since we assembled the class 429declaration in the previous section. The only thing that we add 430to the class declaration is that we tuck it into our own name space 431so that we can keep the global namespace squeaky clean. 432<<mainmenuView.h>>= 433 namespace <<NameSpace>> { 434 <<MainMenuV Class Declaration>> 435 }; 436@ 437 438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 439\subsection{The [[mainmenuView.cpp]] file} 440 441In this section, we assemble the MainMenu view source file. It 442requires the [[SDL]] headers for dealing with surfaces, the screen, 443blitting, and loading images. It requires the header files for 444the [[Cube]] class, the [[SoundDev]] class, the [[View]] class for 445its constants, and the [[MainMenuView]] class itself. 446<<mainmenuView.cpp>>= 447 #include <assert.h> 448 #include <SDL.h> 449 #include <SDL_image.h> 450 #include "cube.h" 451 #include "soundDev.h" 452 #include "view.h" 453 #include "mainmenuView.h" 454@ 455 456After the header files, we include the implementations of the 457constructor, the destructor, and the redraw methods. 458<<mainmenuView.cpp>>= 459 <<MainMenuV Constructor Implementation>> 460 <<MainMenuV Destructor Implementation>> 461 <<MainMenuV Redraw Implementations>> 462@ 463 464The main menu source file then goes on to include the 465implementation of the method used to check to see if 466a particular box has been clicked and the implementation 467of the method used to check to see if the quit button 468has been clicked. 469<<mainmenuView.cpp>>= 470 <<MainMenu Point In Box Implementation>> 471 <<MainMenuV Mouse Click Implementation>> 472@ 473 474Then, the source file includes the definition of the bounding 475boxes. 476<<mainmenuView.cpp>>= 477 <<MainMenu Box Definitions>> 478@ 479