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