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 "PairsView.h" 8 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12 13#include <Alert.h> 14#include <Application.h> 15#include <Bitmap.h> 16#include <Button.h> 17#include <Catalog.h> 18#include <Directory.h> 19#include <Entry.h> 20#include <FindDirectory.h> 21#include <IconUtils.h> 22#include <List.h> 23#include <Node.h> 24#include <NodeInfo.h> 25#include <Path.h> 26 27#include "Pairs.h" 28#include "PairsGlobal.h" 29#include "PairsTopButton.h" 30 31PairsView::PairsView(BRect frame, const char* name, int width, int height, 32 uint32 resizingMode) 33 : 34 BView(frame, name, resizingMode, B_WILL_DRAW), 35 fWidth(width), 36 fHeight(height), 37 fNumOfCards(width * height), 38 fRandPos(new int[fNumOfCards]), 39 fPosX(new int[fNumOfCards]), 40 fPosY(new int[fNumOfCards]) 41{ 42 CreateGameBoard(); 43 _SetPairsBoard(); 44} 45 46 47void 48PairsView::CreateGameBoard() 49{ 50 // Show hidden buttons 51 for (int32 i = 0; i < CountChildren(); i++) { 52 BView* child = ChildAt(i); 53 if (child->IsHidden()) 54 child->Show(); 55 } 56 _GenerateCardPos(); 57} 58 59 60PairsView::~PairsView() 61{ 62 for (int i = 0; i < fCardBitmaps.CountItems(); i++) 63 delete ((BBitmap*)fCardBitmaps.ItemAt(i)); 64 65 for (int i = 0; i < fDeckCard.CountItems(); i++) 66 delete ((TopButton*)fDeckCard.ItemAt(i)); 67 68 delete fRandPos; 69 delete fPosX; 70 delete fPosY; 71} 72 73 74void 75PairsView::AttachedToWindow() 76{ 77 MakeFocus(true); 78} 79 80 81bool 82PairsView::_HasBitmap(BList& bitmaps, BBitmap* bitmap) 83{ 84 // TODO: if this takes too long, we could build a hash value for each 85 // bitmap in a separate list 86 for (int32 i = bitmaps.CountItems(); i-- > 0;) { 87 BBitmap* item = (BBitmap*)bitmaps.ItemAtFast(i); 88 if (!memcmp(item->Bits(), bitmap->Bits(), item->BitsLength())) 89 return true; 90 } 91 92 return false; 93} 94 95#undef B_TRANSLATION_CONTEXT 96#define B_TRANSLATION_CONTEXT "PairsView" 97 98void 99PairsView::_ReadRandomIcons() 100{ 101 // TODO: maybe read the icons only once at startup 102 103 // clean out any previous icons 104 for (int i = 0; i < fCardBitmaps.CountItems(); i++) 105 delete ((BBitmap*)fCardBitmaps.ItemAt(i)); 106 107 fCardBitmaps.MakeEmpty(); 108 109 BDirectory appsDirectory; 110 BDirectory prefsDirectory; 111 112 BPath path; 113 if (find_directory(B_BEOS_APPS_DIRECTORY, &path) == B_OK) 114 appsDirectory.SetTo(path.Path()); 115 if (find_directory(B_BEOS_PREFERENCES_DIRECTORY, &path) == B_OK) 116 prefsDirectory.SetTo(path.Path()); 117 118 // read vector icons from apps and prefs folder and put them 119 // into a BList as BBitmaps 120 BList bitmaps; 121 122 BEntry entry; 123 while (appsDirectory.GetNextEntry(&entry) == B_OK 124 || prefsDirectory.GetNextEntry(&entry) == B_OK) { 125 126 BNode node(&entry); 127 BNodeInfo nodeInfo(&node); 128 129 if (nodeInfo.InitCheck() < B_OK) 130 continue; 131 132 uint8* data; 133 size_t size; 134 type_code type; 135 136 if (nodeInfo.GetIcon(&data, &size, &type) < B_OK) 137 continue; 138 139 if (type != B_VECTOR_ICON_TYPE) { 140 delete[] data; 141 continue; 142 } 143 144 BBitmap* bitmap = new BBitmap( 145 BRect(0, 0, kBitmapSize - 1, kBitmapSize - 1), 0, B_RGBA32); 146 if (BIconUtils::GetVectorIcon(data, size, bitmap) < B_OK) { 147 delete[] data; 148 delete bitmap; 149 continue; 150 } 151 152 delete[] data; 153 154 if (_HasBitmap(bitmaps, bitmap) || !bitmaps.AddItem(bitmap)) 155 delete bitmap; 156 else if (bitmaps.CountItems() >= 128) { 157 // this is enough to choose from, stop eating memory... 158 break; 159 } 160 } 161 162 // pick random bitmaps from the ones we got in the list 163 srand((unsigned)time(0)); 164 165 for (int i = 0; i < fNumOfCards / 2; i++) { 166 int32 index = rand() % bitmaps.CountItems(); 167 BBitmap* bitmap = ((BBitmap*)bitmaps.RemoveItem(index)); 168 if (bitmap == NULL) { 169 char buffer[512]; 170 snprintf(buffer, sizeof(buffer), B_TRANSLATE("Pairs did not find " 171 "enough vector icons in the system; it needs at least %d."), 172 fNumOfCards / 2); 173 BString msgStr(buffer); 174 msgStr << "\n"; 175 BAlert* alert = new BAlert("Fatal", msgStr.String(), 176 B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_FROM_WIDEST, 177 B_STOP_ALERT); 178 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 179 alert->Go(); 180 exit(1); 181 } 182 fCardBitmaps.AddItem(bitmap); 183 } 184 185 // delete the remaining bitmaps from the list 186 while (BBitmap* bitmap = (BBitmap*)bitmaps.RemoveItem((int32)0)) 187 delete bitmap; 188} 189 190 191void 192PairsView::_SetPairsBoard() 193{ 194 for (int i = 0; i < fNumOfCards; i++) { 195 fButtonMessage = new BMessage(kMsgCardButton); 196 fButtonMessage->AddInt32("ButtonNum", i); 197 198 int x = i % fWidth * (kBitmapSize + kSpaceSize) + kSpaceSize; 199 int y = i / fHeight * (kBitmapSize + kSpaceSize) + kSpaceSize; 200 201 TopButton* button = new TopButton(x, y, fButtonMessage); 202 fDeckCard.AddItem(button); 203 AddChild(button); 204 } 205} 206 207 208void 209PairsView::_GenerateCardPos() 210{ 211 _ReadRandomIcons(); 212 213 srand((unsigned)time(0)); 214 215 int* positions = new int[fNumOfCards]; 216 for (int i = 0; i < fNumOfCards; i++) 217 positions[i] = i; 218 219 for (int i = fNumOfCards; i >= 1; i--) { 220 int index = rand() % i; 221 222 fRandPos[fNumOfCards - i] = positions[index]; 223 224 for (int j = index; j < i - 1; j++) 225 positions[j] = positions[j + 1]; 226 } 227 228 for (int i = 0; i < fNumOfCards; i++) { 229 fPosX[i] = (fRandPos[i]) % fWidth * (kBitmapSize + kSpaceSize) 230 + kSpaceSize; 231 fPosY[i] = (fRandPos[i]) / fHeight * (kBitmapSize + kSpaceSize) 232 + kSpaceSize; 233 } 234 235 delete [] positions; 236} 237 238 239void 240PairsView::Draw(BRect updateRect) 241{ 242 SetDrawingMode(B_OP_ALPHA); 243 244 // draw rand pair 1 & 2 245 for (int i = 0; i < fNumOfCards; i++) { 246 BBitmap* bitmap = ((BBitmap*)fCardBitmaps.ItemAt(i % fNumOfCards / 2)); 247 DrawBitmap(bitmap, BPoint(fPosX[i], fPosY[i])); 248 } 249} 250 251 252int 253PairsView::GetIconFromPos(int pos) 254{ 255 return fRandPos[pos]; 256} 257