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