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