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
PairsView(BRect frame,const char * name,uint8 rows,uint8 cols,uint8 iconSize)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
CreateGameBoard()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
~PairsView()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
AttachedToWindow()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
Draw(BRect updateRect)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
FrameResized(float newWidth,float newHeight)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
GetIconPosition(int32 index)152 PairsView::GetIconPosition(int32 index)
153 {
154 return fRandomPosition[index];
155 }
156
157
158 // #pragma mark - PairsView private methods
159
160
161 void
_GenerateCardPositions()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
_ReadRandomIcons()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
_SetPairsBoard()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
_SetPositions()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