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