xref: /haiku/src/kits/tracker/BackgroundImage.cpp (revision f75a7bf508f3156d63a14f8fd77c5e0ca4d08c42)
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 <Node.h>
40 #include <TranslationKit.h>
41 #include <View.h>
42 #include <Window.h>
43 
44 #include <fs_attr.h>
45 
46 #include "BackgroundImage.h"
47 
48 #include "Background.h"
49 #include "Commands.h"
50 #include "PoseView.h"
51 
52 namespace BPrivate {
53 
54 const char *kBackgroundImageInfo 			= B_BACKGROUND_INFO;
55 const char *kBackgroundImageInfoOffset 		= B_BACKGROUND_ORIGIN;
56 const char *kBackgroundImageInfoTextOutline	= B_BACKGROUND_TEXT_OUTLINE;
57 const char *kBackgroundImageInfoMode 		= B_BACKGROUND_MODE;
58 const char *kBackgroundImageInfoWorkspaces 	= B_BACKGROUND_WORKSPACES;
59 const char *kBackgroundImageInfoPath 		= B_BACKGROUND_IMAGE;
60 
61 }
62 
63 BackgroundImage *
64 BackgroundImage::GetBackgroundImage(const BNode *node, bool isDesktop)
65 {
66 	attr_info info;
67 	if (node->GetAttrInfo(kBackgroundImageInfo, &info) != B_OK)
68 		return NULL;
69 
70 	BMessage container;
71 	char *buffer = new char [info.size];
72 
73 	status_t error = node->ReadAttr(kBackgroundImageInfo, info.type, 0, buffer, (size_t)info.size);
74 	if (error == info.size)
75 		error = container.Unflatten(buffer);
76 
77 	delete [] buffer;
78 
79 	if (error != B_OK)
80 		return NULL;
81 
82 	BackgroundImage *result = NULL;
83 	for (int32 index = 0; ; index++) {
84 		const char *path;
85 		uint32 workspaces = B_ALL_WORKSPACES;
86 		Mode mode = kTiled;
87 		bool textWidgetLabelOutline = false;
88 		BPoint offset;
89 
90 		if (container.FindString(kBackgroundImageInfoPath, index, &path) != B_OK)
91 			break;
92 
93 		BBitmap *bitmap = BTranslationUtils::GetBitmap(path);
94 		if (!bitmap) {
95 //			PRINT(("failed to load background bitmap from path\n"));
96 			continue;
97 		}
98 
99 		container.FindInt32(kBackgroundImageInfoWorkspaces, index, (int32 *)&workspaces);
100 		container.FindInt32(kBackgroundImageInfoMode, index, (int32 *)&mode);
101 		container.FindBool(kBackgroundImageInfoTextOutline, index, &textWidgetLabelOutline);
102 		container.FindPoint(kBackgroundImageInfoOffset, index, &offset);
103 
104 		BackgroundImage::BackgroundImageInfo *imageInfo = new
105 			BackgroundImage::BackgroundImageInfo(workspaces, bitmap, mode, offset,
106 				textWidgetLabelOutline);
107 
108 		if (!result)
109 			result = new BackgroundImage(node, isDesktop);
110 
111 		result->Add(imageInfo);
112 	}
113 	return result;
114 }
115 
116 
117 BackgroundImage::BackgroundImageInfo::BackgroundImageInfo(uint32 workspaces,
118 	BBitmap *bitmap, Mode mode, BPoint offset, bool textWidgetOutline)
119 	:	fWorkspace(workspaces),
120 		fBitmap(bitmap),
121 		fMode(mode),
122 		fOffset(offset),
123 		fTextWidgetOutline(textWidgetOutline)
124 {
125 }
126 
127 
128 BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo()
129 {
130 	delete fBitmap;
131 }
132 
133 
134 BackgroundImage::BackgroundImage(const BNode *node, bool desktop)
135 	:	fIsDesktop(desktop),
136 		fDefinedByNode(*node),
137 		fView(NULL),
138 		fShowingBitmap(NULL),
139 		fBitmapForWorkspaceList(1, true)
140 {
141 }
142 
143 BackgroundImage::~BackgroundImage()
144 {
145 }
146 
147 
148 void
149 BackgroundImage::Add(BackgroundImageInfo *info)
150 {
151 	fBitmapForWorkspaceList.AddItem(info);
152 }
153 
154 void
155 BackgroundImage::Show(BView *view, int32 workspace)
156 {
157 	fView = view;
158 
159 	BackgroundImageInfo *info = ImageInfoForWorkspace(workspace);
160 	if (info) {
161 		BPoseView *poseView = dynamic_cast<BPoseView *>(fView);
162 		if (poseView)
163 			poseView->SetWidgetTextOutline(info->fTextWidgetOutline);
164 		Show(info, fView);
165 	}
166 }
167 
168 void
169 BackgroundImage::Show(BackgroundImageInfo *info, BView *view)
170 {
171 	BRect viewBounds(view->Bounds());
172 	BRect bitmapBounds(info->fBitmap->Bounds());
173 	BRect destinationBitmapBounds(bitmapBounds);
174 
175 	uint32 tile = 0;
176 	uint32 followFlags = B_FOLLOW_TOP | B_FOLLOW_LEFT;
177 
178 	// figure out the display mode and the destination bounds for the bitmap
179 	switch (info->fMode) {
180 		case kCentered:
181 			if (fIsDesktop) {
182 				destinationBitmapBounds.OffsetBy(
183 					(viewBounds.Width() - bitmapBounds.Width()) / 2,
184 					(viewBounds.Height() - bitmapBounds.Height()) / 2);
185 				break;
186 			}
187 			// else fall thru
188 		case kScaledToFit:
189 			if (fIsDesktop) {
190 				destinationBitmapBounds = viewBounds;
191 				followFlags = B_FOLLOW_ALL;
192 				break;
193 			}
194 			// else fall thru
195 		case kAtOffset:
196 			destinationBitmapBounds.OffsetTo(info->fOffset);
197 			break;
198 		case kTiled:
199 			if (fIsDesktop) {
200 				destinationBitmapBounds.OffsetBy(
201 					(viewBounds.Width() - bitmapBounds.Width()) / 2,
202 					(viewBounds.Height() - bitmapBounds.Height()) / 2);
203 			}
204 			tile = B_TILE_BITMAP;
205 			break;
206 	}
207 
208 	BPoseView *poseView = dynamic_cast<BPoseView *>(view);
209 	if (poseView)
210 		poseView->SetWidgetTextOutline(info->fTextWidgetOutline);
211 
212 	// switch to the bitmap and force a redraw
213 	view->SetViewBitmap(info->fBitmap, bitmapBounds, destinationBitmapBounds,
214 		followFlags, tile);
215 	view->Invalidate();
216 
217 	fShowingBitmap = info;
218 }
219 
220 void
221 BackgroundImage::Remove()
222 {
223 	if (fShowingBitmap) {
224 		fView->ClearViewBitmap();
225 		fView->Invalidate();
226 		BPoseView *poseView = dynamic_cast<BPoseView *>(fView);
227 		// make sure text widgets draw the default way, erasing their background
228 		if (poseView)
229 			poseView->SetWidgetTextOutline(true);
230 	}
231 	fShowingBitmap = NULL;
232 }
233 
234 BackgroundImage::BackgroundImageInfo *
235 BackgroundImage::ImageInfoForWorkspace(int32 workspace) const
236 {
237 	uint32 workspaceMask = 1;
238 
239 	for ( ; workspace; workspace--)
240 		workspaceMask *= 2;
241 
242 	int32 count = fBitmapForWorkspaceList.CountItems();
243 
244 	// do a simple lookup for the most likely candidate bitmap -
245 	// pick the imageInfo that is only defined for this workspace over one
246 	// that supports multiple workspaces
247 	BackgroundImageInfo *result = NULL;
248 	for (int32 index = 0; index < count; index++) {
249 		BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index);
250 		if (info->fWorkspace == workspaceMask)
251 			return info;
252 		if (info->fWorkspace & workspaceMask)
253 			result = info;
254 	}
255 
256 	return result;
257 }
258 
259 void
260 BackgroundImage::WorkspaceActivated(BView *view, int32 workspace, bool state)
261 {
262 	if (!fIsDesktop)
263 		// we only care for desktop bitmaps
264 		return;
265 
266 	if (!state)
267 		// we only care comming into a new workspace, not leaving one
268 		return;
269 
270 	BackgroundImageInfo *info = ImageInfoForWorkspace(workspace);
271 	if (info != fShowingBitmap) {
272 		if (info)
273 			Show(info, view);
274 		else {
275 			if (BPoseView *poseView = dynamic_cast<BPoseView *>(view))
276 				poseView->SetWidgetTextOutline(true);
277 			view->ClearViewBitmap();
278 			view->Invalidate();
279 		}
280 		fShowingBitmap = info;
281 	}
282 }
283 
284 void
285 BackgroundImage::ScreenChanged(BRect, color_space)
286 {
287 	if (!fIsDesktop || !fShowingBitmap)
288 		return;
289 
290 	if (fShowingBitmap->fMode == kCentered) {
291 		BRect viewBounds(fView->Bounds());
292 		BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds());
293 		BRect destinationBitmapBounds(bitmapBounds);
294 		destinationBitmapBounds.OffsetBy(
295 			(viewBounds.Width() - bitmapBounds.Width()) / 2,
296 			(viewBounds.Height() - bitmapBounds.Height()) / 2);
297 
298 		fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds, destinationBitmapBounds,
299 			B_FOLLOW_NONE, 0);
300 		fView->Invalidate();
301 	}
302 }
303 
304 BackgroundImage *
305 BackgroundImage::Refresh(BackgroundImage *oldBackgroundImage,
306 	const BNode *fromNode, bool desktop, BPoseView *poseView)
307 {
308 	if (oldBackgroundImage) {
309 		oldBackgroundImage->Remove();
310 		delete oldBackgroundImage;
311 	}
312 
313 	BackgroundImage *result = GetBackgroundImage(fromNode, desktop);
314 	if (result && poseView->ViewMode() != kListMode)
315 		result->Show(poseView, current_workspace());
316 
317 	return result;
318 }
319 
320