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