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
40PairsView::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
63void
64PairsView::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
77PairsView::~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
89void
90PairsView::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
103void
104PairsView::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
130void
131PairsView::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
151int32
152PairsView::GetIconPosition(int32 index)
153{
154	return fRandomPosition[index];
155}
156
157
158//	#pragma mark - PairsView private methods
159
160
161void
162PairsView::_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
185void
186PairsView::_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
248void
249PairsView::_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
266void
267PairsView::_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