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