xref: /haiku/src/kits/tracker/BackgroundImage.cpp (revision 32832cbe47f991cc6d2b29824903181d8baaaa63)
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 				continue;
104 			}
105 		} else
106 			break;
107 
108 		if (be_control_look != NULL && isDesktop) {
109 			be_control_look->SetBackgroundInfo(container);
110 		}
111 
112 		container.FindInt32(kBackgroundImageInfoWorkspaces, index,
113 			(int32*)&workspaces);
114 		container.FindInt32(kBackgroundImageInfoMode, index, (int32*)&mode);
115 		container.FindBool(kBackgroundImageInfoTextOutline, index,
116 			&textWidgetLabelOutline);
117 		container.FindPoint(kBackgroundImageInfoOffset, index, &offset);
118 
119 		BackgroundImage::BackgroundImageInfo* imageInfo = new
120 			BackgroundImage::BackgroundImageInfo(workspaces, bitmap, mode,
121 				offset, textWidgetLabelOutline);
122 
123 		if (backgroundImage == NULL)
124 			backgroundImage = new BackgroundImage(node, isDesktop);
125 
126 		backgroundImage->Add(imageInfo);
127 	}
128 
129 	return backgroundImage;
130 }
131 
132 
133 BackgroundImage::BackgroundImageInfo::BackgroundImageInfo(uint32 workspaces,
134 	BBitmap* bitmap, Mode mode, BPoint offset, bool textWidgetOutline)
135 	:
136 	fWorkspace(workspaces),
137 	fBitmap(bitmap),
138 	fMode(mode),
139 	fOffset(offset),
140 	fTextWidgetOutline(textWidgetOutline)
141 {
142 }
143 
144 
145 BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo()
146 {
147 	delete fBitmap;
148 }
149 
150 
151 BackgroundImage::BackgroundImage(const BNode* node, bool desktop)
152 	:
153 	fIsDesktop(desktop),
154 	fDefinedByNode(*node),
155 	fView(NULL),
156 	fShowingBitmap(NULL),
157 	fBitmapForWorkspaceList(1, true)
158 {
159 }
160 
161 
162 BackgroundImage::~BackgroundImage()
163 {
164 }
165 
166 
167 void
168 BackgroundImage::Add(BackgroundImageInfo* info)
169 {
170 	fBitmapForWorkspaceList.AddItem(info);
171 }
172 
173 
174 void
175 BackgroundImage::Show(BView* view, int32 workspace)
176 {
177 	fView = view;
178 
179 	BackgroundImageInfo* info = ImageInfoForWorkspace(workspace);
180 	if (info) {
181 		BPoseView* poseView = dynamic_cast<BPoseView*>(fView);
182 		if (poseView)
183 			poseView->SetWidgetTextOutline(info->fTextWidgetOutline);
184 		Show(info, fView);
185 	}
186 }
187 
188 
189 void
190 BackgroundImage::Show(BackgroundImageInfo* info, BView* view)
191 {
192 	BPoseView* poseView = dynamic_cast<BPoseView*>(view);
193 	if (poseView)
194 		poseView->SetWidgetTextOutline(info->fTextWidgetOutline);
195 
196 	if (info->fBitmap == NULL) {
197 		view->ClearViewBitmap();
198 		view->Invalidate();
199 		fShowingBitmap = info;
200 		return;
201 	}
202 	BRect viewBounds(view->Bounds());
203 	BRect bitmapBounds(info->fBitmap->Bounds());
204 	BRect destinationBitmapBounds(bitmapBounds);
205 
206 	uint32 options = 0;
207 	uint32 followFlags = B_FOLLOW_TOP | B_FOLLOW_LEFT;
208 
209 	// figure out the display mode and the destination bounds for the bitmap
210 	switch (info->fMode) {
211 		case kCentered:
212 			if (fIsDesktop) {
213 				destinationBitmapBounds.OffsetBy(
214 					(viewBounds.Width() - bitmapBounds.Width()) / 2,
215 					(viewBounds.Height() - bitmapBounds.Height()) / 2);
216 				break;
217 			}
218 			// else fall thru
219 		case kScaledToFit:
220 			if (fIsDesktop) {
221 				if (BRectRatio(destinationBitmapBounds)
222 						>= BRectRatio(viewBounds)) {
223 					float overlap = BRectHorizontalOverlap(viewBounds,
224 						destinationBitmapBounds);
225 					destinationBitmapBounds.Set(-overlap, 0,
226 						viewBounds.Width() + overlap, viewBounds.Height());
227 				} else {
228 					float overlap = BRectVerticalOverlap(viewBounds,
229 						destinationBitmapBounds);
230 					destinationBitmapBounds.Set(0, -overlap,
231 						viewBounds.Width(), viewBounds.Height() + overlap);
232 				}
233 				followFlags = B_FOLLOW_ALL;
234 				options |= B_FILTER_BITMAP_BILINEAR;
235 				break;
236 			}
237 			// else fall thru
238 		case kAtOffset:
239 			destinationBitmapBounds.OffsetTo(info->fOffset);
240 			break;
241 
242 		case kTiled:
243 			if (fIsDesktop) {
244 				destinationBitmapBounds.OffsetBy(
245 					(viewBounds.Width() - bitmapBounds.Width()) / 2,
246 					(viewBounds.Height() - bitmapBounds.Height()) / 2);
247 			}
248 			options |= B_TILE_BITMAP;
249 			break;
250 	}
251 
252 	// switch to the bitmap and force a redraw
253 	view->SetViewBitmap(info->fBitmap, bitmapBounds, destinationBitmapBounds,
254 		followFlags, options);
255 	view->Invalidate();
256 	fShowingBitmap = info;
257 }
258 
259 
260 float
261 BackgroundImage::BRectRatio(BRect rect)
262 {
263 	return rect.Width() / rect.Height();
264 }
265 
266 
267 float
268 BackgroundImage::BRectHorizontalOverlap(BRect hostRect, BRect resizedRect)
269 {
270 	return ((hostRect.Height() / resizedRect.Height() * resizedRect.Width())
271 		- hostRect.Width()) / 2;
272 }
273 
274 
275 float
276 BackgroundImage::BRectVerticalOverlap(BRect hostRect, BRect resizedRect)
277 {
278 	return ((hostRect.Width() / resizedRect.Width() * resizedRect.Height())
279 		- hostRect.Height()) / 2;
280 }
281 
282 
283 void
284 BackgroundImage::Remove()
285 {
286 	if (fShowingBitmap != NULL) {
287 		fView->ClearViewBitmap();
288 		fView->Invalidate();
289 		BPoseView* poseView = dynamic_cast<BPoseView*>(fView);
290 		// make sure text widgets draw the default way, erasing
291 		// their background
292 		if (poseView != NULL)
293 			poseView->SetWidgetTextOutline(true);
294 	}
295 
296 	fShowingBitmap = NULL;
297 }
298 
299 
300 BackgroundImage::BackgroundImageInfo*
301 BackgroundImage::ImageInfoForWorkspace(int32 workspace) const
302 {
303 	uint32 workspaceMask = 1;
304 
305 	for ( ; workspace; workspace--)
306 		workspaceMask *= 2;
307 
308 	int32 count = fBitmapForWorkspaceList.CountItems();
309 
310 	// do a simple lookup for the most likely candidate bitmap -
311 	// pick the imageInfo that is only defined for this workspace over one
312 	// that supports multiple workspaces
313 	BackgroundImageInfo* result = NULL;
314 	for (int32 index = 0; index < count; index++) {
315 		BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index);
316 		if (info->fWorkspace == workspaceMask)
317 			return info;
318 
319 		if (info->fWorkspace & workspaceMask)
320 			result = info;
321 	}
322 
323 	return result;
324 }
325 
326 
327 void
328 BackgroundImage::WorkspaceActivated(BView* view, int32 workspace, bool state)
329 {
330 	if (!fIsDesktop) {
331 		// we only care for desktop bitmaps
332 		return;
333 	}
334 
335 	if (!state) {
336 		// we only care comming into a new workspace, not leaving one
337 		return;
338 	}
339 
340 	BackgroundImageInfo* info = ImageInfoForWorkspace(workspace);
341 	if (info != fShowingBitmap) {
342 		if (info != NULL)
343 			Show(info, view);
344 		else {
345 			BPoseView* poseView = dynamic_cast<BPoseView*>(view);
346 			if (poseView != NULL)
347 				poseView->SetWidgetTextOutline(true);
348 
349 			view->ClearViewBitmap();
350 			view->Invalidate();
351 		}
352 
353 		fShowingBitmap = info;
354 	}
355 }
356 
357 
358 void
359 BackgroundImage::ScreenChanged(BRect, color_space)
360 {
361 	if (!fIsDesktop || fShowingBitmap == NULL)
362 		return;
363 
364 	if (fShowingBitmap->fMode == kCentered) {
365 		BRect viewBounds(fView->Bounds());
366 		BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds());
367 		BRect destinationBitmapBounds(bitmapBounds);
368 		destinationBitmapBounds.OffsetBy(
369 			(viewBounds.Width() - bitmapBounds.Width()) / 2,
370 			(viewBounds.Height() - bitmapBounds.Height()) / 2);
371 
372 		fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds,
373 			destinationBitmapBounds, B_FOLLOW_NONE, 0);
374 		fView->Invalidate();
375 	}
376 }
377 
378 
379 BackgroundImage*
380 BackgroundImage::Refresh(BackgroundImage* oldBackgroundImage,
381 	const BNode* fromNode, bool desktop, BPoseView* poseView)
382 {
383 	if (oldBackgroundImage != NULL) {
384 		oldBackgroundImage->Remove();
385 		delete oldBackgroundImage;
386 	}
387 
388 	BackgroundImage* backgroundImage = GetBackgroundImage(fromNode, desktop);
389 	if (backgroundImage != NULL && poseView->ViewMode() != kListMode)
390 		backgroundImage->Show(poseView, current_workspace());
391 
392 	return backgroundImage;
393 }
394