1 /* 2 * Copyright 2008 Ralf Schülke, ralf.schuelke@googlemail.com. 3 * Copyright 2010 Adam Smith <adamd.smith@utoronto.ca> 4 * Copyright 2014 Haiku, Inc. All rights reserved. 5 * 6 * Distributed under the terms of the MIT License. 7 * 8 * Authors: 9 * Ralf Schülke, ralf.schuelke@googlemail.com 10 * John Scipione, jscipione@gmail.com 11 * Adam Smith, adamd.smith@utoronto.ca 12 */ 13 14 15 #include "PairsView.h" 16 17 #include <stdlib.h> 18 // for srand() and rand() 19 20 #include <Application.h> 21 #include <Bitmap.h> 22 #include <Button.h> 23 #include <ControlLook.h> 24 #include <Catalog.h> 25 #include <IconUtils.h> 26 #include <InterfaceDefs.h> 27 #include <Window.h> 28 29 #include "Pairs.h" 30 #include "PairsButton.h" 31 32 33 #undef B_TRANSLATION_CONTEXT 34 #define B_TRANSLATION_CONTEXT "PairsView" 35 36 37 // #pragma mark - PairsView 38 39 40 PairsView::PairsView(BRect frame, const char* name, uint8 rows, uint8 cols, 41 uint8 iconSize) 42 : 43 BView(frame, name, B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS), 44 fRows(rows), 45 fCols(cols), 46 fIconSize(iconSize), 47 fButtonsCount(rows * cols), 48 fCardsCount(fButtonsCount / 2), 49 fPairsButtonList(new BObjectList<PairsButton>(fButtonsCount)), 50 fSmallBitmapsList(new BObjectList<BBitmap>(fCardsCount)), 51 fMediumBitmapsList(new BObjectList<BBitmap>(fCardsCount)), 52 fLargeBitmapsList(new BObjectList<BBitmap>(fCardsCount)), 53 fRandomPosition(new int32[fButtonsCount]), 54 fPositionX(new int32[fButtonsCount]), 55 fPositionY(new int32[fButtonsCount]) 56 { 57 SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 58 CreateGameBoard(); 59 _SetPairsBoard(); 60 } 61 62 63 void 64 PairsView::CreateGameBoard() 65 { 66 // Show hidden buttons 67 int32 childrenCount = CountChildren(); 68 for (int32 i = 0; i < childrenCount; i++) { 69 BView* child = ChildAt(i); 70 if (child->IsHidden()) 71 child->Show(); 72 } 73 _GenerateCardPositions(); 74 } 75 76 77 PairsView::~PairsView() 78 { 79 delete fSmallBitmapsList; 80 delete fMediumBitmapsList; 81 delete fLargeBitmapsList; 82 delete fPairsButtonList; 83 delete[] fRandomPosition; 84 delete[] fPositionX; 85 delete[] fPositionY; 86 } 87 88 89 void 90 PairsView::AttachedToWindow() 91 { 92 for (int32 i = 0; i < fButtonsCount; i++) { 93 PairsButton* button = fPairsButtonList->ItemAt(i); 94 if (button != NULL) 95 button->SetTarget(Window()); 96 } 97 98 MakeFocus(true); 99 BView::AttachedToWindow(); 100 } 101 102 103 void 104 PairsView::Draw(BRect updateRect) 105 { 106 BObjectList<BBitmap>* bitmapsList; 107 switch (fIconSize) { 108 case kSmallIconSize: 109 bitmapsList = fSmallBitmapsList; 110 break; 111 112 case kLargeIconSize: 113 bitmapsList = fLargeBitmapsList; 114 break; 115 116 case kMediumIconSize: 117 default: 118 bitmapsList = fMediumBitmapsList; 119 } 120 121 for (int32 i = 0; i < fButtonsCount; i++) { 122 SetDrawingMode(B_OP_ALPHA); 123 DrawBitmap(bitmapsList->ItemAt(i % (fButtonsCount / 2)), 124 BPoint(fPositionX[i], fPositionY[i])); 125 SetDrawingMode(B_OP_COPY); 126 } 127 } 128 129 130 void 131 PairsView::FrameResized(float newWidth, float newHeight) 132 { 133 int32 spacing = Spacing(); 134 for (int32 i = 0; i < fButtonsCount; i++) { 135 PairsButton* button = fPairsButtonList->ItemAt(i); 136 if (button != NULL) { 137 button->ResizeTo(fIconSize, fIconSize); 138 int32 x = i % fRows * (fIconSize + spacing) + spacing; 139 int32 y = i / fCols * (fIconSize + spacing) + spacing; 140 button->MoveTo(x, y); 141 button->SetFontSize(fIconSize - 15); 142 } 143 } 144 145 _SetPositions(); 146 Invalidate(BRect(0, 0, newWidth, newHeight)); 147 BView::FrameResized(newWidth, newHeight); 148 } 149 150 151 int32 152 PairsView::GetIconPosition(int32 index) 153 { 154 return fRandomPosition[index]; 155 } 156 157 158 // #pragma mark - PairsView private methods 159 160 161 void 162 PairsView::_GenerateCardPositions() 163 { 164 // seed the random number generator based on the current timestamp 165 srand((unsigned)time(0)); 166 167 _ReadRandomIcons(); 168 169 int32* positions = new int32[fButtonsCount]; 170 for (int32 i = 0; i < fButtonsCount; i++) 171 positions[i] = i; 172 173 for (int32 i = fButtonsCount; i > 0; i--) { 174 int32 index = rand() % i; 175 fRandomPosition[fButtonsCount - i] = positions[index]; 176 for (int32 j = index; j < i - 1; j++) 177 positions[j] = positions[j + 1]; 178 } 179 delete[] positions; 180 181 _SetPositions(); 182 } 183 184 185 void 186 PairsView::_ReadRandomIcons() 187 { 188 Pairs* app = dynamic_cast<Pairs*>(be_app); 189 if (app == NULL) // check if NULL to make Coverity happy 190 return; 191 192 // Create a copy of the icon map so we can erase elements from it as we 193 // add them to the list eliminating repeated icons without altering the 194 // orginal IconMap. 195 IconMap tmpIconMap(app->GetIconMap()); 196 size_t mapSize = tmpIconMap.size(); 197 if (mapSize < (size_t)fCardsCount) { 198 // not enough icons, we're screwed 199 return; 200 } 201 202 // clean out any previous icons 203 fSmallBitmapsList->MakeEmpty(); 204 fMediumBitmapsList->MakeEmpty(); 205 fLargeBitmapsList->MakeEmpty(); 206 207 // pick bitmaps at random from the icon map 208 for (int32 i = 0; i < fCardsCount; i++) { 209 IconMap::iterator iter = tmpIconMap.begin(); 210 if (mapSize < (size_t)fCardsCount) { 211 // not enough valid icons, we're really screwed 212 return; 213 } 214 std::advance(iter, rand() % mapSize); 215 size_t key = iter->first; 216 vector_icon* icon = iter->second; 217 218 BBitmap* smallBitmap = new BBitmap( 219 BRect(0, 0, kSmallIconSize - 1, kSmallIconSize - 1), B_RGBA32); 220 status_t smallResult = BIconUtils::GetVectorIcon(icon->data, 221 icon->size, smallBitmap); 222 BBitmap* mediumBitmap = new BBitmap( 223 BRect(0, 0, kMediumIconSize - 1, kMediumIconSize - 1), B_RGBA32); 224 status_t mediumResult = BIconUtils::GetVectorIcon(icon->data, 225 icon->size, mediumBitmap); 226 BBitmap* largeBitmap = new BBitmap( 227 BRect(0, 0, kLargeIconSize - 1, kLargeIconSize - 1), B_RGBA32); 228 status_t largeResult = BIconUtils::GetVectorIcon(icon->data, 229 icon->size, largeBitmap); 230 231 if (smallResult + mediumResult + largeResult == B_OK) { 232 fSmallBitmapsList->AddItem(smallBitmap); 233 fMediumBitmapsList->AddItem(mediumBitmap); 234 fLargeBitmapsList->AddItem(largeBitmap); 235 } else { 236 delete smallBitmap; 237 delete mediumBitmap; 238 delete largeBitmap; 239 i--; 240 } 241 242 mapSize -= tmpIconMap.erase(key); 243 // remove the element from the map so we don't read it again 244 } 245 } 246 247 248 void 249 PairsView::_SetPairsBoard() 250 { 251 int32 spacing = Spacing(); 252 for (int32 i = 0; i < fButtonsCount; i++) { 253 BMessage* buttonMessage = new BMessage(kMsgCardButton); 254 buttonMessage->AddInt32("button number", i); 255 256 int32 x = i % fRows * (fIconSize + spacing) + spacing; 257 int32 y = i / fCols * (fIconSize + spacing) + spacing; 258 259 PairsButton* button = new PairsButton(x, y, fIconSize, buttonMessage); 260 fPairsButtonList->AddItem(button); 261 AddChild(button); 262 } 263 } 264 265 266 void 267 PairsView::_SetPositions() 268 { 269 int32 spacing = Spacing(); 270 for (int32 i = 0; i < fButtonsCount; i++) { 271 fPositionX[i] = fRandomPosition[i] % fRows * (fIconSize + spacing) + spacing; 272 fPositionY[i] = fRandomPosition[i] / fCols * (fIconSize + spacing) + spacing; 273 } 274 } 275