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 B_TRANSLATE_CONTEXT 33 #define B_TRANSLATE_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), B_TRANSLATE_SYSTEM_NAME("Pairs"), 43 B_TITLED_WINDOW, 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(B_TRANSLATE("Game")); 75 fMenuBar->AddItem(menu); 76 77 BMenuItem* menuItem; 78 menu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("New"), 79 new BMessage(MENU_NEW), 'N')); 80 81 menu->AddSeparatorItem(); 82 83 BMenu* sizeMenu = new BMenu(B_TRANSLATE("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(B_TRANSLATE("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( 97 B_TRANSLATE("Intermediate (6x6)"), sizeMessage)); 98 99 sizeMessage = new BMessage(MENU_SIZE); 100 sizeMessage->AddInt32("width", 8); 101 sizeMessage->AddInt32("height", 8); 102 sizeMenu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Expert (8x8)"), 103 sizeMessage)); 104 105 menu->AddItem(sizeMenu); 106 107 menu->AddSeparatorItem(); 108 109 menu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("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 score; 223 score << fButtonClicks; 224 BString strAbout = B_TRANSLATE("%app%\n" 225 "\twritten by Ralf Schülke\n" 226 "\tCopyright 2008-2010, Haiku Inc.\n" 227 "\n" 228 "You completed the game in %num% clicks.\n"); 229 230 strAbout.ReplaceFirst("%app%", 231 B_TRANSLATE_SYSTEM_NAME("Pairs")); 232 strAbout.ReplaceFirst("%num%", score); 233 234 BAlert* alert = new BAlert("about", 235 strAbout.String(), 236 B_TRANSLATE("New game"), 237 B_TRANSLATE("Quit game")); 238 239 BTextView* view = alert->TextView(); 240 BFont font; 241 242 view->SetStylable(true); 243 244 view->GetFont(&font); 245 font.SetSize(18); 246 font.SetFace(B_BOLD_FACE); 247 view->SetFontAndColor(0, 248 strlen(B_TRANSLATE_SYSTEM_NAME("Pairs")), &font); 249 view->ResizeToPreferred(); 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