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