xref: /haiku/src/kits/tracker/BackgroundImage.cpp (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 
35 //  Classes used for setting up and managing background images
36 
37 
38 #include <Bitmap.h>
39 #include <ControlLook.h>
40 #include <Node.h>
41 #include <TranslationKit.h>
42 #include <View.h>
43 #include <Window.h>
44 
45 #include <fs_attr.h>
46 
47 #include "BackgroundImage.h"
48 
49 #include "Background.h"
50 #include "Commands.h"
51 #include "PoseView.h"
52 
53 
54 namespace BPrivate {
55 
56 const char* kBackgroundImageInfo 			= B_BACKGROUND_INFO;
57 const char* kBackgroundImageInfoOffset 		= B_BACKGROUND_ORIGIN;
58 const char* kBackgroundImageInfoTextOutline	= B_BACKGROUND_TEXT_OUTLINE;
59 const char* kBackgroundImageInfoMode 		= B_BACKGROUND_MODE;
60 const char* kBackgroundImageInfoWorkspaces 	= B_BACKGROUND_WORKSPACES;
61 const char* kBackgroundImageInfoPath 		= B_BACKGROUND_IMAGE;
62 
63 }	// namespace BPrivate
64 
65 
66 //	#pragma mark - BackgroundImage
67 
68 
69 BackgroundImage*
70 BackgroundImage::GetBackgroundImage(const BNode* node, bool isDesktop)
71 {
72 	attr_info info;
73 	if (node->GetAttrInfo(kBackgroundImageInfo, &info) != B_OK)
74 		return NULL;
75 
76 	BMessage container;
77 	char* buffer = new char[info.size];
78 
79 	status_t error = node->ReadAttr(kBackgroundImageInfo, info.type, 0,
80 		buffer, (size_t)info.size);
81 	if (error == info.size)
82 		error = container.Unflatten(buffer);
83 
84 	delete[] buffer;
85 
86 	if (error != B_OK)
87 		return NULL;
88 
89 	BackgroundImage* backgroundImage = NULL;
90 	for (int32 index = 0; ; index++) {
91 		const char* path;
92 		uint32 workspaces = B_ALL_WORKSPACES;
93 		Mode mode = kTiled;
94 		bool textWidgetLabelOutline = false;
95 		BPoint offset;
96 		BBitmap* bitmap = NULL;
97 
98 		if (container.FindString(kBackgroundImageInfoPath, index, &path)
99 				== B_OK) {
100 			bitmap = BTranslationUtils::GetBitmap(path);
101 			if (!bitmap)
102 				PRINT(("failed to load background bitmap from path\n"));
103 		} else
104 			break;
105 
106 		if (isDesktop)
107 			be_control_look->SetBackgroundInfo(container);
108 
109 		container.FindInt32(kBackgroundImageInfoWorkspaces, index,
110 			(int32*)&workspaces);
111 		container.FindInt32(kBackgroundImageInfoMode, index, (int32*)&mode);
112 		container.FindBool(kBackgroundImageInfoTextOutline, index,
113 			&textWidgetLabelOutline);
114 		container.FindPoint(kBackgroundImageInfoOffset, index, &offset);
115 
116 		BackgroundImage::BackgroundImageInfo* imageInfo = new
117 			BackgroundImage::BackgroundImageInfo(workspaces, bitmap, mode,
118 				offset, textWidgetLabelOutline);
119 
120 		if (backgroundImage == NULL)
121 			backgroundImage = new BackgroundImage(node, isDesktop);
122 
123 		backgroundImage->Add(imageInfo);
124 	}
125 
126 	return backgroundImage;
127 }
128 
129 
130 BackgroundImage::BackgroundImageInfo::BackgroundImageInfo(uint32 workspaces,
131 	BBitmap* bitmap, Mode mode, BPoint offset, bool textWidgetOutline)
132 	:
133 	fWorkspace(workspaces),
134 	fBitmap(bitmap),
135 	fMode(mode),
136 	fOffset(offset),
137 	fTextWidgetOutline(textWidgetOutline)
138 {
139 }
140 
141 
142 BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo()
143 {
144 	delete fBitmap;
145 }
146 
147 
148 BackgroundImage::BackgroundImage(const BNode* node, bool desktop)
149 	:
150 	fIsDesktop(desktop),
151 	fDefinedByNode(*node),
152 	fView(NULL),
153 	fShowingBitmap(NULL),
154 	fBitmapForWorkspaceList(1, true)
155 {
156 }
157 
158 
159 BackgroundImage::~BackgroundImage()
160 {
161 }
162 
163 
164 void
165 BackgroundImage::Add(BackgroundImageInfo* info)
166 {
167 	fBitmapForWorkspaceList.AddItem(info);
168 }
169 
170 
171 void
172 BackgroundImage::Show(BView* view, int32 workspace)
173 {
174 	fView = view;
175 
176 	BackgroundImageInfo* info = ImageInfoForWorkspace(workspace);
177 	if (info) {
178 		BPoseView* poseView = dynamic_cast<BPoseView*>(fView);
179 		if (poseView != NULL)
180 			poseView->SetWidgetTextOutline(info->fTextWidgetOutline);
181 
182 		Show(info, fView);
183 	}
184 }
185 
186 
187 void
188 BackgroundImage::Show(BackgroundImageInfo* info, BView* view)
189 {
190 	BPoseView* poseView = dynamic_cast<BPoseView*>(view);
191 	if (poseView != NULL)
192 		poseView->SetWidgetTextOutline(info->fTextWidgetOutline);
193 
194 	if (info->fBitmap == NULL) {
195 		view->ClearViewBitmap();
196 		view->Invalidate();
197 		fShowingBitmap = info;
198 		return;
199 	}
200 	BRect viewBounds(view->Bounds());
201 	BRect bitmapBounds(info->fBitmap->Bounds());
202 	BRect destinationBitmapBounds(bitmapBounds);
203 
204 	uint32 options = 0;
205 	uint32 followFlags = B_FOLLOW_TOP | B_FOLLOW_LEFT;
206 
207 	// figure out the display mode and the destination bounds for the bitmap
208 	switch (info->fMode) {
209 		case kCentered:
210 			if (fIsDesktop) {
211 				destinationBitmapBounds.OffsetBy(
212 					(viewBounds.Width() - bitmapBounds.Width()) / 2,
213 					(viewBounds.Height() - bitmapBounds.Height()) / 2);
214 				break;
215 			}
216 			// else fall thru
217 		case kScaledToFit:
218 			if (fIsDesktop) {
219 				if (BRectRatio(destinationBitmapBounds)
220 						>= BRectRatio(viewBounds)) {
221 					float overlap = BRectHorizontalOverlap(viewBounds,
222 						destinationBitmapBounds);
223 					destinationBitmapBounds.Set(-overlap, 0,
224 						viewBounds.Width() + overlap, viewBounds.Height());
225 				} else {
226 					float overlap = BRectVerticalOverlap(viewBounds,
227 						destinationBitmapBounds);
228 					destinationBitmapBounds.Set(0, -overlap,
229 						viewBounds.Width(), viewBounds.Height() + overlap);
230 				}
231 				followFlags = B_FOLLOW_ALL;
232 				options |= B_FILTER_BITMAP_BILINEAR;
233 				break;
234 			}
235 			// else fall thru
236 		case kAtOffset:
237 			destinationBitmapBounds.OffsetTo(info->fOffset);
238 			break;
239 
240 		case kTiled:
241 			if (fIsDesktop) {
242 				destinationBitmapBounds.OffsetBy(
243 					(viewBounds.Width() - bitmapBounds.Width()) / 2,
244 					(viewBounds.Height() - bitmapBounds.Height()) / 2);
245 			}
246 			options |= B_TILE_BITMAP;
247 			break;
248 	}
249 
250 	// switch to the bitmap and force a redraw
251 	view->SetViewBitmap(info->fBitmap, bitmapBounds, destinationBitmapBounds,
252 		followFlags, options);
253 	view->Invalidate();
254 	fShowingBitmap = info;
255 }
256 
257 
258 float
259 BackgroundImage::BRectRatio(BRect rect)
260 {
261 	return rect.Width() / rect.Height();
262 }
263 
264 
265 float
266 BackgroundImage::BRectHorizontalOverlap(BRect hostRect, BRect resizedRect)
267 {
268 	return ((hostRect.Height() / resizedRect.Height() * resizedRect.Width())
269 		- hostRect.Width()) / 2;
270 }
271 
272 
273 float
274 BackgroundImage::BRectVerticalOverlap(BRect hostRect, BRect resizedRect)
275 {
276 	return ((hostRect.Width() / resizedRect.Width() * resizedRect.Height())
277 		- hostRect.Height()) / 2;
278 }
279 
280 
281 void
282 BackgroundImage::Remove()
283 {
284 	if (fShowingBitmap != NULL) {
285 		fView->ClearViewBitmap();
286 		fView->Invalidate();
287 		BPoseView* poseView = dynamic_cast<BPoseView*>(fView);
288 		// make sure text widgets draw the default way, erasing
289 		// their background
290 		if (poseView != NULL)
291 			poseView->SetWidgetTextOutline(true);
292 	}
293 
294 	fShowingBitmap = NULL;
295 }
296 
297 
298 BackgroundImage::BackgroundImageInfo*
299 BackgroundImage::ImageInfoForWorkspace(int32 workspace) const
300 {
301 	uint32 workspaceMask = 1;
302 
303 	for ( ; workspace; workspace--)
304 		workspaceMask *= 2;
305 
306 	int32 count = fBitmapForWorkspaceList.CountItems();
307 
308 	// do a simple lookup for the most likely candidate bitmap -
309 	// pick the imageInfo that is only defined for this workspace over one
310 	// that supports multiple workspaces
311 	BackgroundImageInfo* result = NULL;
312 	for (int32 index = 0; index < count; index++) {
313 		BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index);
314 		if (info->fWorkspace == workspaceMask)
315 			return info;
316 
317 		if (info->fWorkspace & workspaceMask)
318 			result = info;
319 	}
320 
321 	return result;
322 }
323 
324 
325 void
326 BackgroundImage::WorkspaceActivated(BView* view, int32 workspace, bool state)
327 {
328 	if (!fIsDesktop) {
329 		// we only care for desktop bitmaps
330 		return;
331 	}
332 
333 	if (!state) {
334 		// we only care comming into a new workspace, not leaving one
335 		return;
336 	}
337 
338 	BackgroundImageInfo* info = ImageInfoForWorkspace(workspace);
339 	if (info != fShowingBitmap) {
340 		if (info != NULL)
341 			Show(info, view);
342 		else {
343 			BPoseView* poseView = dynamic_cast<BPoseView*>(view);
344 			if (poseView != NULL)
345 				poseView->SetWidgetTextOutline(true);
346 
347 			view->ClearViewBitmap();
348 			view->Invalidate();
349 		}
350 
351 		fShowingBitmap = info;
352 	}
353 }
354 
355 
356 void
357 BackgroundImage::ScreenChanged(BRect, color_space)
358 {
359 	if (!fIsDesktop || fShowingBitmap == NULL || fShowingBitmap->fBitmap == NULL)
360 		return;
361 
362 	if (fShowingBitmap->fMode == kCentered) {
363 		BRect viewBounds(fView->Bounds());
364 		BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds());
365 		BRect destinationBitmapBounds(bitmapBounds);
366 		destinationBitmapBounds.OffsetBy(
367 			(viewBounds.Width() - bitmapBounds.Width()) / 2,
368 			(viewBounds.Height() - bitmapBounds.Height()) / 2);
369 
370 		fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds,
371 			destinationBitmapBounds, B_FOLLOW_NONE, 0);
372 		fView->Invalidate();
373 	}
374 }
375 
376 
377 BackgroundImage*
378 BackgroundImage::Refresh(BackgroundImage* oldBackgroundImage,
379 	const BNode* fromNode, bool desktop, BPoseView* poseView)
380 {
381 	if (oldBackgroundImage != NULL) {
382 		oldBackgroundImage->Remove();
383 		delete oldBackgroundImage;
384 	}
385 
386 	BackgroundImage* backgroundImage = GetBackgroundImage(fromNode, desktop);
387 	if (backgroundImage != NULL && poseView->ViewMode() != kListMode)
388 		backgroundImage->Show(poseView, current_workspace());
389 
390 	return backgroundImage;
391 }
392