xref: /haiku/src/kits/tracker/IconMenuItem.cpp (revision 3ecb7fb4415b319b6aac606551d51efad21037df)
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 //! Menu items with small icons.
36 
37 
38 #include "IconCache.h"
39 #include "IconMenuItem.h"
40 
41 #include <Debug.h>
42 #include <Menu.h>
43 #include <NodeInfo.h>
44 
45 
46 static void
47 DimmedIconBlitter(BView* view, BPoint where, BBitmap* bitmap, void*)
48 {
49 	if (bitmap->ColorSpace() == B_RGBA32) {
50 		rgb_color oldHighColor = view->HighColor();
51 		view->SetHighColor(0, 0, 0, 128);
52 		view->SetDrawingMode(B_OP_ALPHA);
53 		view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
54 		view->DrawBitmap(bitmap, where);
55 		view->SetHighColor(oldHighColor);
56 	} else {
57 		view->SetDrawingMode(B_OP_BLEND);
58 		view->DrawBitmap(bitmap, where);
59 	}
60 	view->SetDrawingMode(B_OP_OVER);
61 }
62 
63 
64 //	#pragma mark - ModelMenuItem
65 
66 
67 ModelMenuItem::ModelMenuItem(const Model* model, const char* title,
68 	BMessage* message, char shortcut, uint32 modifiers,
69 	bool drawText, bool extraPad)
70 	:
71 	BMenuItem(title, message, shortcut, modifiers),
72 	fModel(*model),
73 	fHeightDelta(0),
74 	fDrawText(drawText),
75 	fExtraPad(extraPad)
76 {
77 	ThrowOnInitCheckError(&fModel);
78 	// The 'fExtraPad' field is used to when this menu item is added to
79 	// a menubar instead of a menu. Menus and MenuBars space out items
80 	// differently (more space around items in a menu). This class wants
81 	// to be able to space item the same, no matter where they are. The
82 	// fExtraPad field allows for that.
83 
84 	if (model->IsRoot())
85 		SetLabel(model->Name());
86 
87 	// ModelMenuItem is used in synchronously invoked menus, make sure
88 	// we invoke with a timeout
89 	SetTimeout(kSynchMenuInvokeTimeout);
90 }
91 
92 
93 ModelMenuItem::ModelMenuItem(const Model* model, BMenu* menu, bool drawText,
94 	bool extraPad)
95 	:
96 	BMenuItem(menu),
97 	fModel(*model),
98 	fHeightDelta(0),
99 	fDrawText(drawText),
100 	fExtraPad(extraPad)
101 {
102 	ThrowOnInitCheckError(&fModel);
103 	// ModelMenuItem is used in synchronously invoked menus, make sure
104 	// we invoke with a timeout
105 	SetTimeout(kSynchMenuInvokeTimeout);
106 }
107 
108 
109 ModelMenuItem::~ModelMenuItem()
110 {
111 }
112 
113 
114 status_t
115 ModelMenuItem::SetEntry(const BEntry* entry)
116 {
117 	return fModel.SetTo(entry);
118 }
119 
120 
121 void
122 ModelMenuItem::DrawContent()
123 {
124 	if (fDrawText) {
125 		BPoint drawPoint(ContentLocation());
126 		drawPoint.x += 20 + (fExtraPad ? 6 : 0);
127 		if (fHeightDelta > 0)
128 			drawPoint.y += ceil(fHeightDelta / 2);
129 		Menu()->MovePenTo(drawPoint);
130 		_inherited::DrawContent();
131 	}
132 	DrawIcon();
133 }
134 
135 
136 void
137 ModelMenuItem::Highlight(bool hilited)
138 {
139 	_inherited::Highlight(hilited);
140 	DrawIcon();
141 }
142 
143 
144 void
145 ModelMenuItem::DrawIcon()
146 {
147 	Menu()->PushState();
148 
149 	BPoint where(ContentLocation());
150 	// center icon with text.
151 
152 	float deltaHeight = fHeightDelta < 0 ? -fHeightDelta : 0;
153 	where.y += ceil(deltaHeight / 2);
154 
155 	if (fExtraPad)
156 		where.x += 6;
157 
158 	Menu()->SetDrawingMode(B_OP_OVER);
159 	Menu()->SetLowColor(B_TRANSPARENT_32_BIT);
160 
161 	// draw small icon, synchronously
162 	if (IsEnabled()) {
163 		IconCache::sIconCache->Draw(fModel.ResolveIfLink(), Menu(), where,
164 			kNormalIcon, B_MINI_ICON);
165 	} else {
166 		// dimmed, for now use a special blitter; icon cache should
167 		// know how to blit one eventually
168 		IconCache::sIconCache->SyncDraw(fModel.ResolveIfLink(), Menu(), where,
169 			kNormalIcon, B_MINI_ICON, DimmedIconBlitter);
170 	}
171 
172 	Menu()->PopState();
173 }
174 
175 
176 void
177 ModelMenuItem::GetContentSize(float* width, float* height)
178 {
179 	_inherited::GetContentSize(width, height);
180 	fHeightDelta = 16 - *height;
181 	if (*height < 16)
182 		*height = 16;
183 	*width = *width + 20 + (fExtraPad ? 18 : 0);
184 }
185 
186 
187 status_t
188 ModelMenuItem::Invoke(BMessage* message)
189 {
190 	if (Menu() == NULL)
191 		return B_ERROR;
192 
193 	if (!IsEnabled())
194 		return B_ERROR;
195 
196 	if (message == NULL)
197 		message = Message();
198 
199 	if (message == NULL)
200 		return B_BAD_VALUE;
201 
202 	BMessage clone(*message);
203 	clone.AddInt32("index", Menu()->IndexOf(this));
204 	clone.AddInt64("when", system_time());
205 	clone.AddPointer("source", this);
206 
207 	if ((modifiers() & B_OPTION_KEY) == 0) {
208 		// if option not held, remove refs to close to prevent closing
209 		// parent window
210 		clone.RemoveData("nodeRefsToClose");
211 	}
212 
213 	return BInvoker::Invoke(&clone);
214 }
215 
216 
217 //	#pragma mark - SpecialModelMenuItem
218 
219 
220 /*!	A ModelMenuItem subclass that draws its label in italics.
221 
222 	It's used for example in the "Copy To" menu to indicate some special
223 	folders like the parent folder.
224 */
225 SpecialModelMenuItem::SpecialModelMenuItem(const Model* model, BMenu* menu)
226 	: ModelMenuItem(model, menu)
227 {
228 }
229 
230 
231 void
232 SpecialModelMenuItem::DrawContent()
233 {
234 	Menu()->PushState();
235 
236 	BFont font;
237 	Menu()->GetFont(&font);
238 	font.SetFace(B_ITALIC_FACE);
239 	Menu()->SetFont(&font);
240 
241 	_inherited::DrawContent();
242 	Menu()->PopState();
243 }
244 
245 
246 //	#pragma mark - IconMenuItem
247 
248 
249 /*!	A menu item that draws an icon alongside the label.
250 
251 	It's currently used in the mount and new file template menus.
252 */
253 IconMenuItem::IconMenuItem(const char* label, BMessage* message, BBitmap* icon)
254 	:
255 	PositionPassingMenuItem(label, message),
256 	fDeviceIcon(icon),
257 	fHeightDelta(0)
258 {
259 	// IconMenuItem is used in synchronously invoked menus, make sure
260 	// we invoke with a timeout
261 	SetTimeout(kSynchMenuInvokeTimeout);
262 }
263 
264 
265 IconMenuItem::IconMenuItem(const char* label, BMessage* message,
266 	const BNodeInfo* nodeInfo, icon_size which)
267 	:
268 	PositionPassingMenuItem(label, message),
269 	fDeviceIcon(NULL),
270 	fHeightDelta(0)
271 {
272 	if (nodeInfo != NULL) {
273 		fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1),
274 			kDefaultIconDepth);
275 
276 		if (nodeInfo->GetTrackerIcon(fDeviceIcon, B_MINI_ICON)) {
277 			delete fDeviceIcon;
278 			fDeviceIcon = NULL;
279 		}
280 	}
281 
282 	// IconMenuItem is used in synchronously invoked menus, make sure
283 	// we invoke with a timeout
284 	SetTimeout(kSynchMenuInvokeTimeout);
285 }
286 
287 
288 IconMenuItem::IconMenuItem(const char* label, BMessage* message,
289 	const char* iconType, icon_size which)
290 	:
291 	PositionPassingMenuItem(label, message),
292 	fDeviceIcon(NULL),
293 	fHeightDelta(0)
294 {
295 	BMimeType mime(iconType);
296 	fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1),
297 		kDefaultIconDepth);
298 
299 	if (mime.GetIcon(fDeviceIcon, which) != B_OK) {
300 		BMimeType super;
301 		mime.GetSupertype(&super);
302 		if (super.GetIcon(fDeviceIcon, which) != B_OK) {
303 			delete fDeviceIcon;
304 			fDeviceIcon = NULL;
305 		}
306 	}
307 
308 	// IconMenuItem is used in synchronously invoked menus, make sure
309 	// we invoke with a timeout
310 	SetTimeout(kSynchMenuInvokeTimeout);
311 }
312 
313 
314 IconMenuItem::IconMenuItem(BMenu* submenu, BMessage* message,
315 	const char* iconType, icon_size which)
316 	:
317 	PositionPassingMenuItem(submenu, message),
318 	fDeviceIcon(NULL),
319 	fHeightDelta(0)
320 {
321 	BMimeType mime(iconType);
322 	fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1),
323 		kDefaultIconDepth);
324 
325 	if (mime.GetIcon(fDeviceIcon, which) != B_OK) {
326 		BMimeType super;
327 		mime.GetSupertype(&super);
328 		if (super.GetIcon(fDeviceIcon, which) != B_OK) {
329 			delete fDeviceIcon;
330 			fDeviceIcon = NULL;
331 		}
332 	}
333 
334 	// IconMenuItem is used in synchronously invoked menus, make sure
335 	// we invoke with a timeout
336 	SetTimeout(kSynchMenuInvokeTimeout);
337 }
338 
339 
340 IconMenuItem::~IconMenuItem()
341 {
342 	delete fDeviceIcon;
343 }
344 
345 
346 void
347 IconMenuItem::GetContentSize(float* width, float* height)
348 {
349 	_inherited::GetContentSize(width, height);
350 
351 	fHeightDelta = 16 - *height;
352 	if (*height < 16)
353 		*height = 16;
354 
355 	*width += 20;
356 }
357 
358 
359 void
360 IconMenuItem::DrawContent()
361 {
362 	BPoint drawPoint(ContentLocation());
363 	drawPoint.x += 20;
364 	if (fHeightDelta > 0)
365 		drawPoint.y += ceil(fHeightDelta / 2);
366 	Menu()->MovePenTo(drawPoint);
367 	_inherited::DrawContent();
368 
369 	Menu()->PushState();
370 
371 	BPoint where(ContentLocation());
372 	float deltaHeight = fHeightDelta < 0 ? -fHeightDelta : 0;
373 	where.y += ceil(deltaHeight / 2);
374 
375 	if (fDeviceIcon) {
376 		if (IsEnabled())
377 			Menu()->SetDrawingMode(B_OP_ALPHA);
378 		else {
379 			Menu()->SetDrawingMode(B_OP_ALPHA);
380 			Menu()->SetHighColor(0, 0, 0, 64);
381 			Menu()->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
382 		}
383 		Menu()->DrawBitmapAsync(fDeviceIcon, where);
384 	}
385 
386 	Menu()->PopState();
387 }
388