xref: /haiku/src/apps/pairs/PairsView.cpp (revision d179e1fb749801097833a23db8a18591f0be76b7)
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