xref: /haiku/src/kits/tracker/IconMenuItem.cpp (revision 0e50eab75e25d0d82090e22dbff766dfaa6f5e86)
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 	view->SetDrawingMode(B_OP_BLEND);
124 	view->DrawBitmap(bitmap, where);
125 	view->SetDrawingMode(B_OP_OVER);
126 }
127 
128 
129 void
130 ModelMenuItem::DrawIcon()
131 {
132 	Menu()->PushState();
133 
134 	BPoint where(ContentLocation());
135 	// center icon with text.
136 
137 	float deltaHeight = fHeightDelta < 0 ? -fHeightDelta : 0;
138 	where.y += ceil( deltaHeight/2 );
139 
140 	if (fExtraPad)
141 		where.x += 6;
142 
143 	Menu()->SetDrawingMode(B_OP_OVER);
144 	Menu()->SetLowColor(B_TRANSPARENT_32_BIT);
145 
146 	// draw small icon, synchronously
147 	if (IsEnabled())
148 		IconCache::sIconCache->Draw(fModel.ResolveIfLink(), Menu(), where,
149 			kNormalIcon, B_MINI_ICON);
150 	else {
151 		// dimmed, for now use a special blitter; icon cache should
152 		// know how to blit one eventually
153 		IconCache::sIconCache->SyncDraw(fModel.ResolveIfLink(), Menu(), where,
154 			kNormalIcon, B_MINI_ICON, DimmedIconBlitter);
155 	}
156 
157 	Menu()->PopState();
158 }
159 
160 
161 void
162 ModelMenuItem::GetContentSize(float *width, float *height)
163 {
164 	_inherited::GetContentSize(width, height);
165 	fHeightDelta = 16 - *height;
166 	if (*height < 16)
167 		*height = 16;
168 	*width = *width + 20 + (fExtraPad ? 18 : 0);
169 }
170 
171 
172 status_t
173 ModelMenuItem::Invoke(BMessage *message)
174 {
175 	if (!Menu())
176 		return B_ERROR;
177 
178 	if (!IsEnabled())
179 		return B_ERROR;
180 
181 	if (!message)
182 		message = Message();
183 
184 	if (!message)
185 		return B_BAD_VALUE;
186 
187 	BMessage clone(*message);
188 	clone.AddInt32("index", Menu()->IndexOf(this));
189 	clone.AddInt64("when", system_time());
190 	clone.AddPointer("source", this);
191 
192 	if ((modifiers() & B_OPTION_KEY) == 0) {
193 		// if option not held, remove refs to close to prevent closing
194 		// parent window
195 		clone.RemoveData("nodeRefsToClose");
196 	}
197 
198 	return BInvoker::Invoke(&clone);
199 }
200 
201 
202 //	#pragma mark -
203 
204 
205 SpecialModelMenuItem::SpecialModelMenuItem(const Model *model,BMenu *menu)
206 	: ModelMenuItem(model,menu)
207 {
208 }
209 
210 
211 void
212 SpecialModelMenuItem::DrawContent()
213 {
214 	Menu()->PushState();
215 
216 	BFont font;
217 	Menu()->GetFont(&font);
218 	font.SetFace(B_ITALIC_FACE);
219 	Menu()->SetFont(&font);
220 
221 	_inherited::DrawContent();
222 	Menu()->PopState();
223 }
224 
225 
226 //	#pragma mark -
227 
228 
229 IconMenuItem::IconMenuItem(const char *label, BMessage *message, BBitmap *icon)
230 	: PositionPassingMenuItem(label, message),
231 	fDeviceIcon(icon)
232 {
233 	// IconMenuItem is used in synchronously invoked menus, make sure
234 	// we invoke with a timeout
235 	SetTimeout(kSynchMenuInvokeTimeout);
236 }
237 
238 
239 IconMenuItem::IconMenuItem(const char *label, BMessage *message,
240 		const BNodeInfo *nodeInfo, icon_size which)
241 	: PositionPassingMenuItem(label, message),
242 	fDeviceIcon(NULL)
243 {
244 	if (nodeInfo) {
245 		fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_CMAP8);
246 		if (nodeInfo->GetTrackerIcon(fDeviceIcon, B_MINI_ICON)) {
247 			delete fDeviceIcon;
248 			fDeviceIcon = NULL;
249 		}
250 	}
251 
252 	// IconMenuItem is used in synchronously invoked menus, make sure
253 	// we invoke with a timeout
254 	SetTimeout(kSynchMenuInvokeTimeout);
255 }
256 
257 
258 IconMenuItem::IconMenuItem(const char *label, BMessage *message,
259 		const char *iconType, icon_size which)
260 	: PositionPassingMenuItem(label, message),
261 	fDeviceIcon(NULL)
262 {
263 	BMimeType mime(iconType);
264 	fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_CMAP8);
265 
266 	if (mime.GetIcon(fDeviceIcon, which) != B_OK) {
267 		delete fDeviceIcon;
268 		fDeviceIcon = NULL;
269 	}
270 
271 	// IconMenuItem is used in synchronously invoked menus, make sure
272 	// we invoke with a timeout
273 	SetTimeout(kSynchMenuInvokeTimeout);
274 }
275 
276 
277 IconMenuItem::IconMenuItem(BMenu *submenu, BMessage *message,
278 		const char *iconType, icon_size which)
279 	: PositionPassingMenuItem(submenu, message),
280 	fDeviceIcon(NULL)
281 {
282 	BMimeType mime(iconType);
283 	fDeviceIcon = new BBitmap(BRect(0, 0, which - 1, which - 1), B_CMAP8);
284 
285 	if (mime.GetIcon(fDeviceIcon, which) != B_OK) {
286 		delete fDeviceIcon;
287 		fDeviceIcon = NULL;
288 	}
289 
290 	// IconMenuItem is used in synchronously invoked menus, make sure
291 	// we invoke with a timeout
292 	SetTimeout(kSynchMenuInvokeTimeout);
293 }
294 
295 
296 IconMenuItem::~IconMenuItem()
297 {
298 	delete fDeviceIcon;
299 }
300 
301 
302 void
303 IconMenuItem::GetContentSize(float *width, float *height)
304 {
305 	_inherited::GetContentSize(width, height);
306 	*width += 20;
307 	*height += 3;
308 }
309 
310 
311 void
312 IconMenuItem::DrawContent()
313 {
314 	BPoint drawPoint(ContentLocation());
315 	drawPoint.x += 20;
316 	Menu()->MovePenTo(drawPoint);
317 	_inherited::DrawContent();
318 
319 	BPoint where(ContentLocation());
320 	where.y = Frame().top;
321 
322 	if (fDeviceIcon) {
323 		if (IsEnabled())
324 			Menu()->SetDrawingMode(B_OP_OVER);
325 		else
326 			Menu()->SetDrawingMode(B_OP_BLEND);
327 
328 		Menu()->DrawBitmapAsync(fDeviceIcon, where);
329 	}
330 }
331 
332