xref: /haiku/src/apps/deskbar/BarMenuBar.cpp (revision 1757f197bd98997256fea2918bfa4603bf81b748)
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
30 trademarks of Be Incorporated in the United States and other countries. Other
31 brand product names are registered trademarks or trademarks of their respective
32 holders.
33 All rights reserved.
34 */
35 
36 
37 #include "BarMenuBar.h"
38 
39 #include <algorithm>
40 
41 #include <Bitmap.h>
42 #include <ControlLook.h>
43 #include <Debug.h>
44 #include <IconUtils.h>
45 #include <NodeInfo.h>
46 
47 #include "icons.h"
48 
49 #include "BarMenuTitle.h"
50 #include "BarView.h"
51 #include "BarWindow.h"
52 #include "DeskbarMenu.h"
53 #include "DeskbarUtils.h"
54 #include "ResourceSet.h"
55 #include "StatusView.h"
56 #include "TeamMenu.h"
57 
58 
59 const float kSepItemWidth = 5.0f;
60 
61 const float kTeamIconBitmapHeight = 19.f;
62 
63 
64 //	#pragma mark - TSeparatorItem
65 
66 
67 TSeparatorItem::TSeparatorItem()
68 	:
69 	BSeparatorItem()
70 {
71 }
72 
73 
74 void
75 TSeparatorItem::Draw()
76 {
77 	BMenu* menu = Menu();
78 	if (menu == NULL)
79 		return;
80 
81 	BRect frame(Frame());
82 	frame.right = frame.left + kSepItemWidth;
83 	rgb_color base = ui_color(B_MENU_BACKGROUND_COLOR);
84 
85 	menu->PushState();
86 
87 	menu->SetHighColor(tint_color(base, 1.22));
88 	frame.top--;
89 		// need to expand the frame for some reason
90 
91 	// stroke a darker line on the left edge
92 	menu->StrokeLine(frame.LeftTop(), frame.LeftBottom());
93 	frame.left++;
94 
95 	// fill in background
96 	be_control_look->DrawButtonBackground(menu, frame, frame, base);
97 
98 	menu->PopState();
99 }
100 
101 
102 //	#pragma mark - TBarMenuBar
103 
104 
105 TBarMenuBar::TBarMenuBar(BRect frame, const char* name, TBarView* barView)
106 	:
107 	BMenuBar(frame, name, B_FOLLOW_NONE, B_ITEMS_IN_ROW, false),
108 	fBarView(barView),
109 	fAppListMenuItem(NULL),
110 	fSeparatorItem(NULL),
111 	fTeamIconData(NULL),
112 	fTeamIconSize(0)
113 {
114 	SetItemMargins(0.0f, 0.0f, 0.0f, 0.0f);
115 
116 	TDeskbarMenu* beMenu = new TDeskbarMenu(barView);
117 	TBarWindow::SetDeskbarMenu(beMenu);
118 
119 	BBitmap* icon = NULL;
120 	size_t dataSize;
121 	const void* data = AppResSet()->FindResource(B_VECTOR_ICON_TYPE,
122 		R_LeafLogoBitmap, &dataSize);
123 	if (data != NULL) {
124 		// Scale bitmap according to font size
125 		float width = std::max(63.f, ceilf(63 * be_plain_font->Size() / 12.f));
126 		// but limit by be_bold_font size
127 		width = std::min(width, ceilf(63.f * be_bold_font->Size() / 12.f));
128 		float height = std::max(22.f, ceilf(22 * be_plain_font->Size() / 12.f));
129 		height = std::min(height, ceilf(22.f * be_bold_font->Size() / 12.f));
130 		icon = new BBitmap(BRect(0, 0, width - 1, height - 1), B_RGBA32);
131 		if (icon->InitCheck() != B_OK
132 			|| BIconUtils::GetVectorIcon((const uint8*)data, dataSize, icon)
133 					!= B_OK) {
134 			delete icon;
135 			icon = NULL;
136 		}
137 	}
138 
139 	fDeskbarMenuItem = new TBarMenuTitle(0.0f, 0.0f, icon, beMenu, fBarView);
140 	AddItem(fDeskbarMenuItem);
141 }
142 
143 
144 TBarMenuBar::~TBarMenuBar()
145 {
146 }
147 
148 
149 void
150 TBarMenuBar::SmartResize(float width, float height)
151 {
152 	if (width == -1.0f && height == -1.0f) {
153 		BRect frame = Frame();
154 		width = frame.Width();
155 		height = frame.Height();
156 	} else
157 		ResizeTo(width, height);
158 
159 	width -= 1;
160 
161 	if (fSeparatorItem != NULL)
162 		fDeskbarMenuItem->SetContentSize(width - kSepItemWidth, height);
163 	else {
164 		int32 count = CountItems();
165 		if (fDeskbarMenuItem)
166 			fDeskbarMenuItem->SetContentSize(width / count, height);
167 		if (fAppListMenuItem)
168 			fAppListMenuItem->SetContentSize(width / count, height);
169 	}
170 
171 	InvalidateLayout();
172 }
173 
174 
175 bool
176 TBarMenuBar::AddTeamMenu()
177 {
178 	if (CountItems() > 1)
179 		return false;
180 
181 	BRect frame(Frame());
182 
183 	delete fAppListMenuItem;
184 	fAppListMenuItem = new TBarMenuTitle(0.0f, 0.0f, FetchTeamIcon(),
185 		new TTeamMenu(fBarView), fBarView);
186 
187 	bool added = AddItem(fAppListMenuItem, fBarView->Left() ? 0 : 1);
188 
189 	if (added)
190 		SmartResize(frame.Width() - 1.0f, frame.Height());
191 	else
192 		SmartResize(frame.Width(), frame.Height());
193 
194 	return added;
195 }
196 
197 
198 bool
199 TBarMenuBar::RemoveTeamMenu()
200 {
201 	if (CountItems() < 2)
202 		return false;
203 
204 	bool removed = false;
205 
206 	if (fAppListMenuItem != NULL && RemoveItem(fAppListMenuItem)) {
207 		delete fAppListMenuItem;
208 		fAppListMenuItem = NULL;
209 		SmartResize(-1, -1);
210 		removed = true;
211 	}
212 
213 	return removed;
214 }
215 
216 
217 bool
218 TBarMenuBar::AddSeparatorItem()
219 {
220 	if (CountItems() > 1)
221 		return false;
222 
223 	BRect frame(Frame());
224 
225 	delete fSeparatorItem;
226 	fSeparatorItem = new TSeparatorItem();
227 
228 	bool added = AddItem(fSeparatorItem);
229 
230 	if (added)
231 		SmartResize(frame.Width() - 1.0f, frame.Height());
232 	else
233 		SmartResize(frame.Width(), frame.Height());
234 
235 	return added;
236 }
237 
238 
239 bool
240 TBarMenuBar::RemoveSeperatorItem()
241 {
242 	if (CountItems() < 2)
243 		return false;
244 
245 	bool removed = false;
246 
247 	if (fSeparatorItem != NULL && RemoveItem(fSeparatorItem)) {
248 		delete fSeparatorItem;
249 		fSeparatorItem = NULL;
250 		SmartResize(-1, -1);
251 		removed = true;
252 	}
253 
254 	return removed;
255 }
256 
257 
258 void
259 TBarMenuBar::Draw(BRect updateRect)
260 {
261 	// skip the fancy BMenuBar drawing code
262 	BMenu::Draw(updateRect);
263 }
264 
265 
266 void
267 TBarMenuBar::DrawBackground(BRect updateRect)
268 {
269 	BMenu::DrawBackground(updateRect);
270 }
271 
272 
273 void
274 TBarMenuBar::MouseMoved(BPoint where, uint32 code, const BMessage* message)
275 {
276 	// the following code parallels that in ExpandoMenuBar for DnD tracking
277 
278 	if (!message) {
279 		// force a cleanup
280 		fBarView->DragStop(true);
281 		BMenuBar::MouseMoved(where, code, message);
282 		return;
283 	}
284 
285 	switch (code) {
286 		case B_ENTERED_VIEW:
287 		{
288 			BPoint loc;
289 			uint32 buttons;
290 			GetMouse(&loc, &buttons);
291 			if (message != NULL && buttons != 0) {
292 				// attempt to start DnD tracking
293 				fBarView->CacheDragData(const_cast<BMessage*>(message));
294 				MouseDown(loc);
295 			}
296 			break;
297 		}
298 	}
299 
300 	BMenuBar::MouseMoved(where, code, message);
301 }
302 
303 
304 static void
305 init_tracking_hook(BMenuItem* item, bool (*hookFunction)(BMenu*, void*),
306 	void* state)
307 {
308 	if (!item)
309 		return;
310 
311 	BMenu* windowMenu = item->Submenu();
312 	if (windowMenu) {
313 		// have a menu, set the tracking hook
314 		windowMenu->SetTrackingHook(hookFunction, state);
315 	}
316 }
317 
318 
319 void
320 TBarMenuBar::InitTrackingHook(bool (*hookFunction)(BMenu*, void*),
321 	void* state, bool both)
322 {
323 	BPoint loc;
324 	uint32 buttons;
325 	GetMouse(&loc, &buttons);
326 	// set the hook functions for the two menus
327 	// will always have the deskbar menu
328 	// may have the app menu as well (mini mode)
329 	if (fDeskbarMenuItem->Frame().Contains(loc) || both)
330 		init_tracking_hook(fDeskbarMenuItem, hookFunction, state);
331 
332 	if (fAppListMenuItem && (fAppListMenuItem->Frame().Contains(loc) || both))
333 		init_tracking_hook(fAppListMenuItem, hookFunction, state);
334 }
335 
336 
337 const BBitmap*
338 TBarMenuBar::FetchTeamIcon()
339 {
340 	const BBitmap* teamIcon = NULL;
341 
342 	if (fTeamIconData == NULL || fTeamIconSize == 0) {
343 		// we haven't fetched vector icon data yet, fetch it
344 		fTeamIconData = (const uint8*)AppResSet()->FindResource(
345 			B_VECTOR_ICON_TYPE, R_TeamIconVector, &fTeamIconSize);
346 	}
347 
348 	if (fTeamIconData != NULL && fTeamIconSize > 0) {
349 		// seems valid, scale bitmap according to font size
350 		float iconHeight = std::max(kTeamIconBitmapHeight,
351 			ceilf(kTeamIconBitmapHeight * be_plain_font->Size() / 12.f));
352 		// but limit by be_bold_font_size
353 		iconHeight = std::min(iconHeight,
354 			ceilf(kTeamIconBitmapHeight * be_bold_font->Size() / 12.f));
355 		BRect iconRect = BRect(0, 0, iconHeight, iconHeight);
356 		iconRect.InsetBy(-1, -1);
357 			// grow icon by 1px so that it renders nicely at 12pt font size
358 		BBitmap* icon = new(std::nothrow) BBitmap(iconRect, B_RGBA32);
359 		if (icon != NULL && BIconUtils::GetVectorIcon(fTeamIconData,
360 				fTeamIconSize, icon) == B_OK) {
361 			// rasterize vector icon into a bitmap at the scaled size
362 			teamIcon = icon;
363 		}
364 	}
365 
366 	return teamIcon;
367 }
368