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