xref: /haiku/src/apps/pairs/PairsWindow.cpp (revision 46b7da1f4f40f7157d74fc7fb26ff9ec7f2416f2)
169e62e48SStephan Aßmus /*
24c587adeSStephan Aßmus  * Copyright 2008 Ralf Schülke, ralf.schuelke@googlemail.com.
34c587adeSStephan Aßmus  * Copyright 2010 Adam Smith <adamd.smith@utoronto.ca>
4c6b0a589SJohn Scipione  * Copyright 2014 Haiku, Inc. All rights reserved.
5c6b0a589SJohn Scipione  *
6c6b0a589SJohn Scipione  * Distributed under the terms of the MIT License.
7c6b0a589SJohn Scipione  *
8c6b0a589SJohn Scipione  * Authors:
9fdc05529SJohn Scipione  *		Ralf Schülke, ralf.schuelke@googlemail.com
10c6b0a589SJohn Scipione  *		John Scipione, jscipione@gmail.com
11fdc05529SJohn Scipione  *		Adam Smith, adamd.smith@utoronto.ca
1269e62e48SStephan Aßmus  */
1369e62e48SStephan Aßmus 
14c6b0a589SJohn Scipione 
150eb592d7SAxel Dörfler #include "PairsWindow.h"
160eb592d7SAxel Dörfler 
1769e62e48SStephan Aßmus #include <Application.h>
1869e62e48SStephan Aßmus #include <Alert.h>
1984df7867SAdrien Destugues #include <Button.h>
2084df7867SAdrien Destugues #include <Catalog.h>
2197e1b053SJohn Scipione #include <ObjectList.h>
224c587adeSStephan Aßmus #include <Menu.h>
234c587adeSStephan Aßmus #include <MenuBar.h>
244c587adeSStephan Aßmus #include <MenuItem.h>
2584df7867SAdrien Destugues #include <MessageRunner.h>
2669e62e48SStephan Aßmus #include <String.h>
277457ccb4SAugustin Cavalier #include <StringFormat.h>
2884df7867SAdrien Destugues #include <TextView.h>
2969e62e48SStephan Aßmus 
3069e62e48SStephan Aßmus #include "Pairs.h"
3197e1b053SJohn Scipione #include "PairsButton.h"
3269e62e48SStephan Aßmus #include "PairsView.h"
3369e62e48SStephan Aßmus 
344c587adeSStephan Aßmus 
35546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT
36546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "PairsWindow"
3769e62e48SStephan Aßmus 
38c6b0a589SJohn Scipione 
394c587adeSStephan Aßmus const uint32 MENU_NEW					= 'MGnw';
4097e1b053SJohn Scipione const uint32 MENU_DIFFICULTY			= 'MGdf';
414c587adeSStephan Aßmus const uint32 MENU_QUIT					= 'MGqu';
4297e1b053SJohn Scipione const uint32 MENU_ICON_SIZE				= 'MSIs';
4397e1b053SJohn Scipione 
4497e1b053SJohn Scipione const uint32 kMsgPairComparing			= 'pcom';
454c587adeSStephan Aßmus 
464c587adeSStephan Aßmus 
47c6b0a589SJohn Scipione //	#pragma mark - PairsWindow
48c6b0a589SJohn Scipione 
49c6b0a589SJohn Scipione 
PairsWindow()5069e62e48SStephan Aßmus PairsWindow::PairsWindow()
514c587adeSStephan Aßmus 	:
5297e1b053SJohn Scipione 	BWindow(BRect(0, 0, 0, 0), B_TRANSLATE_SYSTEM_NAME("Pairs"),
53b97c5149SJonas Sundström 		B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE
5469e62e48SStephan Aßmus 			| B_NOT_RESIZABLE | B_NOT_ZOOMABLE),
5569e62e48SStephan Aßmus 	fPairComparing(NULL),
5669e62e48SStephan Aßmus 	fIsFirstClick(true),
5769e62e48SStephan Aßmus 	fIsPairsActive(true),
5897e1b053SJohn Scipione 	fPairCardPosition(0),
5997e1b053SJohn Scipione 	fPairCardTmpPosition(0),
6097e1b053SJohn Scipione 	fButtonTmpPosition(0),
6197e1b053SJohn Scipione 	fButtonPosition(0),
6269e62e48SStephan Aßmus 	fButtonClicks(0),
6397e1b053SJohn Scipione 	fFinishPairs(0),
6497e1b053SJohn Scipione 	fIconSizeMenu(NULL)
6569e62e48SStephan Aßmus {
664c587adeSStephan Aßmus 	_MakeMenuBar();
674c587adeSStephan Aßmus 	_MakeGameView(4, 4);
6895087bc5SAxel Dörfler 
6995087bc5SAxel Dörfler 	CenterOnScreen();
7069e62e48SStephan Aßmus }
7169e62e48SStephan Aßmus 
7269e62e48SStephan Aßmus 
~PairsWindow()7369e62e48SStephan Aßmus PairsWindow::~PairsWindow()
7469e62e48SStephan Aßmus {
7569e62e48SStephan Aßmus 	delete fPairComparing;
7669e62e48SStephan Aßmus }
7769e62e48SStephan Aßmus 
7869e62e48SStephan Aßmus 
7969e62e48SStephan Aßmus void
_MakeMenuBar()804c587adeSStephan Aßmus PairsWindow::_MakeMenuBar()
814c587adeSStephan Aßmus {
824c587adeSStephan Aßmus 	fMenuBar = new BMenuBar(BRect(0, 0, 0, 0), "menubar");
834c587adeSStephan Aßmus 	AddChild(fMenuBar);
844c587adeSStephan Aßmus 
8597e1b053SJohn Scipione 	BMenu* gameMenu = new BMenu(B_TRANSLATE("Game"));
8697e1b053SJohn Scipione 	fMenuBar->AddItem(gameMenu);
874c587adeSStephan Aßmus 
884c587adeSStephan Aßmus 	BMenuItem* menuItem;
894c587adeSStephan Aßmus 
9097e1b053SJohn Scipione 	BMenu* newMenu = new BMenu(B_TRANSLATE("New"));
9197e1b053SJohn Scipione 	newMenu->SetRadioMode(true);
924c587adeSStephan Aßmus 
9397e1b053SJohn Scipione 	BMessage* difficultyMessage = new BMessage(MENU_DIFFICULTY);
9497e1b053SJohn Scipione 	difficultyMessage->AddInt32("rows", 4);
9597e1b053SJohn Scipione 	difficultyMessage->AddInt32("cols", 4);
9697e1b053SJohn Scipione 	newMenu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Beginner (4x4)"),
9797e1b053SJohn Scipione 		difficultyMessage));
984c587adeSStephan Aßmus 	menuItem->SetMarked(true);
994c587adeSStephan Aßmus 
10097e1b053SJohn Scipione 	difficultyMessage = new BMessage(MENU_DIFFICULTY);
10197e1b053SJohn Scipione 	difficultyMessage->AddInt32("rows", 6);
10297e1b053SJohn Scipione 	difficultyMessage->AddInt32("cols", 6);
10393c53000SMurai Takashi 	newMenu->AddItem(new BMenuItem(B_TRANSLATE("Intermediate (6x6)"),
10493c53000SMurai Takashi 		difficultyMessage));
1054c587adeSStephan Aßmus 
10697e1b053SJohn Scipione 	difficultyMessage = new BMessage(MENU_DIFFICULTY);
10797e1b053SJohn Scipione 	difficultyMessage->AddInt32("rows", 8);
10897e1b053SJohn Scipione 	difficultyMessage->AddInt32("cols", 8);
10993c53000SMurai Takashi 	newMenu->AddItem(new BMenuItem(B_TRANSLATE("Expert (8x8)"),
11097e1b053SJohn Scipione 		difficultyMessage));
1114c587adeSStephan Aßmus 
11297e1b053SJohn Scipione 	menuItem = new BMenuItem(newMenu, new BMessage(MENU_NEW));
11397e1b053SJohn Scipione 	menuItem->SetShortcut('N', B_COMMAND_KEY);
11497e1b053SJohn Scipione 	gameMenu->AddItem(menuItem);
1154c587adeSStephan Aßmus 
11697e1b053SJohn Scipione 	gameMenu->AddSeparatorItem();
1174c587adeSStephan Aßmus 
118d7093b24SMurai Takashi 	gameMenu->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
1194c587adeSStephan Aßmus 		new BMessage(MENU_QUIT), 'Q'));
12097e1b053SJohn Scipione 
12197e1b053SJohn Scipione 	fIconSizeMenu = new BMenu(B_TRANSLATE("Size"));
12297e1b053SJohn Scipione 	fIconSizeMenu->SetRadioMode(true);
12397e1b053SJohn Scipione 	fMenuBar->AddItem(fIconSizeMenu);
12497e1b053SJohn Scipione 
12597e1b053SJohn Scipione 	BMessage* iconSizeMessage = new BMessage(MENU_ICON_SIZE);
12697e1b053SJohn Scipione 	iconSizeMessage->AddInt32("size", kSmallIconSize);
127d7093b24SMurai Takashi 	fIconSizeMenu->AddItem(new BMenuItem(
12897e1b053SJohn Scipione 		B_TRANSLATE("Small"), iconSizeMessage), 0);
12997e1b053SJohn Scipione 
13097e1b053SJohn Scipione 	iconSizeMessage = new BMessage(MENU_ICON_SIZE);
13197e1b053SJohn Scipione 	iconSizeMessage->AddInt32("size", kMediumIconSize);
13297e1b053SJohn Scipione 	fIconSizeMenu->AddItem(menuItem = new BMenuItem(
13397e1b053SJohn Scipione 		B_TRANSLATE("Medium"), iconSizeMessage), 1);
13497e1b053SJohn Scipione 	menuItem->SetMarked(true);
13597e1b053SJohn Scipione 
13697e1b053SJohn Scipione 	iconSizeMessage = new BMessage(MENU_ICON_SIZE);
13797e1b053SJohn Scipione 	iconSizeMessage->AddInt32("size", kLargeIconSize);
138d7093b24SMurai Takashi 	fIconSizeMenu->AddItem(new BMenuItem(
13997e1b053SJohn Scipione 		B_TRANSLATE("Large"), iconSizeMessage), 2);
1404c587adeSStephan Aßmus }
1414c587adeSStephan Aßmus 
1424c587adeSStephan Aßmus 
1434c587adeSStephan Aßmus void
_MakeGameView(uint8 rows,uint8 cols)14497e1b053SJohn Scipione PairsWindow::_MakeGameView(uint8 rows, uint8 cols)
1454c587adeSStephan Aßmus {
1464c587adeSStephan Aßmus 	BRect viewBounds = Bounds();
1474c587adeSStephan Aßmus 	viewBounds.top = fMenuBar->Bounds().Height() + 1;
1484c587adeSStephan Aßmus 
14997e1b053SJohn Scipione 	uint8 iconSize;
15097e1b053SJohn Scipione 	BMenuItem* marked = fIconSizeMenu->FindMarked();
15197e1b053SJohn Scipione 	if (marked != NULL) {
15297e1b053SJohn Scipione 		switch (fIconSizeMenu->IndexOf(marked)) {
15397e1b053SJohn Scipione 			case 0:
15497e1b053SJohn Scipione 				iconSize = kSmallIconSize;
15597e1b053SJohn Scipione 				break;
15697e1b053SJohn Scipione 
15797e1b053SJohn Scipione 			case 2:
15897e1b053SJohn Scipione 				iconSize = kLargeIconSize;
15997e1b053SJohn Scipione 				break;
16097e1b053SJohn Scipione 
16197e1b053SJohn Scipione 			case 1:
16297e1b053SJohn Scipione 			default:
16397e1b053SJohn Scipione 				iconSize = kMediumIconSize;
16497e1b053SJohn Scipione 		}
16597e1b053SJohn Scipione 	} else {
16697e1b053SJohn Scipione 		iconSize = kMediumIconSize;
16797e1b053SJohn Scipione 		fIconSizeMenu->ItemAt(1)->SetMarked(true);
16897e1b053SJohn Scipione 	}
16997e1b053SJohn Scipione 
17097e1b053SJohn Scipione 	fPairsView = new PairsView(viewBounds, "PairsView", rows, cols, iconSize);
1714c587adeSStephan Aßmus 	AddChild(fPairsView);
17297e1b053SJohn Scipione 	_ResizeWindow(rows, cols);
1734c587adeSStephan Aßmus }
1744c587adeSStephan Aßmus 
1754c587adeSStephan Aßmus 
1764c587adeSStephan Aßmus void
NewGame()1774c587adeSStephan Aßmus PairsWindow::NewGame()
1784c587adeSStephan Aßmus {
1794c587adeSStephan Aßmus 	fButtonClicks = 0;
1804c587adeSStephan Aßmus 	fFinishPairs = 0;
181*2398586dSDale Cieslak 	fIsFirstClick = true;
1824c587adeSStephan Aßmus 	fPairsView->CreateGameBoard();
1834c587adeSStephan Aßmus }
1844c587adeSStephan Aßmus 
1854c587adeSStephan Aßmus 
1864c587adeSStephan Aßmus void
SetGameSize(uint8 rows,uint8 cols)18797e1b053SJohn Scipione PairsWindow::SetGameSize(uint8 rows, uint8 cols)
1884c587adeSStephan Aßmus {
1894c587adeSStephan Aßmus 	RemoveChild(fPairsView);
1904c587adeSStephan Aßmus 	delete fPairsView;
19197e1b053SJohn Scipione 
19297e1b053SJohn Scipione 	_MakeGameView(rows, cols);
1934c587adeSStephan Aßmus 	NewGame();
1944c587adeSStephan Aßmus }
1954c587adeSStephan Aßmus 
1964c587adeSStephan Aßmus 
1974c587adeSStephan Aßmus void
MessageReceived(BMessage * message)19869e62e48SStephan Aßmus PairsWindow::MessageReceived(BMessage* message)
19969e62e48SStephan Aßmus {
20069e62e48SStephan Aßmus 	switch (message->what) {
2014c587adeSStephan Aßmus 		case MENU_NEW:
2024c587adeSStephan Aßmus 			NewGame();
2034c587adeSStephan Aßmus 			break;
204c6b0a589SJohn Scipione 
20597e1b053SJohn Scipione 		case MENU_DIFFICULTY:
2064c587adeSStephan Aßmus 		{
20797e1b053SJohn Scipione 			int32 rows;
20897e1b053SJohn Scipione 			int32 cols;
20997e1b053SJohn Scipione 			if (message->FindInt32("rows", &rows) == B_OK
21097e1b053SJohn Scipione 				&& message->FindInt32("cols", &cols) == B_OK) {
21197e1b053SJohn Scipione 				SetGameSize(rows, cols);
2124c587adeSStephan Aßmus 			}
2134c587adeSStephan Aßmus 			break;
2144c587adeSStephan Aßmus 		}
215c6b0a589SJohn Scipione 
21697e1b053SJohn Scipione 		case MENU_ICON_SIZE:
21797e1b053SJohn Scipione 		{
21897e1b053SJohn Scipione 			int32 size;
21997e1b053SJohn Scipione 			if (message->FindInt32("size", &size) == B_OK) {
22097e1b053SJohn Scipione 				fPairsView->SetIconSize(size);
22197e1b053SJohn Scipione 				_ResizeWindow(fPairsView->Rows(), fPairsView->Cols());
22297e1b053SJohn Scipione 			}
22397e1b053SJohn Scipione 
22497e1b053SJohn Scipione 			break;
22597e1b053SJohn Scipione 		}
22697e1b053SJohn Scipione 
2274c587adeSStephan Aßmus 		case MENU_QUIT:
2284c587adeSStephan Aßmus 			be_app->PostMessage(B_QUIT_REQUESTED);
2294c587adeSStephan Aßmus 			break;
230c6b0a589SJohn Scipione 
23169e62e48SStephan Aßmus 		case kMsgCardButton:
23297e1b053SJohn Scipione 		{
23397e1b053SJohn Scipione 			if (!fIsPairsActive)
23469e62e48SStephan Aßmus 				break;
23569e62e48SStephan Aßmus 
23697e1b053SJohn Scipione 			int32 buttonNumber;
23797e1b053SJohn Scipione 			if (message->FindInt32("button number", &buttonNumber) != B_OK)
23897e1b053SJohn Scipione 				break;
23997e1b053SJohn Scipione 
24097e1b053SJohn Scipione 			BObjectList<PairsButton>* pairsButtonList
24197e1b053SJohn Scipione 				= fPairsView->PairsButtonList();
24297e1b053SJohn Scipione 			if (pairsButtonList == NULL)
24397e1b053SJohn Scipione 				break;
24497e1b053SJohn Scipione 
24597e1b053SJohn Scipione 			// look at what icon is behind a button
24697e1b053SJohn Scipione 			int32 buttonCount = pairsButtonList->CountItems();
24797e1b053SJohn Scipione 			for (int32 i = 0; i < buttonCount; i++) {
24897e1b053SJohn Scipione 				int32 iconPosition = fPairsView->GetIconPosition(i);
24997e1b053SJohn Scipione 				if (iconPosition == buttonNumber) {
25097e1b053SJohn Scipione 					fPairCardPosition = i % (buttonCount / 2);
25197e1b053SJohn Scipione 					fButtonPosition = iconPosition;
25269e62e48SStephan Aßmus 					break;
25369e62e48SStephan Aßmus 				}
25469e62e48SStephan Aßmus 			}
25569e62e48SStephan Aßmus 
25669e62e48SStephan Aßmus 			// gameplay
25797e1b053SJohn Scipione 			fButtonClicks++;
25897e1b053SJohn Scipione 			pairsButtonList->ItemAt(fButtonPosition)->Hide();
25969e62e48SStephan Aßmus 
26069e62e48SStephan Aßmus 			if (fIsFirstClick) {
26197e1b053SJohn Scipione 				fPairCardTmpPosition = fPairCardPosition;
26297e1b053SJohn Scipione 				fButtonTmpPosition = fButtonPosition;
26369e62e48SStephan Aßmus 			} else {
26469e62e48SStephan Aßmus 				delete fPairComparing;
26569e62e48SStephan Aßmus 					// message of message runner might not have arrived
26669e62e48SStephan Aßmus 					// yet, so it is deleted here to prevent any leaking
26769e62e48SStephan Aßmus 					// just in case
2684a89dc95SAlexandre Deckner 				BMessage message(kMsgPairComparing);
26969e62e48SStephan Aßmus 				fPairComparing = new BMessageRunner(BMessenger(this),
2704a89dc95SAlexandre Deckner 					&message,  5 * 100000L, 1);
27169e62e48SStephan Aßmus 				fIsPairsActive = false;
27269e62e48SStephan Aßmus 			}
27369e62e48SStephan Aßmus 
27469e62e48SStephan Aßmus 			fIsFirstClick = !fIsFirstClick;
27569e62e48SStephan Aßmus 			break;
27697e1b053SJohn Scipione 		}
27769e62e48SStephan Aßmus 
27869e62e48SStephan Aßmus 		case kMsgPairComparing:
27997e1b053SJohn Scipione 		{
28097e1b053SJohn Scipione 			BObjectList<PairsButton>* pairsButtonList
28197e1b053SJohn Scipione 				= fPairsView->PairsButtonList();
28297e1b053SJohn Scipione 			if (pairsButtonList == NULL)
28397e1b053SJohn Scipione 				break;
28497e1b053SJohn Scipione 
28569e62e48SStephan Aßmus 			delete fPairComparing;
28669e62e48SStephan Aßmus 			fPairComparing = NULL;
28769e62e48SStephan Aßmus 
28869e62e48SStephan Aßmus 			fIsPairsActive = true;
28969e62e48SStephan Aßmus 
29097e1b053SJohn Scipione 			if (fPairCardPosition == fPairCardTmpPosition)
29169e62e48SStephan Aßmus 				fFinishPairs++;
2924c587adeSStephan Aßmus 			else {
29397e1b053SJohn Scipione 				pairsButtonList->ItemAt(fButtonPosition)->Show();
29497e1b053SJohn Scipione 				pairsButtonList->ItemAt(fButtonTmpPosition)->Show();
29569e62e48SStephan Aßmus 			}
29669e62e48SStephan Aßmus 
29769e62e48SStephan Aßmus 			// game end and results
29897e1b053SJohn Scipione 			if (fFinishPairs == pairsButtonList->CountItems() / 2) {
29971302e7cSJonas Sundström 				BString strAbout = B_TRANSLATE("%app%\n"
3000b9dd3b0SAdrien Destugues 					"\twritten by Ralf Schülke\n"
3010b9dd3b0SAdrien Destugues 					"\tCopyright 2008-2010, Haiku Inc.\n"
30253382a8aSAdrien Destugues 					"\n");
3030b9dd3b0SAdrien Destugues 
30471302e7cSJonas Sundström 				strAbout.ReplaceFirst("%app%",
305560ff447SJonas Sundström 					B_TRANSLATE_SYSTEM_NAME("Pairs"));
30653382a8aSAdrien Destugues 
30753382a8aSAdrien Destugues 				// Note: in english the singular form is never used, but other
30853382a8aSAdrien Destugues 				// languages behave differently.
3097457ccb4SAugustin Cavalier 				static BStringFormat format(B_TRANSLATE(
31053382a8aSAdrien Destugues 					"You completed the game in "
311961fdd8cSAdrien Destugues 					"{0, plural, one{# click} other{# clicks}}.\n"));
312961fdd8cSAdrien Destugues 				format.Format(strAbout, fButtonClicks);
31369e62e48SStephan Aßmus 
31499d126bdSMatt Madia 				BAlert* alert = new BAlert("about",
3158eff03f5SOliver Tappe 					strAbout.String(),
31699d126bdSMatt Madia 					B_TRANSLATE("New game"),
31799d126bdSMatt Madia 					B_TRANSLATE("Quit game"));
31869e62e48SStephan Aßmus 
31969e62e48SStephan Aßmus 				BTextView* view = alert->TextView();
32069e62e48SStephan Aßmus 				BFont font;
32169e62e48SStephan Aßmus 
32269e62e48SStephan Aßmus 				view->SetStylable(true);
32369e62e48SStephan Aßmus 
32469e62e48SStephan Aßmus 				view->GetFont(&font);
32569e62e48SStephan Aßmus 				font.SetSize(18);
32669e62e48SStephan Aßmus 				font.SetFace(B_BOLD_FACE);
32771302e7cSJonas Sundström 				view->SetFontAndColor(0,
328560ff447SJonas Sundström 					strlen(B_TRANSLATE_SYSTEM_NAME("Pairs")), &font);
32969e62e48SStephan Aßmus 				view->ResizeToPreferred();
3305b264395SAdrien Destugues 				alert->SetShortcut(0, B_ESCAPE);
33169e62e48SStephan Aßmus 
332c6b0a589SJohn Scipione 				if (alert->Go() == 0)
3334c587adeSStephan Aßmus 					NewGame();
334c6b0a589SJohn Scipione 				else
33569e62e48SStephan Aßmus 					be_app->PostMessage(B_QUIT_REQUESTED);
33669e62e48SStephan Aßmus 			}
33769e62e48SStephan Aßmus 			break;
33897e1b053SJohn Scipione 		}
33969e62e48SStephan Aßmus 
34069e62e48SStephan Aßmus 		default:
34169e62e48SStephan Aßmus 			BWindow::MessageReceived(message);
34269e62e48SStephan Aßmus 	}
34369e62e48SStephan Aßmus }
34497e1b053SJohn Scipione 
34597e1b053SJohn Scipione 
34697e1b053SJohn Scipione //	#pragma mark - PairsWindow private methods
34797e1b053SJohn Scipione 
34897e1b053SJohn Scipione 
34997e1b053SJohn Scipione void
_ResizeWindow(uint8 rows,uint8 cols)35097e1b053SJohn Scipione PairsWindow::_ResizeWindow(uint8 rows, uint8 cols)
35197e1b053SJohn Scipione {
35297e1b053SJohn Scipione 	int32 iconSize = fPairsView->IconSize();
35397e1b053SJohn Scipione 	int32 spacing = fPairsView->Spacing();
35497e1b053SJohn Scipione 
35597e1b053SJohn Scipione 	ResizeTo((iconSize + spacing) * rows + spacing,
35697e1b053SJohn Scipione 		(iconSize + spacing) * cols + spacing + fMenuBar->Bounds().Height());
35797e1b053SJohn Scipione }
358