xref: /haiku/src/apps/pairs/PairsView.cpp (revision 4a29c739af6299c51963c4f5c63fd49f113a74be)
1 /*
2  * Copyright 2008, Ralf Schülke, teammaui@web.de. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "PairsView.h"
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 
11 #include <Alert.h>
12 #include <Application.h>
13 #include <Bitmap.h>
14 #include <Button.h>
15 #include <Directory.h>
16 #include <Entry.h>
17 #include <FindDirectory.h>
18 #include <IconUtils.h>
19 #include <List.h>
20 #include <Node.h>
21 #include <NodeInfo.h>
22 #include <Path.h>
23 
24 #include "Pairs.h"
25 #include "PairsGlobal.h"
26 #include "PairsTopButton.h"
27 
28 // TODO: support custom board sizes
29 
30 PairsView::PairsView(BRect frame, const char* name, uint32 resizingMode)
31 	: BView(frame, name, resizingMode, B_WILL_DRAW)
32 {
33 	// init bitmap pointers
34 	for (int i = 0; i < 8; i++)
35 		fCard[i] = NULL;
36 
37 	CreateGameBoard();
38 	_SetPairsBoard();
39 }
40 
41 
42 void
43 PairsView::CreateGameBoard()
44 {
45 	// Show hidden buttons
46 	for (int32 i = 0; i < CountChildren(); i++) {
47 		BView* child = ChildAt(i);
48 		if (child->IsHidden())
49 			child->Show();
50 	}
51 	_GenerateCardPos();
52 }
53 
54 
55 PairsView::~PairsView()
56 {
57 	for (int i = 0; i < 8; i++)
58 		delete fCard[i];
59 
60 	for (int i = 0; i < 16; i++)
61 		delete fDeckCard[i];
62 }
63 
64 
65 void
66 PairsView::AttachedToWindow()
67 {
68 	MakeFocus(true);
69 }
70 
71 
72 bool
73 PairsView::_HasBitmap(BList& bitmaps, BBitmap* bitmap)
74 {
75 	// TODO: if this takes too long, we could build a hash value for each
76 	// bitmap in a separate list
77 	for (int32 i = bitmaps.CountItems(); i-- > 0;) {
78 		BBitmap* item = (BBitmap*)bitmaps.ItemAtFast(i);
79 		if (!memcmp(item->Bits(), bitmap->Bits(), item->BitsLength()))
80 			return true;
81 	}
82 
83 	return false;
84 }
85 
86 
87 void
88 PairsView::_ReadRandomIcons()
89 {
90 	// TODO: maybe read the icons only once at startup
91 
92 	// clean out any previous icons
93 	for (int i = 0; i < 8; i++) {
94 		delete fCard[i];
95 		fCard[i] = NULL;
96 	}
97 
98 	BDirectory appsDirectory;
99 	BDirectory prefsDirectory;
100 
101 	BPath path;
102 	if (find_directory(B_BEOS_APPS_DIRECTORY, &path) == B_OK)
103 		appsDirectory.SetTo(path.Path());
104 	if (find_directory(B_BEOS_PREFERENCES_DIRECTORY, &path) == B_OK)
105 		prefsDirectory.SetTo(path.Path());
106 
107 	// read vector icons from apps and prefs folder and put them
108 	// into a BList as BBitmaps
109 	BList bitmaps;
110 
111 	BEntry entry;
112 	while (appsDirectory.GetNextEntry(&entry) == B_OK
113 		|| prefsDirectory.GetNextEntry(&entry) == B_OK) {
114 
115 		BNode node(&entry);
116 		BNodeInfo nodeInfo(&node);
117 
118 		if (nodeInfo.InitCheck() < B_OK)
119 			continue;
120 
121 		uint8* data;
122 		size_t size;
123 		type_code type;
124 
125 		if (nodeInfo.GetIcon(&data, &size, &type) < B_OK)
126 			continue;
127 
128 		if (type != B_VECTOR_ICON_TYPE) {
129 			delete[] data;
130 			continue;
131 		}
132 
133 		BBitmap* bitmap = new BBitmap(
134 			BRect(0, 0, kBitmapSize - 1, kBitmapSize - 1), 0, B_RGBA32);
135 		if (BIconUtils::GetVectorIcon(data, size, bitmap) < B_OK) {
136 			delete[] data;
137 			delete bitmap;
138 			continue;
139 		}
140 
141 		delete[] data;
142 
143 		if (_HasBitmap(bitmaps, bitmap) || !bitmaps.AddItem(bitmap))
144 			delete bitmap;
145 		else if (bitmaps.CountItems() >= 128) {
146 			// this is enough to choose from, stop eating memory...
147 			break;
148 		}
149 	}
150 
151 	// pick eight random bitmaps from the ones we got in the list
152 	srand((unsigned)time(0));
153 
154 	for (int i = 0; i < 8; i++) {
155 		int32 index = rand() % bitmaps.CountItems();
156 		fCard[i] = (BBitmap*)bitmaps.RemoveItem(index);
157 		if (fCard[i] == NULL) {
158 			BAlert* alert = new BAlert("fatal", "Pairs did not find enough "
159 				"vector icons in the system, it needs at least eight.",
160 				"Oh!", NULL, NULL, B_WIDTH_FROM_WIDEST, B_STOP_ALERT);
161 			alert->Go();
162 			exit(1);
163 		}
164 	}
165 
166 	// delete the remaining bitmaps from the list
167 	while (BBitmap* bitmap = (BBitmap*)bitmaps.RemoveItem(0L))
168 		delete bitmap;
169 }
170 
171 
172 void
173 PairsView::_SetPairsBoard()
174 {
175 	for (int i = 0; i < 16; i++) {
176 		fButtonMessage = new BMessage(kMsgCardButton);
177 		fButtonMessage->AddInt32("ButtonNum", i);
178 
179 		int x =  i % 4 * (kBitmapSize + 10) + 10;
180 		int y =  i / 4 * (kBitmapSize + 10) + 10;
181 
182 		fDeckCard[i] = new TopButton(x, y, fButtonMessage);
183 		AddChild(fDeckCard[i]);
184 	}
185 }
186 
187 
188 void
189 PairsView::_GenerateCardPos()
190 {
191 	_ReadRandomIcons();
192 
193 	srand((unsigned)time(0));
194 
195 	int positions[16];
196 	for (int i = 0; i < 16; i++)
197 		positions[i] = i;
198 
199 	for (int i = 16; i >= 1; i--) {
200 		int index = rand() % i;
201 
202 		fRandPos[16-i] = positions[index];
203 
204 		for (int j = index; j < i - 1; j++)
205 			positions[j] = positions[j + 1];
206 	}
207 
208 	for (int i = 0; i < 16; i++) {
209 		fPosX[i] = (fRandPos[i]) % 4 * (kBitmapSize + 10) + 10;
210 		fPosY[i] = (fRandPos[i]) / 4 * (kBitmapSize + 10) + 10;
211 	}
212 }
213 
214 
215 void
216 PairsView::Draw(BRect updateRect)
217 {
218 	SetDrawingMode(B_OP_ALPHA);
219 
220 	// draw rand pair 1 & 2
221 	for (int i = 0; i < 16; i++)
222 		DrawBitmap(fCard[i % 8], BPoint(fPosX[i], fPosY[i]));
223 }
224 
225 
226 int
227 PairsView::GetIconFromPos(int pos)
228 {
229 	return fRandPos[pos];
230 }
231