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
30trademarks of Be Incorporated in the United States and other countries. Other
31brand product names are registered trademarks or trademarks of their respective
32holders.
33All 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
59const float kSepItemWidth = 5.0f;
60
61const float kTeamIconBitmapHeight = 19.f;
62
63
64//	#pragma mark - TSeparatorItem
65
66
67TSeparatorItem::TSeparatorItem()
68	:
69	BSeparatorItem()
70{
71}
72
73
74void
75TSeparatorItem::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
105TBarMenuBar::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	SetFont(be_bold_font);
116
117	TDeskbarMenu* beMenu = new TDeskbarMenu(barView);
118	TBarWindow::SetDeskbarMenu(beMenu);
119
120	BBitmap* icon = NULL;
121	size_t dataSize;
122	const void* data = AppResSet()->FindResource(B_VECTOR_ICON_TYPE,
123		R_LeafLogoBitmap, &dataSize);
124	if (data != NULL) {
125		// seems valid, scale bitmap according to be_bold_font size
126		float width = std::max(63.f, ceilf(63 * be_bold_font->Size() / 12.f));
127		float height = std::max(22.f, ceilf(22 * be_bold_font->Size() / 12.f));
128		icon = new BBitmap(BRect(0, 0, width - 1, height - 1), B_RGBA32);
129		if (icon->InitCheck() != B_OK
130			|| BIconUtils::GetVectorIcon((const uint8*)data, dataSize, icon)
131					!= B_OK) {
132			delete icon;
133			icon = NULL;
134		}
135	}
136
137	fDeskbarMenuItem = new TBarMenuTitle(0.0f, 0.0f, icon, beMenu, fBarView);
138	AddItem(fDeskbarMenuItem);
139}
140
141
142TBarMenuBar::~TBarMenuBar()
143{
144}
145
146
147void
148TBarMenuBar::SmartResize(float width, float height)
149{
150	if (width == -1.0f && height == -1.0f) {
151		BRect frame = Frame();
152		width = frame.Width();
153		height = frame.Height();
154	} else
155		ResizeTo(width, height);
156
157	if (fSeparatorItem != NULL)
158		fDeskbarMenuItem->SetContentSize(width - kSepItemWidth, height);
159	else {
160		int32 count = CountItems();
161		if (fDeskbarMenuItem != NULL)
162			fDeskbarMenuItem->SetContentSize(floorf(width / count), height);
163		if (fAppListMenuItem != NULL)
164			fAppListMenuItem->SetContentSize(floorf(width / count), height);
165	}
166
167	InvalidateLayout();
168}
169
170
171bool
172TBarMenuBar::AddTeamMenu()
173{
174	if (CountItems() > 1)
175		return false;
176
177	BRect frame(Frame());
178
179	delete fAppListMenuItem;
180	fAppListMenuItem = new TBarMenuTitle(0.0f, 0.0f, FetchTeamIcon(),
181		new TTeamMenu(fBarView), fBarView);
182
183	bool added = AddItem(fAppListMenuItem, fBarView->Left() ? 0 : 1);
184
185	if (added)
186		SmartResize(frame.Width() - 1.0f, frame.Height());
187	else
188		SmartResize(frame.Width(), frame.Height());
189
190	return added;
191}
192
193
194bool
195TBarMenuBar::RemoveTeamMenu()
196{
197	if (CountItems() < 2)
198		return false;
199
200	bool removed = false;
201
202	if (fAppListMenuItem != NULL && RemoveItem(fAppListMenuItem)) {
203		delete fAppListMenuItem;
204		fAppListMenuItem = NULL;
205		SmartResize(-1, -1);
206		removed = true;
207	}
208
209	return removed;
210}
211
212
213bool
214TBarMenuBar::AddSeparatorItem()
215{
216	if (CountItems() > 1)
217		return false;
218
219	BRect frame(Frame());
220
221	delete fSeparatorItem;
222	fSeparatorItem = new TSeparatorItem();
223
224	bool added = AddItem(fSeparatorItem);
225
226	if (added)
227		SmartResize(frame.Width() - 1.0f, frame.Height());
228	else
229		SmartResize(frame.Width(), frame.Height());
230
231	return added;
232}
233
234
235bool
236TBarMenuBar::RemoveSeperatorItem()
237{
238	if (CountItems() < 2)
239		return false;
240
241	bool removed = false;
242
243	if (fSeparatorItem != NULL && RemoveItem(fSeparatorItem)) {
244		delete fSeparatorItem;
245		fSeparatorItem = NULL;
246		SmartResize(-1, -1);
247		removed = true;
248	}
249
250	return removed;
251}
252
253
254void
255TBarMenuBar::Draw(BRect updateRect)
256{
257	// skip the fancy BMenuBar drawing code
258	BMenu::Draw(updateRect);
259}
260
261
262void
263TBarMenuBar::DrawBackground(BRect updateRect)
264{
265	BMenu::DrawBackground(updateRect);
266}
267
268
269void
270TBarMenuBar::MouseMoved(BPoint where, uint32 code, const BMessage* message)
271{
272	// the following code parallels that in ExpandoMenuBar for DnD tracking
273
274	if (!message) {
275		// force a cleanup
276		fBarView->DragStop(true);
277		BMenuBar::MouseMoved(where, code, message);
278		return;
279	}
280
281	switch (code) {
282		case B_ENTERED_VIEW:
283		{
284			BPoint loc;
285			uint32 buttons;
286			GetMouse(&loc, &buttons);
287			if (message != NULL && buttons != 0) {
288				// attempt to start DnD tracking
289				fBarView->CacheDragData(const_cast<BMessage*>(message));
290				MouseDown(loc);
291			}
292			break;
293		}
294	}
295
296	BMenuBar::MouseMoved(where, code, message);
297}
298
299
300static void
301init_tracking_hook(BMenuItem* item, bool (*hookFunction)(BMenu*, void*),
302	void* state)
303{
304	if (!item)
305		return;
306
307	BMenu* windowMenu = item->Submenu();
308	if (windowMenu) {
309		// have a menu, set the tracking hook
310		windowMenu->SetTrackingHook(hookFunction, state);
311	}
312}
313
314
315void
316TBarMenuBar::InitTrackingHook(bool (*hookFunction)(BMenu*, void*),
317	void* state, bool both)
318{
319	BPoint loc;
320	uint32 buttons;
321	GetMouse(&loc, &buttons);
322	// set the hook functions for the two menus
323	// will always have the deskbar menu
324	// may have the app menu as well (mini mode)
325	if (fDeskbarMenuItem->Frame().Contains(loc) || both)
326		init_tracking_hook(fDeskbarMenuItem, hookFunction, state);
327
328	if (fAppListMenuItem && (fAppListMenuItem->Frame().Contains(loc) || both))
329		init_tracking_hook(fAppListMenuItem, hookFunction, state);
330}
331
332
333const BBitmap*
334TBarMenuBar::FetchTeamIcon()
335{
336	const BBitmap* teamIcon = NULL;
337
338	if (fTeamIconData == NULL || fTeamIconSize == 0) {
339		// we haven't fetched vector icon data yet, fetch it
340		fTeamIconData = (const uint8*)AppResSet()->FindResource(
341			B_VECTOR_ICON_TYPE, R_TeamIcon, &fTeamIconSize);
342	}
343
344	if (fTeamIconData != NULL && fTeamIconSize > 0) {
345		// seems valid, scale bitmap according to be_bold_font size
346		float iconHeight = std::max(kTeamIconBitmapHeight,
347			ceilf(kTeamIconBitmapHeight * be_bold_font->Size() / 12.f));
348		BRect iconRect = BRect(0, 0, iconHeight, iconHeight);
349		iconRect.InsetBy(-1, -1);
350			// grow icon by 1px so that it renders nicely at 12pt font size
351		BBitmap* icon = new(std::nothrow) BBitmap(iconRect, B_RGBA32);
352		if (icon != NULL && icon->InitCheck() == B_OK
353			&& BIconUtils::GetVectorIcon(fTeamIconData, fTeamIconSize, icon)
354				== B_OK) {
355			// rasterize vector icon into a bitmap at the scaled size
356			teamIcon = icon;
357		} else if (icon != NULL)
358			delete icon;
359	}
360
361	return teamIcon;
362}
363