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