1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30of Be Incorporated in the United States and other countries. Other brand product
31names are registered trademarks or trademarks of their respective holders.
32All 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
45static void
46DimmedIconBlitter(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 -
64
65
66ModelMenuItem::ModelMenuItem(const Model* model, const char* title,
67		BMessage* message, char shortcut, uint32 modifiers,
68		bool drawText, bool extraPad)
69	: BMenuItem(title, message, shortcut, modifiers),
70	fModel(*model),
71	fHeightDelta(0),
72	fDrawText(drawText),
73	fExtraPad(extraPad)
74{
75	ThrowOnInitCheckError(&fModel);
76	// The 'fExtraPad' field is used to when this menu item is added to
77	// a menubar instead of a menu. Menus and MenuBars space out items
78	// differently (more space around items in a menu). This class wants
79	// to be able to space item the same, no matter where they are. The
80	// fExtraPad field allows for that.
81
82	if (model->IsRoot())
83		SetLabel(model->Name());
84
85	// ModelMenuItem is used in synchronously invoked menus, make sure
86	// we invoke with a timeout
87	SetTimeout(kSynchMenuInvokeTimeout);
88}
89
90
91ModelMenuItem::ModelMenuItem(const Model* model, BMenu* menu, bool drawText,
92	bool extraPad)
93	:	BMenuItem(menu),
94		fModel(*model),
95		fHeightDelta(0),
96		fDrawText(drawText),
97		fExtraPad(extraPad)
98{
99	ThrowOnInitCheckError(&fModel);
100	// ModelMenuItem is used in synchronously invoked menus, make sure
101	// we invoke with a timeout
102	SetTimeout(kSynchMenuInvokeTimeout);
103}
104
105
106ModelMenuItem::~ModelMenuItem()
107{
108}
109
110
111status_t
112ModelMenuItem::SetEntry(const BEntry* entry)
113{
114	return fModel.SetTo(entry);
115}
116
117
118void
119ModelMenuItem::DrawContent()
120{
121	if (fDrawText) {
122		BPoint drawPoint(ContentLocation());
123		drawPoint.x += 20 + (fExtraPad ? 6 : 0);
124		if (fHeightDelta > 0)
125			drawPoint.y += ceil(fHeightDelta / 2);
126		Menu()->MovePenTo(drawPoint);
127		_inherited::DrawContent();
128	}
129	DrawIcon();
130}
131
132
133void
134ModelMenuItem::Highlight(bool hilited)
135{
136	_inherited::Highlight(hilited);
137	DrawIcon();
138}
139
140
141void
142ModelMenuItem::DrawIcon()
143{
144	Menu()->PushState();
145
146	BPoint where(ContentLocation());
147	// center icon with text.
148
149	float deltaHeight = fHeightDelta < 0 ? -fHeightDelta : 0;
150	where.y += ceil(deltaHeight / 2);
151
152	if (fExtraPad)
153		where.x += 6;
154
155	Menu()->SetDrawingMode(B_OP_OVER);
156	Menu()->SetLowColor(B_TRANSPARENT_32_BIT);
157
158	// draw small icon, synchronously
159	if (IsEnabled()) {
160		IconCache::sIconCache->Draw(fModel.ResolveIfLink(), Menu(), where,
161			kNormalIcon, B_MINI_ICON);
162	} else {
163		// dimmed, for now use a special blitter; icon cache should
164		// know how to blit one eventually
165		IconCache::sIconCache->SyncDraw(fModel.ResolveIfLink(), Menu(), where,
166			kNormalIcon, B_MINI_ICON, DimmedIconBlitter);
167	}
168
169	Menu()->PopState();
170}
171
172
173void
174ModelMenuItem::GetContentSize(float* width, float* height)
175{
176	_inherited::GetContentSize(width, height);
177	fHeightDelta = 16 - *height;
178	if (*height < 16)
179		*height = 16;
180	*width = *width + 20 + (fExtraPad ? 18 : 0);
181}
182
183
184status_t
185ModelMenuItem::Invoke(BMessage* message)
186{
187	if (!Menu())
188		return B_ERROR;
189
190	if (!IsEnabled())
191		return B_ERROR;
192
193	if (!message)
194		message = Message();
195
196	if (!message)
197		return B_BAD_VALUE;
198
199	BMessage clone(*message);
200	clone.AddInt32("index", Menu()->IndexOf(this));
201	clone.AddInt64("when", system_time());
202	clone.AddPointer("source", this);
203
204	if ((modifiers() & B_OPTION_KEY) == 0) {
205		// if option not held, remove refs to close to prevent closing
206		// parent window
207		clone.RemoveData("nodeRefsToClose");
208	}
209
210	return BInvoker::Invoke(&clone);
211}
212
213
214//	#pragma mark -
215
216
217/*!
218	A ModelMenuItem subclass that draws its label in italics.
219	It's used for example in the "Copy To" menu to indicate some special
220	folders like the parent folder.
221*/
222SpecialModelMenuItem::SpecialModelMenuItem(const Model* model, BMenu* menu)
223	: ModelMenuItem(model, menu)
224{
225}
226
227
228void
229SpecialModelMenuItem::DrawContent()
230{
231	Menu()->PushState();
232
233	BFont font;
234	Menu()->GetFont(&font);
235	font.SetFace(B_ITALIC_FACE);
236	Menu()->SetFont(&font);
237
238	_inherited::DrawContent();
239	Menu()->PopState();
240}
241
242
243//	#pragma mark -
244
245
246/*!
247	A menu item that draws an icon alongside the label.
248	It's currently used in the mount and new file template menus.
249*/
250IconMenuItem::IconMenuItem(const char* label, BMessage* message, BBitmap* icon)
251	: PositionPassingMenuItem(label, message),
252	fDeviceIcon(icon),
253	fHeightDelta(0)
254{
255	// IconMenuItem is used in synchronously invoked menus, make sure
256	// we invoke with a timeout
257	SetTimeout(kSynchMenuInvokeTimeout);
258}
259
260
261IconMenuItem::IconMenuItem(const char* label, BMessage* message,
262		const BNodeInfo* nodeInfo, icon_size which)
263	: PositionPassingMenuItem(label, message),
264	fDeviceIcon(NULL),
265	fHeightDelta(0)
266{
267	if (nodeInfo) {
268#ifdef __HAIKU__
269		fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_RGBA32);
270#else
271		fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_CMAP8);
272#endif
273
274		if (nodeInfo->GetTrackerIcon(fDeviceIcon, B_MINI_ICON)) {
275			delete fDeviceIcon;
276			fDeviceIcon = NULL;
277		}
278	}
279
280	// IconMenuItem is used in synchronously invoked menus, make sure
281	// we invoke with a timeout
282	SetTimeout(kSynchMenuInvokeTimeout);
283}
284
285
286IconMenuItem::IconMenuItem(const char* label, BMessage* message,
287		const char* iconType, icon_size which)
288	: PositionPassingMenuItem(label, message),
289	fDeviceIcon(NULL),
290	fHeightDelta(0)
291{
292	BMimeType mime(iconType);
293#ifdef __HAIKU__
294	fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_RGBA32);
295#else
296	fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_CMAP8);
297#endif
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
314IconMenuItem::IconMenuItem(BMenu* submenu, BMessage* message,
315		const char* iconType, icon_size which)
316	: PositionPassingMenuItem(submenu, message),
317	fDeviceIcon(NULL),
318	fHeightDelta(0)
319{
320	BMimeType mime(iconType);
321#ifdef __HAIKU__
322	fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_RGBA32);
323#else
324	fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_CMAP8);
325#endif
326
327	if (mime.GetIcon(fDeviceIcon, which) != B_OK) {
328		BMimeType super;
329		mime.GetSupertype(&super);
330		if (super.GetIcon(fDeviceIcon, which) != B_OK) {
331			delete fDeviceIcon;
332			fDeviceIcon = NULL;
333		}
334	}
335
336	// IconMenuItem is used in synchronously invoked menus, make sure
337	// we invoke with a timeout
338	SetTimeout(kSynchMenuInvokeTimeout);
339}
340
341
342IconMenuItem::~IconMenuItem()
343{
344	delete fDeviceIcon;
345}
346
347
348void
349IconMenuItem::GetContentSize(float* width, float* height)
350{
351	_inherited::GetContentSize(width, height);
352
353	fHeightDelta = 16 - *height;
354	if (*height < 16)
355		*height = 16;
356
357	*width += 20;
358}
359
360
361void
362IconMenuItem::DrawContent()
363{
364	BPoint drawPoint(ContentLocation());
365	drawPoint.x += 20;
366	if (fHeightDelta > 0)
367		drawPoint.y += ceil(fHeightDelta / 2);
368	Menu()->MovePenTo(drawPoint);
369	_inherited::DrawContent();
370
371	Menu()->PushState();
372
373	BPoint where(ContentLocation());
374	float deltaHeight = fHeightDelta < 0 ? -fHeightDelta : 0;
375	where.y += ceil(deltaHeight / 2);
376
377	if (fDeviceIcon) {
378		if (IsEnabled())
379#ifdef __HAIKU__
380			Menu()->SetDrawingMode(B_OP_ALPHA);
381		else {
382			Menu()->SetDrawingMode(B_OP_ALPHA);
383			Menu()->SetHighColor(0, 0, 0, 64);
384			Menu()->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
385		}
386#else
387			Menu()->SetDrawingMode(B_OP_OVER);
388		else
389			Menu()->SetDrawingMode(B_OP_BLEND);
390#endif
391		Menu()->DrawBitmapAsync(fDeviceIcon, where);
392	}
393
394	Menu()->PopState();
395}
396
397