xref: /haiku/src/kits/tracker/BackgroundImage.cpp (revision 4fd62caa9acc437534c41bbb7d3fc9d53e915005)
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 tile = 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 				break;
229 			}
230 			// else fall thru
231 		case kAtOffset:
232 			destinationBitmapBounds.OffsetTo(info->fOffset);
233 			break;
234 		case kTiled:
235 			if (fIsDesktop) {
236 				destinationBitmapBounds.OffsetBy(
237 					(viewBounds.Width() - bitmapBounds.Width()) / 2,
238 					(viewBounds.Height() - bitmapBounds.Height()) / 2);
239 			}
240 			tile = B_TILE_BITMAP;
241 			break;
242 	}
243 
244 	// switch to the bitmap and force a redraw
245 	view->SetViewBitmap(info->fBitmap, bitmapBounds, destinationBitmapBounds,
246 		followFlags, tile);
247 	view->Invalidate();
248 	fShowingBitmap = info;
249 }
250 
251 
252 float
253 BackgroundImage::BRectRatio(BRect rect)
254 {
255 	return rect.Width() / rect.Height();
256 }
257 
258 
259 float
260 BackgroundImage::BRectHorizontalOverlap(BRect hostRect, BRect resizedRect)
261 {
262 	return ((hostRect.Height() / resizedRect.Height() * resizedRect.Width())
263 		- hostRect.Width()) / 2;
264 }
265 
266 
267 float
268 BackgroundImage::BRectVerticalOverlap(BRect hostRect, BRect resizedRect)
269 {
270 	return ((hostRect.Width() / resizedRect.Width() * resizedRect.Height())
271 		- hostRect.Height()) / 2;
272 }
273 
274 
275 void
276 BackgroundImage::Remove()
277 {
278 	if (fShowingBitmap) {
279 		fView->ClearViewBitmap();
280 		fView->Invalidate();
281 		BPoseView* poseView = dynamic_cast<BPoseView*>(fView);
282 		// make sure text widgets draw the default way, erasing
283 		// their background
284 		if (poseView)
285 			poseView->SetWidgetTextOutline(true);
286 	}
287 	fShowingBitmap = NULL;
288 }
289 
290 
291 BackgroundImage::BackgroundImageInfo*
292 BackgroundImage::ImageInfoForWorkspace(int32 workspace) const
293 {
294 	uint32 workspaceMask = 1;
295 
296 	for ( ; workspace; workspace--)
297 		workspaceMask *= 2;
298 
299 	int32 count = fBitmapForWorkspaceList.CountItems();
300 
301 	// do a simple lookup for the most likely candidate bitmap -
302 	// pick the imageInfo that is only defined for this workspace over one
303 	// that supports multiple workspaces
304 	BackgroundImageInfo* result = NULL;
305 	for (int32 index = 0; index < count; index++) {
306 		BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index);
307 		if (info->fWorkspace == workspaceMask)
308 			return info;
309 		if (info->fWorkspace & workspaceMask)
310 			result = info;
311 	}
312 
313 	return result;
314 }
315 
316 
317 void
318 BackgroundImage::WorkspaceActivated(BView* view, int32 workspace, bool state)
319 {
320 	if (!fIsDesktop)
321 		// we only care for desktop bitmaps
322 		return;
323 
324 	if (!state)
325 		// we only care comming into a new workspace, not leaving one
326 		return;
327 
328 	BackgroundImageInfo* info = ImageInfoForWorkspace(workspace);
329 
330 	if (info != fShowingBitmap) {
331 		if (info)
332 			Show(info, view);
333 		else {
334 			if (BPoseView* poseView = dynamic_cast<BPoseView*>(view))
335 				poseView->SetWidgetTextOutline(true);
336 			view->ClearViewBitmap();
337 			view->Invalidate();
338 		}
339 		fShowingBitmap = info;
340 	}
341 }
342 
343 
344 void
345 BackgroundImage::ScreenChanged(BRect, color_space)
346 {
347 	if (!fIsDesktop || !fShowingBitmap)
348 		return;
349 
350 	if (fShowingBitmap->fMode == kCentered) {
351 		BRect viewBounds(fView->Bounds());
352 		BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds());
353 		BRect destinationBitmapBounds(bitmapBounds);
354 		destinationBitmapBounds.OffsetBy(
355 			(viewBounds.Width() - bitmapBounds.Width()) / 2,
356 			(viewBounds.Height() - bitmapBounds.Height()) / 2);
357 
358 		fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds,
359 			destinationBitmapBounds, B_FOLLOW_NONE, 0);
360 		fView->Invalidate();
361 	}
362 }
363 
364 
365 BackgroundImage*
366 BackgroundImage::Refresh(BackgroundImage* oldBackgroundImage,
367 	const BNode* fromNode, bool desktop, BPoseView* poseView)
368 {
369 	if (oldBackgroundImage) {
370 		oldBackgroundImage->Remove();
371 		delete oldBackgroundImage;
372 	}
373 
374 	BackgroundImage* result = GetBackgroundImage(fromNode, desktop);
375 	if (result && poseView->ViewMode() != kListMode)
376 		result->Show(poseView, current_workspace());
377 
378 	return result;
379 }
380