1 /* 2 * Copyright 2008 Ralf Schülke, ralf.schuelke@googlemail.com. 3 * Copyright 2010 Adam Smith <adamd.smith@utoronto.ca> 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 7 #include "PairsWindow.h" 8 9 #include <stdio.h> 10 11 #include <Application.h> 12 #include <Alert.h> 13 #include <Button.h> 14 #include <Catalog.h> 15 #include <Locale.h> 16 #include <Menu.h> 17 #include <MenuBar.h> 18 #include <MenuItem.h> 19 #include <MessageRunner.h> 20 #include <String.h> 21 #include <TextView.h> 22 23 #include "Pairs.h" 24 #include "PairsGlobal.h" 25 #include "PairsView.h" 26 #include "PairsTopButton.h" 27 28 29 // #pragma mark - PairsWindow 30 31 32 #undef TR_CONTEXT 33 #define TR_CONTEXT "PairsWindow" 34 35 const uint32 MENU_NEW = 'MGnw'; 36 const uint32 MENU_SIZE = 'MGsz'; 37 const uint32 MENU_QUIT = 'MGqu'; 38 39 40 PairsWindow::PairsWindow() 41 : 42 BWindow(BRect(100, 100, 405, 423), "Pairs", B_TITLED_WINDOW, 43 B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE 44 | B_NOT_RESIZABLE | B_NOT_ZOOMABLE), 45 fPairComparing(NULL), 46 fIsFirstClick(true), 47 fIsPairsActive(true), 48 fPairCard(0), 49 fPairCardTmp(0), 50 fButtonTmp(0), 51 fButton(0), 52 fButtonClicks(0), 53 fFinishPairs(0) 54 { 55 _MakeMenuBar(); 56 _MakeGameView(4, 4); 57 58 CenterOnScreen(); 59 } 60 61 62 PairsWindow::~PairsWindow() 63 { 64 delete fPairComparing; 65 } 66 67 68 void 69 PairsWindow::_MakeMenuBar() 70 { 71 fMenuBar = new BMenuBar(BRect(0, 0, 0, 0), "menubar"); 72 AddChild(fMenuBar); 73 74 BMenu* menu = new BMenu(TR("Game")); 75 fMenuBar->AddItem(menu); 76 77 BMenuItem* menuItem; 78 menu->AddItem(menuItem = new BMenuItem(TR("New"), 79 new BMessage(MENU_NEW), 'N')); 80 81 menu->AddSeparatorItem(); 82 83 BMenu* sizeMenu = new BMenu(TR("Size")); 84 sizeMenu->SetRadioMode(true); 85 86 BMessage* sizeMessage = new BMessage(MENU_SIZE); 87 sizeMessage->AddInt32("width", 4); 88 sizeMessage->AddInt32("height", 4); 89 sizeMenu->AddItem(menuItem = new BMenuItem(TR("Beginner (4x4)"), 90 sizeMessage)); 91 menuItem->SetMarked(true); 92 93 sizeMessage = new BMessage(MENU_SIZE); 94 sizeMessage->AddInt32("width", 6); 95 sizeMessage->AddInt32("height", 6); 96 sizeMenu->AddItem(menuItem = new BMenuItem(TR("Intermediate (6x6)"), 97 sizeMessage)); 98 99 sizeMessage = new BMessage(MENU_SIZE); 100 sizeMessage->AddInt32("width", 8); 101 sizeMessage->AddInt32("height", 8); 102 sizeMenu->AddItem(menuItem = new BMenuItem(TR("Expert (8x8)"), 103 sizeMessage)); 104 105 menu->AddItem(sizeMenu); 106 107 menu->AddSeparatorItem(); 108 109 menu->AddItem(menuItem = new BMenuItem(TR("Quit"), 110 new BMessage(MENU_QUIT), 'Q')); 111 } 112 113 114 void 115 PairsWindow::_MakeGameView(int width, int height) 116 { 117 BRect viewBounds = Bounds(); 118 viewBounds.top = fMenuBar->Bounds().Height() + 1; 119 120 fPairsView = new PairsView(viewBounds, "PairsView", width, height, 121 B_FOLLOW_NONE); 122 fPairsView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 123 AddChild(fPairsView); 124 } 125 126 127 void 128 PairsWindow::NewGame() 129 { 130 fButtonClicks = 0; 131 fFinishPairs = 0; 132 fPairsView->CreateGameBoard(); 133 } 134 135 136 void 137 PairsWindow::SetGameSize(int width, int height) 138 { 139 ResizeTo((kBitmapSize + kSpaceSize) * width + kSpaceSize, 140 (kBitmapSize + kSpaceSize) * height + kSpaceSize 141 + fMenuBar->Bounds().Height()); 142 RemoveChild(fPairsView); 143 delete fPairsView; 144 _MakeGameView(width, height); 145 NewGame(); 146 } 147 148 149 void 150 PairsWindow::MessageReceived(BMessage* message) 151 { 152 switch (message->what) { 153 case MENU_NEW: 154 NewGame(); 155 break; 156 case MENU_SIZE: 157 { 158 int32 width; 159 int32 height; 160 if (message->FindInt32("width", &width) == B_OK 161 && message->FindInt32("height", &height) == B_OK) { 162 SetGameSize(width, height); 163 } 164 break; 165 } 166 case MENU_QUIT: 167 be_app->PostMessage(B_QUIT_REQUESTED); 168 break; 169 case kMsgCardButton: 170 if (fIsPairsActive) { 171 fButtonClicks++; 172 173 int32 num; 174 if (message->FindInt32("ButtonNum", &num) < B_OK) 175 break; 176 177 // look what Icon is behind a button 178 for (int h = 0; h < fPairsView->fNumOfCards; h++) { 179 if (fPairsView->GetIconFromPos(h) == num) { 180 fPairCard = (h % fPairsView->fNumOfCards / 2); 181 fButton = fPairsView->GetIconFromPos(h); 182 break; 183 } 184 } 185 186 // gameplay 187 ((TopButton*)fPairsView->fDeckCard.ItemAt(fButton))->Hide(); 188 189 if (fIsFirstClick) { 190 fPairCardTmp = fPairCard; 191 fButtonTmp = fButton; 192 } else { 193 delete fPairComparing; 194 // message of message runner might not have arrived 195 // yet, so it is deleted here to prevent any leaking 196 // just in case 197 BMessage message(kMsgPairComparing); 198 fPairComparing = new BMessageRunner(BMessenger(this), 199 &message, 5 * 100000L, 1); 200 fIsPairsActive = false; 201 } 202 203 fIsFirstClick = !fIsFirstClick; 204 } 205 break; 206 207 case kMsgPairComparing: 208 delete fPairComparing; 209 fPairComparing = NULL; 210 211 fIsPairsActive = true; 212 213 if (fPairCard == fPairCardTmp) 214 fFinishPairs++; 215 else { 216 ((TopButton*)fPairsView->fDeckCard.ItemAt(fButton))->Show(); 217 ((TopButton*)fPairsView->fDeckCard.ItemAt(fButtonTmp))->Show(); 218 } 219 220 // game end and results 221 if (fFinishPairs == fPairsView->fNumOfCards / 2) { 222 BString strAbout; 223 strAbout 224 << "Pairs\n" 225 << "\twritten by Ralf Schülke\n" 226 << "\tCopyright 2008-2010, Haiku Inc.\n" 227 << "\n" 228 << "You completed the game in " << fButtonClicks 229 << " clicks.\n"; 230 231 BAlert* alert = new BAlert("about", TR(strAbout.String()), 232 TR("New game"), TR("Quit game")); 233 234 BTextView* view = alert->TextView(); 235 BFont font; 236 237 view->SetStylable(true); 238 239 view->GetFont(&font); 240 font.SetSize(18); 241 font.SetFace(B_BOLD_FACE); 242 view->SetFontAndColor(0, 6, &font); 243 view->ResizeToPreferred(); 244 245 if (alert->Go() == 0) { 246 // New game 247 NewGame(); 248 } else { 249 // Quit game 250 be_app->PostMessage(B_QUIT_REQUESTED); 251 } 252 } 253 break; 254 255 default: 256 BWindow::MessageReceived(message); 257 break; 258 } 259 } 260