xref: /haiku/src/apps/pairs/PairsWindow.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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