xref: /haiku/src/add-ons/screen_savers/icons/IconsSaver.cpp (revision 529cd177b573aaba391c8adc9c9f5ad76a14bf81)
1 /*
2  * Copyright 2009 Vincent Duvert, vincent.duvert@free.fr
3  * Copyright 2014 Haiku, Inc. All rights reserved.
4  *
5  * Distributed under the terms of the MIT License.
6  *
7  * Authors:
8  *		Vincent Duvert, vincent.duvert@free.fr
9  *		John Scipione, jscipione@gmail.com
10  */
11 
12 
13 #include "IconsSaver.h"
14 
15 #include <stdlib.h>
16 
17 #include <Bitmap.h>
18 #include <Catalog.h>
19 #include <MimeType.h>
20 
21 #include <BuildScreenSaverDefaultSettingsView.h>
22 
23 #include "IconDisplay.h"
24 #include "VectorIcon.h"
25 
26 
27 #undef B_TRANSLATION_CONTEXT
28 #define B_TRANSLATION_CONTEXT "Screensaver Icons"
29 
30 
31 #define RAND_BETWEEN(a, b) ((rand() % ((b) - (a) + 1) + (a)))
32 
33 
34 static const int32 kMaxConcurrentIcons = 15;
35 static const int32 kMinIconWidthPercentage = 5;
36 	// percentage of the screen width
37 static const int32 kMaxIconWidthPercentage = 20;
38 	// same here
39 static const int32 kMinIconCount = 20;
40 static const int32 kMaxIconCount = 384;
41 
42 
43 const rgb_color kBackgroundColor = ui_color(B_DESKTOP_COLOR);
44 
45 
46 BScreenSaver* instantiate_screen_saver(BMessage* msg, image_id image)
47 {
48 	return new IconsSaver(msg, image);
49 }
50 
51 
52 //	#pragma mark - IconsSaver
53 
54 
55 IconsSaver::IconsSaver(BMessage* archive, image_id image)
56 	:
57 	BScreenSaver(archive, image),
58 	fIcons(NULL),
59 	fBackBitmap(NULL),
60 	fBackView(NULL),
61 	fMinSize(0),
62 	fMaxSize(0)
63 {
64 }
65 
66 
67 IconsSaver::~IconsSaver()
68 {
69 }
70 
71 
72 status_t
73 IconsSaver::StartSaver(BView* view, bool /*preview*/)
74 {
75 	if (fVectorIcons.CountItems() < kMinIconCount)
76 		_GetVectorIcons();
77 
78 	srand(system_time() % INT_MAX);
79 
80 	BRect screenRect(0, 0, view->Frame().Width(), view->Frame().Height());
81 	fBackBitmap = new BBitmap(screenRect, B_RGBA32, true);
82 	if (!fBackBitmap->IsValid())
83 		return B_NO_MEMORY;
84 
85 	fBackView = new BView(screenRect, "back view", 0, 0);
86 	if (fBackView == NULL)
87 		return B_NO_MEMORY;
88 
89 	fBackView->SetViewColor(kBackgroundColor);
90 	fBackView->SetHighColor(kBackgroundColor);
91 
92 	fBackBitmap->AddChild(fBackView);
93 	if (fBackBitmap->Lock()) {
94 		fBackView->FillRect(fBackView->Frame());
95 		fBackView->SetDrawingMode(B_OP_ALPHA);
96 		fBackView->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
97 		fBackView->Sync();
98 		fBackBitmap->Unlock();
99 	}
100 
101 	fIcons = new IconDisplay[kMaxConcurrentIcons];
102 
103 	fMaxSize = (screenRect.IntegerWidth() * kMaxIconWidthPercentage) / 100;
104 	fMinSize = (screenRect.IntegerWidth() * kMinIconWidthPercentage) / 100;
105 	if (fMaxSize > 255)
106 		fMaxSize = 255;
107 
108 	if (fMaxSize > screenRect.IntegerHeight())
109 		fMaxSize = screenRect.IntegerHeight();
110 
111 	if (fMinSize > fMaxSize)
112 		fMinSize = fMaxSize;
113 
114 	return B_OK;
115 }
116 
117 
118 void
119 IconsSaver::StopSaver()
120 {
121 	delete[] fIcons;
122 	fIcons = NULL;
123 }
124 
125 
126 void
127 IconsSaver::Draw(BView* view, int32 frame)
128 {
129 	static int32 previousFrame = 0;
130 
131 	// update drawing
132 	if (fBackBitmap->Lock()) {
133 		for (uint8 i = 0 ; i < kMaxConcurrentIcons ; i++)
134 			fIcons[i].ClearOn(fBackView);
135 
136 		int32 delta = frame - previousFrame;
137 		for (uint8 i = 0 ; i < kMaxConcurrentIcons ; i++)
138 			fIcons[i].DrawOn(fBackView, delta);
139 
140 		fBackView->Sync();
141 		fBackBitmap->Unlock();
142 	}
143 
144 	// sync the view with the back buffer
145 	view->DrawBitmap(fBackBitmap);
146 	previousFrame = frame;
147 
148 	if (fVectorIcons.CountItems() < kMinIconCount)
149 		return;
150 
151 	// restart one icon
152 	for (uint8 i = 0 ; i < kMaxConcurrentIcons ; i++) {
153 		if (!fIcons[i].IsRunning()) {
154 			uint16 size = RAND_BETWEEN(fMinSize, fMaxSize);
155 			uint16 maxX = view->Frame().IntegerWidth() - size;
156 			uint16 maxY = view->Frame().IntegerHeight() - size;
157 
158 			BRect iconFrame(0, 0, size, size);
159 			iconFrame.OffsetTo(RAND_BETWEEN(0, maxX), RAND_BETWEEN(0, maxY));
160 
161 			// Check that the icon doesn't overlap with others
162 			for (uint8 j = 0 ; j < kMaxConcurrentIcons ; j++) {
163 				if (fIcons[j].IsRunning() &&
164 					iconFrame.Intersects(fIcons[j].GetFrame()))
165 					return;
166 			}
167 
168 			int32 index = RAND_BETWEEN(0, fVectorIcons.CountItems() - 1);
169 			fIcons[i].Run(fVectorIcons.ItemAt(index), iconFrame);
170 			return;
171 		}
172 	}
173 }
174 
175 
176 void
177 IconsSaver::StartConfig(BView* view)
178 {
179 	BPrivate::BuildScreenSaverDefaultSettingsView(view, "Icons",
180 		B_TRANSLATE("by Vincent Duvert"));
181 }
182 
183 
184 //	#pragma mark - IconsSaver private methods
185 
186 
187 void
188 IconsSaver::_GetVectorIcons()
189 {
190 	// Load vector icons from the MIME type database
191 	BMessage types;
192 	if (BMimeType::GetInstalledTypes(&types) != B_OK)
193 		return;
194 
195 	const char* type;
196 	for (int32 i = 0; types.FindString("types", i, &type) == B_OK; i++) {
197 		BMimeType mimeType(type);
198 		if (mimeType.InitCheck() != B_OK)
199 			continue;
200 
201 		uint8* data;
202 		size_t size;
203 
204 		if (mimeType.GetIcon(&data, &size) != B_OK) {
205 			// didn't find an icon
206 			continue;
207 		}
208 
209 		vector_icon* icon = (vector_icon*)malloc(sizeof(vector_icon));
210 		if (icon == NULL) {
211 			// ran out of memory, delete the icon data
212 			delete[] data;
213 			continue;
214 		}
215 
216 		icon->data = data;
217 		icon->size = size;
218 
219 		// found a vector icon, add it to the list
220 		fVectorIcons.AddItem(icon);
221 		if (fVectorIcons.CountItems() >= kMaxIconCount) {
222 			// this is enough to choose from, stop eating memory...
223 			return;
224 		}
225 	}
226 }
227