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