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