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