/*
* Copyright 2008 Ralf Schülke, ralf.schuelke@googlemail.com.
* Copyright 2010 Adam Smith <adamd.smith@utoronto.ca>
* Copyright 2014 Haiku, Inc. All rights reserved.
*
* Distributed under the terms of the MIT License.
*
* Authors:
* Ralf Schülke, ralf.schuelke@googlemail.com
* John Scipione, jscipione@gmail.com
* Adam Smith, adamd.smith@utoronto.ca
*/
#include "PairsWindow.h"
#include <Application.h>
#include <Alert.h>
#include <Button.h>
#include <Catalog.h>
#include <ObjectList.h>
#include <Menu.h>
#include <MenuBar.h>
#include <MenuItem.h>
#include <MessageRunner.h>
#include <String.h>
#include <StringFormat.h>
#include <TextView.h>
#include "Pairs.h"
#include "PairsButton.h"
#include "PairsView.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "PairsWindow"
const uint32 MENU_NEW = 'MGnw';
const uint32 MENU_DIFFICULTY = 'MGdf';
const uint32 MENU_QUIT = 'MGqu';
const uint32 MENU_ICON_SIZE = 'MSIs';
const uint32 kMsgPairComparing = 'pcom';
// #pragma mark - PairsWindow
PairsWindow::PairsWindow()
:
BWindow(BRect(0, 0, 0, 0), B_TRANSLATE_SYSTEM_NAME("Pairs"),
B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE
| B_NOT_RESIZABLE | B_NOT_ZOOMABLE),
fPairComparing(NULL),
fIsFirstClick(true),
fIsPairsActive(true),
fPairCardPosition(0),
fPairCardTmpPosition(0),
fButtonTmpPosition(0),
fButtonPosition(0),
fButtonClicks(0),
fFinishPairs(0),
fIconSizeMenu(NULL)
{
_MakeMenuBar();
_MakeGameView(4, 4);
CenterOnScreen();
}
PairsWindow::~PairsWindow()
{
delete fPairComparing;
}
void
PairsWindow::_MakeMenuBar()
{
fMenuBar = new BMenuBar(BRect(0, 0, 0, 0), "menubar");
AddChild(fMenuBar);
BMenu* gameMenu = new BMenu(B_TRANSLATE("Game"));
fMenuBar->AddItem(gameMenu);
BMenuItem* menuItem;
BMenu* newMenu = new BMenu(B_TRANSLATE("New"));
newMenu->SetRadioMode(true);
BMessage* difficultyMessage = new BMessage(MENU_DIFFICULTY);
difficultyMessage->AddInt32("rows", 4);
difficultyMessage->AddInt32("cols", 4);
newMenu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Beginner (4x4)"),
difficultyMessage));
menuItem->SetMarked(true);
difficultyMessage = new BMessage(MENU_DIFFICULTY);
difficultyMessage->AddInt32("rows", 6);
difficultyMessage->AddInt32("cols", 6);
newMenu->AddItem(menuItem = new BMenuItem(
B_TRANSLATE("Intermediate (6x6)"), difficultyMessage));
difficultyMessage = new BMessage(MENU_DIFFICULTY);
difficultyMessage->AddInt32("rows", 8);
difficultyMessage->AddInt32("cols", 8);
newMenu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Expert (8x8)"),
difficultyMessage));
menuItem = new BMenuItem(newMenu, new BMessage(MENU_NEW));
menuItem->SetShortcut('N', B_COMMAND_KEY);
gameMenu->AddItem(menuItem);
gameMenu->AddSeparatorItem();
gameMenu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Quit"),
new BMessage(MENU_QUIT), 'Q'));
fIconSizeMenu = new BMenu(B_TRANSLATE("Size"));
fIconSizeMenu->SetRadioMode(true);
fMenuBar->AddItem(fIconSizeMenu);
BMessage* iconSizeMessage = new BMessage(MENU_ICON_SIZE);
iconSizeMessage->AddInt32("size", kSmallIconSize);
fIconSizeMenu->AddItem(menuItem = new BMenuItem(
B_TRANSLATE("Small"), iconSizeMessage), 0);
iconSizeMessage = new BMessage(MENU_ICON_SIZE);
iconSizeMessage->AddInt32("size", kMediumIconSize);
fIconSizeMenu->AddItem(menuItem = new BMenuItem(
B_TRANSLATE("Medium"), iconSizeMessage), 1);
menuItem->SetMarked(true);
iconSizeMessage = new BMessage(MENU_ICON_SIZE);
iconSizeMessage->AddInt32("size", kLargeIconSize);
fIconSizeMenu->AddItem(menuItem = new BMenuItem(
B_TRANSLATE("Large"), iconSizeMessage), 2);
}
void
PairsWindow::_MakeGameView(uint8 rows, uint8 cols)
{
BRect viewBounds = Bounds();
viewBounds.top = fMenuBar->Bounds().Height() + 1;
uint8 iconSize;
BMenuItem* marked = fIconSizeMenu->FindMarked();
if (marked != NULL) {
switch (fIconSizeMenu->IndexOf(marked)) {
case 0:
iconSize = kSmallIconSize;
break;
case 2:
iconSize = kLargeIconSize;
break;
case 1:
default:
iconSize = kMediumIconSize;
}
} else {
iconSize = kMediumIconSize;
fIconSizeMenu->ItemAt(1)->SetMarked(true);
}
fPairsView = new PairsView(viewBounds, "PairsView", rows, cols, iconSize);
AddChild(fPairsView);
_ResizeWindow(rows, cols);
}
void
PairsWindow::NewGame()
{
fButtonClicks = 0;
fFinishPairs = 0;
fPairsView->CreateGameBoard();
}
void
PairsWindow::SetGameSize(uint8 rows, uint8 cols)
{
RemoveChild(fPairsView);
delete fPairsView;
_MakeGameView(rows, cols);
NewGame();
}
void
PairsWindow::MessageReceived(BMessage* message)
{
switch (message->what) {
case MENU_NEW:
NewGame();
break;
case MENU_DIFFICULTY:
{
int32 rows;
int32 cols;
if (message->FindInt32("rows", &rows) == B_OK
&& message->FindInt32("cols", &cols) == B_OK) {
SetGameSize(rows, cols);
}
break;
}
case MENU_ICON_SIZE:
{
int32 size;
if (message->FindInt32("size", &size) == B_OK) {
fPairsView->SetIconSize(size);
_ResizeWindow(fPairsView->Rows(), fPairsView->Cols());
}
break;
}
case MENU_QUIT:
be_app->PostMessage(B_QUIT_REQUESTED);
break;
case kMsgCardButton:
{
if (!fIsPairsActive)
break;
int32 buttonNumber;
if (message->FindInt32("button number", &buttonNumber) != B_OK)
break;
BObjectList<PairsButton>* pairsButtonList
= fPairsView->PairsButtonList();
if (pairsButtonList == NULL)
break;
// look at what icon is behind a button
int32 buttonCount = pairsButtonList->CountItems();
for (int32 i = 0; i < buttonCount; i++) {
int32 iconPosition = fPairsView->GetIconPosition(i);
if (iconPosition == buttonNumber) {
fPairCardPosition = i % (buttonCount / 2);
fButtonPosition = iconPosition;
break;
}
}
// gameplay
fButtonClicks++;
pairsButtonList->ItemAt(fButtonPosition)->Hide();
if (fIsFirstClick) {
fPairCardTmpPosition = fPairCardPosition;
fButtonTmpPosition = fButtonPosition;
} else {
delete fPairComparing;
// message of message runner might not have arrived
// yet, so it is deleted here to prevent any leaking
// just in case
BMessage message(kMsgPairComparing);
fPairComparing = new BMessageRunner(BMessenger(this),
&message, 5 * 100000L, 1);
fIsPairsActive = false;
}
fIsFirstClick = !fIsFirstClick;
break;
}
case kMsgPairComparing:
{
BObjectList<PairsButton>* pairsButtonList
= fPairsView->PairsButtonList();
if (pairsButtonList == NULL)
break;
delete fPairComparing;
fPairComparing = NULL;
fIsPairsActive = true;
if (fPairCardPosition == fPairCardTmpPosition)
fFinishPairs++;
else {
pairsButtonList->ItemAt(fButtonPosition)->Show();
pairsButtonList->ItemAt(fButtonTmpPosition)->Show();
}
// game end and results
if (fFinishPairs == pairsButtonList->CountItems() / 2) {
BString strAbout = B_TRANSLATE("%app%\n"
"\twritten by Ralf Schülke\n"
"\tCopyright 2008-2010, Haiku Inc.\n"
"\n");
strAbout.ReplaceFirst("%app%",
B_TRANSLATE_SYSTEM_NAME("Pairs"));
// Note: in english the singular form is never used, but other
// languages behave differently.
static BStringFormat format(B_TRANSLATE(
"You completed the game in "
"{0, plural, one{# click} other{# clicks}}.\n"));
format.Format(strAbout, fButtonClicks);
BAlert* alert = new BAlert("about",
strAbout.String(),
B_TRANSLATE("New game"),
B_TRANSLATE("Quit game"));
BTextView* view = alert->TextView();
BFont font;
view->SetStylable(true);
view->GetFont(&font);
font.SetSize(18);
font.SetFace(B_BOLD_FACE);
view->SetFontAndColor(0,
strlen(B_TRANSLATE_SYSTEM_NAME("Pairs")), &font);
view->ResizeToPreferred();
alert->SetShortcut(0, B_ESCAPE);
if (alert->Go() == 0)
NewGame();
else
be_app->PostMessage(B_QUIT_REQUESTED);
}
break;
}
default:
BWindow::MessageReceived(message);
}
}
// #pragma mark - PairsWindow private methods
void
PairsWindow::_ResizeWindow(uint8 rows, uint8 cols)
{
int32 iconSize = fPairsView->IconSize();
int32 spacing = fPairsView->Spacing();
ResizeTo((iconSize + spacing) * rows + spacing,
(iconSize + spacing) * cols + spacing + fMenuBar->Bounds().Height());
}
↑ V773 Visibility scope of the 'alert' pointer was exited without releasing the memory. A memory leak is possible.