diff --git a/src/apps/pairs/Jamfile b/src/apps/pairs/Jamfile index 21541a51c4..f4d8698b13 100644 --- a/src/apps/pairs/Jamfile +++ b/src/apps/pairs/Jamfile @@ -2,9 +2,9 @@ SubDir HAIKU_TOP src apps pairs ; Application Pairs : Pairs.cpp - PairsWindow.cpp + PairsButton.cpp PairsView.cpp - PairsTopButton.cpp + PairsWindow.cpp : be localestub $(TARGET_LIBSTDC++) : Pairs.rdef @@ -13,6 +13,7 @@ Application Pairs : DoCatalogs Pairs : x-vnd.Haiku-Pairs : + Pairs.cpp PairsView.cpp PairsWindow.cpp ; diff --git a/src/apps/pairs/Pairs.cpp b/src/apps/pairs/Pairs.cpp index 561f0fd178..27cb8ce94d 100644 --- a/src/apps/pairs/Pairs.cpp +++ b/src/apps/pairs/Pairs.cpp @@ -13,14 +13,22 @@ #include -#include +#include #include +#include #include "PairsWindow.h" +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "Pairs" + + const char* kSignature = "application/x-vnd.Haiku-Pairs"; +static const size_t kMinIconCount = 64; +static const size_t kMaxIconCount = 384; + // #pragma mark - Pairs @@ -30,6 +38,7 @@ Pairs::Pairs() BApplication(kSignature), fWindow(NULL) { + _GetVectorIcons(); } @@ -60,6 +69,92 @@ Pairs::MessageReceived(BMessage* message) } +bool +Pairs::QuitRequested() +{ + // delete vector icons + for (IconMap::iterator iter = fIconMap.begin(); iter != fIconMap.end(); + ++iter) { + delete fIconMap[iter->first]; + } + + return true; +} + + +// #pragma mark - Pairs private methods + + +void +Pairs::_GetVectorIcons() +{ + // Load vector icons from the MIME type database and add a pointer to them + // into a std::map keyed by a generated hash. + + BMessage types; + if (BMimeType::GetInstalledTypes("application", &types) != B_OK) + return; + + const char* type; + for (int32 i = 0; types.FindString("types", i, &type) == B_OK; i++) { + BMimeType mimeType(type); + if (mimeType.InitCheck() != B_OK) + continue; + + uint8* data; + size_t size; + + if (mimeType.GetIcon(&data, &size) != B_OK) { + // didn't find an icon + continue; + } + + size_t hash = 0xdeadbeef; + for (size_t i = 0; i < size; i++) + hash = 31 * hash + data[i]; + + if (fIconMap.find(hash) != fIconMap.end()) { + // key has already been added to the map + delete[] data; + continue; + } + + vector_icon* icon = (vector_icon*)malloc(sizeof(vector_icon)); + if (icon == NULL) { + delete[] data; + free(icon); + continue; + } + + icon->data = data; + icon->size = size; + + // found a vector icon, add it to the list + fIconMap[hash] = icon; + if (fIconMap.size() >= kMaxIconCount) { + // this is enough to choose from, stop eating memory... + return; + } + } + + if (fIconMap.size() < kMinIconCount) { + char buffer[512]; + snprintf(buffer, sizeof(buffer), + B_TRANSLATE_COMMENT("Pairs did not find enough vector icons " + "to start; it needs at least %zu, found %zu.\n", + "Don't translate \"%zu\", but make sure to keep them."), + kMinIconCount, fIconMap.size()); + BString messageString(buffer); + BAlert* alert = new BAlert("Fatal", messageString.String(), + B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_FROM_WIDEST, + B_STOP_ALERT); + alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); + alert->Go(); + exit(1); + } +} + + // #pragma mark - main diff --git a/src/apps/pairs/Pairs.h b/src/apps/pairs/Pairs.h index 58d8309791..222c328396 100644 --- a/src/apps/pairs/Pairs.h +++ b/src/apps/pairs/Pairs.h @@ -11,27 +11,45 @@ #define PAIRS_H +#include + #include -#include extern const char* kSignature; +struct vector_icon { + uint8* data; + size_t size; +}; + + +class BBitmap; class BMessage; class PairsWindow; + +typedef std::map IconMap; + + class Pairs : public BApplication { public: - Pairs(); - virtual ~Pairs(); + Pairs(); + virtual ~Pairs(); - virtual void ReadyToRun(); - virtual void RefsReceived(BMessage* message); - virtual void MessageReceived(BMessage* message); + virtual void ReadyToRun(); + virtual void RefsReceived(BMessage* message); + virtual void MessageReceived(BMessage* message); + virtual bool QuitRequested(); + + IconMap GetIconMap() const { return fIconMap; }; private: - PairsWindow* fWindow; + void _GetVectorIcons(); + + PairsWindow* fWindow; + IconMap fIconMap; }; diff --git a/src/apps/pairs/PairsButton.cpp b/src/apps/pairs/PairsButton.cpp new file mode 100644 index 0000000000..c020a7a74b --- /dev/null +++ b/src/apps/pairs/PairsButton.cpp @@ -0,0 +1,28 @@ +/* + * Copyright 2008 Ralf Schülke, ralf.schuelke@googlemail.com. + * Copyright 2014 Haiku, Inc. All rights reserved. + * + * Distributed under the terms of the MIT License. + * + * Authors: + * John Scipione, jscipione@gmail.com + */ + + +#include "PairsButton.h" + + +// #pragma mark - PairsButton + + +PairsButton::PairsButton(int32 x, int32 y, int32 size, BMessage* message) + : + BButton(BRect(x, y, x + size, y + size), "pairs button", "?", message) +{ + SetFontSize(size - 15); +} + + +PairsButton::~PairsButton() +{ +} diff --git a/src/apps/pairs/PairsTopButton.h b/src/apps/pairs/PairsButton.h similarity index 50% rename from src/apps/pairs/PairsTopButton.h rename to src/apps/pairs/PairsButton.h index 32632d1d4c..eb59a58df3 100644 --- a/src/apps/pairs/PairsTopButton.h +++ b/src/apps/pairs/PairsButton.h @@ -7,17 +7,19 @@ * Authors: * John Scipione, jscipione@gmail.com */ -#ifndef PAIRS_TOP_BUTTON_H -#define PAIRS_TOP_BUTTON_H +#ifndef PAIRS_BUTTON_H +#define PAIRS_BUTTON_H -#include -class BButton; +#include -class TopButton : public BButton { + +class PairsButton : public BButton { public: - TopButton(int x, int y, BMessage* message); - virtual ~TopButton(); + PairsButton(int32 x, int32 y, int32 size, + BMessage* message); + virtual ~PairsButton(); }; -#endif // PAIRS_TOP_BUTTON_H + +#endif // PAIRS_BUTTON_H diff --git a/src/apps/pairs/PairsGlobal.h b/src/apps/pairs/PairsGlobal.h deleted file mode 100644 index af97f6ca3e..0000000000 --- a/src/apps/pairs/PairsGlobal.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2008 Ralf Schülke, ralf.schuelke@googlemail.com. - * Copyright 2014 Haiku, Inc. All rights reserved. - * - * Distributed under the terms of the MIT License. - * - * Authors: - * John Scipione, jscipione@gmail.com - */ -#ifndef PAIRS_GLOBAL_H -#define PAIRS_GLOBAL_H - - -#include - - -const uint32 kMsgCardButton = 'card'; -const uint32 kMsgPairComparing = 'pcom'; -const int kBitmapSize = 64; -const int kSpaceSize = 10; - - -#endif // PAIRS_GLOBAL_H diff --git a/src/apps/pairs/PairsTopButton.cpp b/src/apps/pairs/PairsTopButton.cpp deleted file mode 100644 index f066c0cfca..0000000000 --- a/src/apps/pairs/PairsTopButton.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2008 Ralf Schülke, ralf.schuelke@googlemail.com. - * Copyright 2014 Haiku, Inc. All rights reserved. - * - * Distributed under the terms of the MIT License. - * - * Authors: - * John Scipione, jscipione@gmail.com - */ - -#include -#include - -#include - -#include "PairsTopButton.h" -#include "PairsGlobal.h" - - -TopButton::TopButton(int x, int y, BMessage* message) - : BButton(BRect(x, y, x + kBitmapSize, y + kBitmapSize), "top_button", - "?", message) -{ - SetFontSize(54); -} - - -TopButton::~TopButton() -{ -} diff --git a/src/apps/pairs/PairsView.cpp b/src/apps/pairs/PairsView.cpp index 2e1ba0e51b..1ac37c91b4 100644 --- a/src/apps/pairs/PairsView.cpp +++ b/src/apps/pairs/PairsView.cpp @@ -12,39 +12,44 @@ #include "PairsView.h" -#include -#include -#include - -#include #include #include #include +#include #include -#include -#include -#include #include -#include -#include -#include -#include +#include +#include #include "Pairs.h" -#include "PairsGlobal.h" -#include "PairsTopButton.h" +#include "PairsButton.h" -PairsView::PairsView(BRect frame, const char* name, int width, int height, - uint32 resizingMode) + +#undef B_TRANSLATION_CONTEXT +#define B_TRANSLATION_CONTEXT "PairsView" + + +// #pragma mark - PairsView + + +PairsView::PairsView(BRect frame, const char* name, uint8 rows, uint8 cols, + uint8 iconSize) : - BView(frame, name, resizingMode, B_WILL_DRAW), - fWidth(width), - fHeight(height), - fNumOfCards(width * height), - fRandPos(new int[fNumOfCards]), - fPosX(new int[fNumOfCards]), - fPosY(new int[fNumOfCards]) + BView(frame, name, B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS), + fRows(rows), + fCols(cols), + fIconSize(iconSize), + fButtonsCount(rows * cols), + fCardsCount(fButtonsCount / 2), + fPairsButtonList(new BObjectList(fButtonsCount)), + fSmallBitmapsList(new BObjectList(fCardsCount)), + fMediumBitmapsList(new BObjectList(fCardsCount)), + fLargeBitmapsList(new BObjectList(fCardsCount)), + fRandomPosition(new int32[fButtonsCount]), + fPositionX(new int32[fButtonsCount]), + fPositionY(new int32[fButtonsCount]) { + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); CreateGameBoard(); _SetPairsBoard(); } @@ -54,209 +59,211 @@ void PairsView::CreateGameBoard() { // Show hidden buttons - for (int32 i = 0; i < CountChildren(); i++) { + int32 childrenCount = CountChildren(); + for (int32 i = 0; i < childrenCount; i++) { BView* child = ChildAt(i); if (child->IsHidden()) child->Show(); } - _GenerateCardPos(); + _GenerateCardPositions(); } PairsView::~PairsView() { - for (int i = 0; i < fCardBitmaps.CountItems(); i++) - delete ((BBitmap*)fCardBitmaps.ItemAt(i)); - - for (int i = 0; i < fDeckCard.CountItems(); i++) - delete ((TopButton*)fDeckCard.ItemAt(i)); - - delete fRandPos; - delete fPosX; - delete fPosY; + delete fSmallBitmapsList; + delete fMediumBitmapsList; + delete fLargeBitmapsList; + delete fPairsButtonList; + delete fRandomPosition; + delete fPositionX; + delete fPositionY; } void PairsView::AttachedToWindow() { + for (int32 i = 0; i < fButtonsCount; i++) { + PairsButton* button = fPairsButtonList->ItemAt(i); + if (button != NULL) + button->SetTarget(Window()); + } + MakeFocus(true); -} - - -bool -PairsView::_HasBitmap(BList& bitmaps, BBitmap* bitmap) -{ - // TODO: if this takes too long, we could build a hash value for each - // bitmap in a separate list - for (int32 i = bitmaps.CountItems(); i-- > 0;) { - BBitmap* item = (BBitmap*)bitmaps.ItemAtFast(i); - if (!memcmp(item->Bits(), bitmap->Bits(), item->BitsLength())) - return true; - } - - return false; -} - -#undef B_TRANSLATION_CONTEXT -#define B_TRANSLATION_CONTEXT "PairsView" - -void -PairsView::_ReadRandomIcons() -{ - // TODO: maybe read the icons only once at startup - - // clean out any previous icons - for (int i = 0; i < fCardBitmaps.CountItems(); i++) - delete ((BBitmap*)fCardBitmaps.ItemAt(i)); - - fCardBitmaps.MakeEmpty(); - - BDirectory appsDirectory; - BDirectory prefsDirectory; - - BPath path; - if (find_directory(B_BEOS_APPS_DIRECTORY, &path) == B_OK) - appsDirectory.SetTo(path.Path()); - if (find_directory(B_BEOS_PREFERENCES_DIRECTORY, &path) == B_OK) - prefsDirectory.SetTo(path.Path()); - - // read vector icons from apps and prefs folder and put them - // into a BList as BBitmaps - BList bitmaps; - - BEntry entry; - while (appsDirectory.GetNextEntry(&entry) == B_OK - || prefsDirectory.GetNextEntry(&entry) == B_OK) { - - BNode node(&entry); - BNodeInfo nodeInfo(&node); - - if (nodeInfo.InitCheck() < B_OK) - continue; - - uint8* data; - size_t size; - type_code type; - - if (nodeInfo.GetIcon(&data, &size, &type) < B_OK) - continue; - - if (type != B_VECTOR_ICON_TYPE) { - delete[] data; - continue; - } - - BBitmap* bitmap = new BBitmap( - BRect(0, 0, kBitmapSize - 1, kBitmapSize - 1), 0, B_RGBA32); - if (BIconUtils::GetVectorIcon(data, size, bitmap) < B_OK) { - delete[] data; - delete bitmap; - continue; - } - - delete[] data; - - if (_HasBitmap(bitmaps, bitmap) || !bitmaps.AddItem(bitmap)) - delete bitmap; - else if (bitmaps.CountItems() >= 128) { - // this is enough to choose from, stop eating memory... - break; - } - } - - // pick random bitmaps from the ones we got in the list - srand((unsigned)time(0)); - - for (int i = 0; i < fNumOfCards / 2; i++) { - int32 index = rand() % bitmaps.CountItems(); - BBitmap* bitmap = ((BBitmap*)bitmaps.RemoveItem(index)); - if (bitmap == NULL) { - char buffer[512]; - snprintf(buffer, sizeof(buffer), B_TRANSLATE("Pairs did not find " - "enough vector icons in the system; it needs at least %d."), - fNumOfCards / 2); - BString msgStr(buffer); - msgStr << "\n"; - BAlert* alert = new BAlert("Fatal", msgStr.String(), - B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_FROM_WIDEST, - B_STOP_ALERT); - alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); - alert->Go(); - exit(1); - } - fCardBitmaps.AddItem(bitmap); - } - - // delete the remaining bitmaps from the list - while (BBitmap* bitmap = (BBitmap*)bitmaps.RemoveItem((int32)0)) - delete bitmap; -} - - -void -PairsView::_SetPairsBoard() -{ - for (int i = 0; i < fNumOfCards; i++) { - fButtonMessage = new BMessage(kMsgCardButton); - fButtonMessage->AddInt32("ButtonNum", i); - - int x = i % fWidth * (kBitmapSize + kSpaceSize) + kSpaceSize; - int y = i / fHeight * (kBitmapSize + kSpaceSize) + kSpaceSize; - - TopButton* button = new TopButton(x, y, fButtonMessage); - fDeckCard.AddItem(button); - AddChild(button); - } -} - - -void -PairsView::_GenerateCardPos() -{ - _ReadRandomIcons(); - - srand((unsigned)time(0)); - - int* positions = new int[fNumOfCards]; - for (int i = 0; i < fNumOfCards; i++) - positions[i] = i; - - for (int i = fNumOfCards; i >= 1; i--) { - int index = rand() % i; - - fRandPos[fNumOfCards - i] = positions[index]; - - for (int j = index; j < i - 1; j++) - positions[j] = positions[j + 1]; - } - - for (int i = 0; i < fNumOfCards; i++) { - fPosX[i] = (fRandPos[i]) % fWidth * (kBitmapSize + kSpaceSize) - + kSpaceSize; - fPosY[i] = (fRandPos[i]) / fHeight * (kBitmapSize + kSpaceSize) - + kSpaceSize; - } - - delete [] positions; + BView::AttachedToWindow(); } void PairsView::Draw(BRect updateRect) { - SetDrawingMode(B_OP_ALPHA); + BObjectList* bitmapsList; + switch (fIconSize) { + case kSmallIconSize: + bitmapsList = fSmallBitmapsList; + break; - // draw rand pair 1 & 2 - for (int i = 0; i < fNumOfCards; i++) { - BBitmap* bitmap = ((BBitmap*)fCardBitmaps.ItemAt(i % fNumOfCards / 2)); - DrawBitmap(bitmap, BPoint(fPosX[i], fPosY[i])); + case kLargeIconSize: + bitmapsList = fLargeBitmapsList; + break; + + case kMediumIconSize: + default: + bitmapsList = fMediumBitmapsList; + } + + for (int32 i = 0; i < fButtonsCount; i++) { + SetDrawingMode(B_OP_ALPHA); + DrawBitmap(bitmapsList->ItemAt(i % (fButtonsCount / 2)), + BPoint(fPositionX[i], fPositionY[i])); + SetDrawingMode(B_OP_COPY); } } -int -PairsView::GetIconFromPos(int pos) +void +PairsView::FrameResized(float newWidth, float newHeight) { - return fRandPos[pos]; + int32 spacing = Spacing(); + for (int32 i = 0; i < fButtonsCount; i++) { + PairsButton* button = fPairsButtonList->ItemAt(i); + if (button != NULL) { + button->ResizeTo(fIconSize, fIconSize); + int32 x = i % fRows * (fIconSize + spacing) + spacing; + int32 y = i / fCols * (fIconSize + spacing) + spacing; + button->MoveTo(x, y); + button->SetFontSize(fIconSize - 15); + } + } + + _SetPositions(); + Invalidate(BRect(0, 0, newWidth, newHeight)); + BView::FrameResized(newWidth, newHeight); +} + + +int32 +PairsView::GetIconPosition(int32 index) +{ + return fRandomPosition[index]; +} + + +// #pragma mark - PairsView private methods + + +void +PairsView::_GenerateCardPositions() +{ + // seed the random number generator based on the current timestamp + srand((unsigned)time(0)); + + _ReadRandomIcons(); + + int32* positions = new int32[fButtonsCount]; + for (int32 i = 0; i < fButtonsCount; i++) + positions[i] = i; + + for (int32 i = fButtonsCount; i > 0; i--) { + int32 index = rand() % i; + fRandomPosition[fButtonsCount - i] = positions[index]; + for (int32 j = index; j < i - 1; j++) + positions[j] = positions[j + 1]; + } + delete[] positions; + + _SetPositions(); +} + + +void +PairsView::_ReadRandomIcons() +{ + Pairs* app = dynamic_cast(be_app); + if (app == NULL) // check if NULL to make Coverity happy + return; + + // Create a copy of the icon map so we can erase elements from it as we + // add them to the list eliminating repeated icons without altering the + // orginal IconMap. + IconMap tmpIconMap(app->GetIconMap()); + size_t mapSize = tmpIconMap.size(); + if (mapSize < (size_t)fCardsCount) { + // not enough icons, we're screwed + return; + } + + // clean out any previous icons + fSmallBitmapsList->MakeEmpty(); + fMediumBitmapsList->MakeEmpty(); + fLargeBitmapsList->MakeEmpty(); + + // pick bitmaps at random from the icon map + for (int32 i = 0; i < fCardsCount; i++) { + IconMap::iterator iter = tmpIconMap.begin(); + if (mapSize < (size_t)fCardsCount) { + // not enough valid icons, we're really screwed + return; + } + std::advance(iter, rand() % mapSize); + size_t key = iter->first; + vector_icon* icon = iter->second; + + BBitmap* smallBitmap = new BBitmap( + BRect(0, 0, kSmallIconSize - 1, kSmallIconSize - 1), B_RGBA32); + status_t smallResult = BIconUtils::GetVectorIcon(icon->data, + icon->size, smallBitmap); + BBitmap* mediumBitmap = new BBitmap( + BRect(0, 0, kMediumIconSize - 1, kMediumIconSize - 1), B_RGBA32); + status_t mediumResult = BIconUtils::GetVectorIcon(icon->data, + icon->size, mediumBitmap); + BBitmap* largeBitmap = new BBitmap( + BRect(0, 0, kLargeIconSize - 1, kLargeIconSize - 1), B_RGBA32); + status_t largeResult = BIconUtils::GetVectorIcon(icon->data, + icon->size, largeBitmap); + + if (smallResult + mediumResult + largeResult == B_OK) { + fSmallBitmapsList->AddItem(smallBitmap); + fMediumBitmapsList->AddItem(mediumBitmap); + fLargeBitmapsList->AddItem(largeBitmap); + } else { + delete smallBitmap; + delete mediumBitmap; + delete largeBitmap; + i--; + } + + mapSize -= tmpIconMap.erase(key); + // remove the element from the map so we don't read it again + } +} + + +void +PairsView::_SetPairsBoard() +{ + int32 spacing = Spacing(); + for (int32 i = 0; i < fButtonsCount; i++) { + BMessage* buttonMessage = new BMessage(kMsgCardButton); + buttonMessage->AddInt32("button number", i); + + int32 x = i % fRows * (fIconSize + spacing) + spacing; + int32 y = i / fCols * (fIconSize + spacing) + spacing; + + PairsButton* button = new PairsButton(x, y, fIconSize, buttonMessage); + fPairsButtonList->AddItem(button); + AddChild(button); + } +} + + +void +PairsView::_SetPositions() +{ + int32 spacing = Spacing(); + for (int32 i = 0; i < fButtonsCount; i++) { + fPositionX[i] = fRandomPosition[i] % fRows * (fIconSize + spacing) + spacing; + fPositionY[i] = fRandomPosition[i] / fCols * (fIconSize + spacing) + spacing; + } } diff --git a/src/apps/pairs/PairsView.h b/src/apps/pairs/PairsView.h index cbcef74719..c3748729e3 100644 --- a/src/apps/pairs/PairsView.h +++ b/src/apps/pairs/PairsView.h @@ -12,40 +12,63 @@ #define PAIRS_VIEW_H +#include #include -class TopButton; +const uint8 kSmallIconSize = 32; +const uint8 kMediumIconSize = 64; +const uint8 kLargeIconSize = 128; + +const uint32 kMsgCardButton = 'card'; + + +class BBitmap; +class PairsButton; + class PairsView : public BView { public: PairsView(BRect frame, const char* name, - int width, int height, - uint32 resizingMode); + uint8 rows, uint8 cols, uint8 iconSize); virtual ~PairsView(); virtual void AttachedToWindow(); virtual void Draw(BRect updateRect); + virtual void FrameResized(float newWidth, float newHeight); + virtual void CreateGameBoard(); - int fWidth; - int fHeight; - int fNumOfCards; + int32 Rows() const { return fRows; }; + int32 Cols() const { return fCols; }; + BObjectList* PairsButtonList() const + { return fPairsButtonList; }; - BList fDeckCard; - int GetIconFromPos(int pos); + int32 GetIconPosition(int32 index); + + int32 IconSize() const { return fIconSize; }; + void SetIconSize(int32 size) { fIconSize = size; }; + + int32 Spacing() const { return fIconSize / 6; }; private: - void _SetPairsBoard(); + void _GenerateCardPositions(); void _ReadRandomIcons(); - void _GenerateCardPos(); - bool _HasBitmap(BList& bitmaps, BBitmap* bitmap); + void _SetPairsBoard(); + void _SetPositions(); - BMessage* fButtonMessage; - BList fCardBitmaps; - int* fRandPos; - int* fPosX; - int* fPosY; + uint8 fRows; + uint8 fCols; + uint8 fIconSize; + int32 fButtonsCount; + int32 fCardsCount; + BObjectList* fPairsButtonList; + BObjectList* fSmallBitmapsList; + BObjectList* fMediumBitmapsList; + BObjectList* fLargeBitmapsList; + int32* fRandomPosition; + int32* fPositionX; + int32* fPositionY; }; diff --git a/src/apps/pairs/PairsWindow.cpp b/src/apps/pairs/PairsWindow.cpp index 2a11514487..3d09164121 100644 --- a/src/apps/pairs/PairsWindow.cpp +++ b/src/apps/pairs/PairsWindow.cpp @@ -12,12 +12,11 @@ #include "PairsWindow.h" -#include - #include #include #include #include +#include #include #include #include @@ -26,9 +25,8 @@ #include #include "Pairs.h" -#include "PairsGlobal.h" +#include "PairsButton.h" #include "PairsView.h" -#include "PairsTopButton.h" #undef B_TRANSLATION_CONTEXT @@ -36,8 +34,11 @@ const uint32 MENU_NEW = 'MGnw'; -const uint32 MENU_SIZE = 'MGsz'; +const uint32 MENU_DIFFICULTY = 'MGdf'; const uint32 MENU_QUIT = 'MGqu'; +const uint32 MENU_ICON_SIZE = 'MSIs'; + +const uint32 kMsgPairComparing = 'pcom'; // #pragma mark - PairsWindow @@ -45,18 +46,19 @@ const uint32 MENU_QUIT = 'MGqu'; PairsWindow::PairsWindow() : - BWindow(BRect(100, 100, 405, 423), B_TRANSLATE_SYSTEM_NAME("Pairs"), + 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), + | B_NOT_RESIZABLE | B_NOT_ZOOMABLE), fPairComparing(NULL), fIsFirstClick(true), fIsPairsActive(true), - fPairCard(0), - fPairCardTmp(0), - fButtonTmp(0), - fButton(0), + fPairCardPosition(0), + fPairCardTmpPosition(0), + fButtonTmpPosition(0), + fButtonPosition(0), fButtonClicks(0), - fFinishPairs(0) + fFinishPairs(0), + fIconSizeMenu(NULL) { _MakeMenuBar(); _MakeGameView(4, 4); @@ -77,56 +79,94 @@ PairsWindow::_MakeMenuBar() fMenuBar = new BMenuBar(BRect(0, 0, 0, 0), "menubar"); AddChild(fMenuBar); - BMenu* menu = new BMenu(B_TRANSLATE("Game")); - fMenuBar->AddItem(menu); + BMenu* gameMenu = new BMenu(B_TRANSLATE("Game")); + fMenuBar->AddItem(gameMenu); BMenuItem* menuItem; - menu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("New"), - new BMessage(MENU_NEW), 'N')); - menu->AddSeparatorItem(); + BMenu* newMenu = new BMenu(B_TRANSLATE("New")); + newMenu->SetRadioMode(true); - BMenu* sizeMenu = new BMenu(B_TRANSLATE("Size")); - sizeMenu->SetRadioMode(true); - - BMessage* sizeMessage = new BMessage(MENU_SIZE); - sizeMessage->AddInt32("width", 4); - sizeMessage->AddInt32("height", 4); - sizeMenu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Beginner (4x4)"), - sizeMessage)); + 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); - sizeMessage = new BMessage(MENU_SIZE); - sizeMessage->AddInt32("width", 6); - sizeMessage->AddInt32("height", 6); - sizeMenu->AddItem(menuItem = new BMenuItem( - B_TRANSLATE("Intermediate (6x6)"), sizeMessage)); + difficultyMessage = new BMessage(MENU_DIFFICULTY); + difficultyMessage->AddInt32("rows", 6); + difficultyMessage->AddInt32("cols", 6); + newMenu->AddItem(menuItem = new BMenuItem( + B_TRANSLATE("Intermediate (6x6)"), difficultyMessage)); - sizeMessage = new BMessage(MENU_SIZE); - sizeMessage->AddInt32("width", 8); - sizeMessage->AddInt32("height", 8); - sizeMenu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Expert (8x8)"), - sizeMessage)); + difficultyMessage = new BMessage(MENU_DIFFICULTY); + difficultyMessage->AddInt32("rows", 8); + difficultyMessage->AddInt32("cols", 8); + newMenu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Expert (8x8)"), + difficultyMessage)); - menu->AddItem(sizeMenu); + menuItem = new BMenuItem(newMenu, new BMessage(MENU_NEW)); + menuItem->SetShortcut('N', B_COMMAND_KEY); + gameMenu->AddItem(menuItem); - menu->AddSeparatorItem(); + gameMenu->AddSeparatorItem(); - menu->AddItem(menuItem = new BMenuItem(B_TRANSLATE("Quit"), + 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(int width, int height) +PairsWindow::_MakeGameView(uint8 rows, uint8 cols) { BRect viewBounds = Bounds(); viewBounds.top = fMenuBar->Bounds().Height() + 1; - fPairsView = new PairsView(viewBounds, "PairsView", width, height, - B_FOLLOW_NONE); - fPairsView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + 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); } @@ -140,14 +180,12 @@ PairsWindow::NewGame() void -PairsWindow::SetGameSize(int width, int height) +PairsWindow::SetGameSize(uint8 rows, uint8 cols) { - ResizeTo((kBitmapSize + kSpaceSize) * width + kSpaceSize, - (kBitmapSize + kSpaceSize) * height + kSpaceSize - + fMenuBar->Bounds().Height()); RemoveChild(fPairsView); delete fPairsView; - _MakeGameView(width, height); + + _MakeGameView(rows, cols); NewGame(); } @@ -160,112 +198,153 @@ PairsWindow::MessageReceived(BMessage* message) NewGame(); break; - case MENU_SIZE: + case MENU_DIFFICULTY: { - int32 width; - int32 height; - if (message->FindInt32("width", &width) == B_OK - && message->FindInt32("height", &height) == B_OK) { - SetGameSize(width, height); + 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) { - fButtonClicks++; + { + if (!fIsPairsActive) + break; - int32 num; - if (message->FindInt32("ButtonNum", &num) < B_OK) + int32 buttonNumber; + if (message->FindInt32("button number", &buttonNumber) != B_OK) + break; + + BObjectList* 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; - - // look what Icon is behind a button - for (int h = 0; h < fPairsView->fNumOfCards; h++) { - if (fPairsView->GetIconFromPos(h) == num) { - fPairCard = (h % fPairsView->fNumOfCards / 2); - fButton = fPairsView->GetIconFromPos(h); - break; - } } + } - // gameplay - ((TopButton*)fPairsView->fDeckCard.ItemAt(fButton))->Hide(); + // gameplay + fButtonClicks++; + pairsButtonList->ItemAt(fButtonPosition)->Hide(); - if (fIsFirstClick) { - fPairCardTmp = fPairCard; - fButtonTmp = fButton; - } 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; - } + 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; + fIsFirstClick = !fIsFirstClick; + break; + } + + case kMsgPairComparing: + { + BObjectList* 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 score; + score << fButtonClicks; + BString strAbout = B_TRANSLATE("%app%\n" + "\twritten by Ralf Schülke\n" + "\tCopyright 2008-2010, Haiku Inc.\n" + "\n" + "You completed the game in %num% clicks.\n"); + + strAbout.ReplaceFirst("%app%", + B_TRANSLATE_SYSTEM_NAME("Pairs")); + strAbout.ReplaceFirst("%num%", score); + + 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; - - case kMsgPairComparing: - delete fPairComparing; - fPairComparing = NULL; - - fIsPairsActive = true; - - if (fPairCard == fPairCardTmp) - fFinishPairs++; - else { - ((TopButton*)fPairsView->fDeckCard.ItemAt(fButton))->Show(); - ((TopButton*)fPairsView->fDeckCard.ItemAt(fButtonTmp))->Show(); - } - - // game end and results - if (fFinishPairs == fPairsView->fNumOfCards / 2) { - BString score; - score << fButtonClicks; - BString strAbout = B_TRANSLATE("%app%\n" - "\twritten by Ralf Schülke\n" - "\tCopyright 2008-2010, Haiku Inc.\n" - "\n" - "You completed the game in %num% clicks.\n"); - - strAbout.ReplaceFirst("%app%", - B_TRANSLATE_SYSTEM_NAME("Pairs")); - strAbout.ReplaceFirst("%num%", score); - - 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()); +} diff --git a/src/apps/pairs/PairsWindow.h b/src/apps/pairs/PairsWindow.h index 633e0dcd3b..a063d7c7bf 100644 --- a/src/apps/pairs/PairsWindow.h +++ b/src/apps/pairs/PairsWindow.h @@ -15,8 +15,9 @@ #include -class PairsView; +class BMenu; class BMessageRunner; +class PairsView; class PairsWindow : public BWindow { @@ -27,11 +28,12 @@ public: virtual void MessageReceived(BMessage* message); void NewGame(); - void SetGameSize(int width, int height); + void SetGameSize(uint8 rows, uint8 cols); private: - void _MakeGameView(int width, int height); + void _MakeGameView(uint8 rows, uint8 cols); void _MakeMenuBar(); + void _ResizeWindow(uint8 rows, uint8 cols); BView* fBackgroundView; PairsView* fPairsView; @@ -39,12 +41,13 @@ private: BMessageRunner* fPairComparing; bool fIsFirstClick; bool fIsPairsActive; - int fPairCard; - int fPairCardTmp; - int fButtonTmp; - int fButton; - int fButtonClicks; - int fFinishPairs; + int32 fPairCardPosition; + int32 fPairCardTmpPosition; + int32 fButtonTmpPosition; + int32 fButtonPosition; + int32 fButtonClicks; + int32 fFinishPairs; + BMenu* fIconSizeMenu; }; #endif // PAIRS_WINDOW_H