xref: /haiku/src/apps/deskbar/BarMenuBar.cpp (revision 0fae96c5a349db3761ac2a4ab4a7fbbf23a3b76c)
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 	if (fSeparatorItem != NULL)
160 		fDeskbarMenuItem->SetContentSize(width - kSepItemWidth, height);
161 	else {
162 		int32 count = CountItems();
163 		if (fDeskbarMenuItem != NULL)
164 			fDeskbarMenuItem->SetContentSize(floorf(width / count), height);
165 		if (fAppListMenuItem != NULL)
166 			fAppListMenuItem->SetContentSize(floorf(width / count), height);
167 	}
168 
169 	InvalidateLayout();
170 }
171 
172 
173 bool
174 TBarMenuBar::AddTeamMenu()
175 {
176 	if (CountItems() > 1)
177 		return false;
178 
179 	BRect frame(Frame());
180 
181 	delete fAppListMenuItem;
182 	fAppListMenuItem = new TBarMenuTitle(0.0f, 0.0f, FetchTeamIcon(),
183 		new TTeamMenu(fBarView), fBarView);
184 
185 	bool added = AddItem(fAppListMenuItem, fBarView->Left() ? 0 : 1);
186 
187 	if (added)
188 		SmartResize(frame.Width() - 1.0f, frame.Height());
189 	else
190 		SmartResize(frame.Width(), frame.Height());
191 
192 	return added;
193 }
194 
195 
196 bool
197 TBarMenuBar::RemoveTeamMenu()
198 {
199 	if (CountItems() < 2)
200 		return false;
201 
202 	bool removed = false;
203 
204 	if (fAppListMenuItem != NULL && RemoveItem(fAppListMenuItem)) {
205 		delete fAppListMenuItem;
206 		fAppListMenuItem = NULL;
207 		SmartResize(-1, -1);
208 		removed = true;
209 	}
210 
211 	return removed;
212 }
213 
214 
215 bool
216 TBarMenuBar::AddSeparatorItem()
217 {
218 	if (CountItems() > 1)
219 		return false;
220 
221 	BRect frame(Frame());
222 
223 	delete fSeparatorItem;
224 	fSeparatorItem = new TSeparatorItem();
225 
226 	bool added = AddItem(fSeparatorItem);
227 
228 	if (added)
229 		SmartResize(frame.Width() - 1.0f, frame.Height());
230 	else
231 		SmartResize(frame.Width(), frame.Height());
232 
233 	return added;
234 }
235 
236 
237 bool
238 TBarMenuBar::RemoveSeperatorItem()
239 {
240 	if (CountItems() < 2)
241 		return false;
242 
243 	bool removed = false;
244 
245 	if (fSeparatorItem != NULL && RemoveItem(fSeparatorItem)) {
246 		delete fSeparatorItem;
247 		fSeparatorItem = NULL;
248 		SmartResize(-1, -1);
249 		removed = true;
250 	}
251 
252 	return removed;
253 }
254 
255 
256 void
257 TBarMenuBar::Draw(BRect updateRect)
258 {
259 	// skip the fancy BMenuBar drawing code
260 	BMenu::Draw(updateRect);
261 }
262 
263 
264 void
265 TBarMenuBar::DrawBackground(BRect updateRect)
266 {
267 	BMenu::DrawBackground(updateRect);
268 }
269 
270 
271 void
272 TBarMenuBar::MouseMoved(BPoint where, uint32 code, const BMessage* message)
273 {
274 	// the following code parallels that in ExpandoMenuBar for DnD tracking
275 
276 	if (!message) {
277 		// force a cleanup
278 		fBarView->DragStop(true);
279 		BMenuBar::MouseMoved(where, code, message);
280 		return;
281 	}
282 
283 	switch (code) {
284 		case B_ENTERED_VIEW:
285 		{
286 			BPoint loc;
287 			uint32 buttons;
288 			GetMouse(&loc, &buttons);
289 			if (message != NULL && buttons != 0) {
290 				// attempt to start DnD tracking
291 				fBarView->CacheDragData(const_cast<BMessage*>(message));
292 				MouseDown(loc);
293 			}
294 			break;
295 		}
296 	}
297 
298 	BMenuBar::MouseMoved(where, code, message);
299 }
300 
301 
302 static void
303 init_tracking_hook(BMenuItem* item, bool (*hookFunction)(BMenu*, void*),
304 	void* state)
305 {
306 	if (!item)
307 		return;
308 
309 	BMenu* windowMenu = item->Submenu();
310 	if (windowMenu) {
311 		// have a menu, set the tracking hook
312 		windowMenu->SetTrackingHook(hookFunction, state);
313 	}
314 }
315 
316 
317 void
318 TBarMenuBar::InitTrackingHook(bool (*hookFunction)(BMenu*, void*),
319 	void* state, bool both)
320 {
321 	BPoint loc;
322 	uint32 buttons;
323 	GetMouse(&loc, &buttons);
324 	// set the hook functions for the two menus
325 	// will always have the deskbar menu
326 	// may have the app menu as well (mini mode)
327 	if (fDeskbarMenuItem->Frame().Contains(loc) || both)
328 		init_tracking_hook(fDeskbarMenuItem, hookFunction, state);
329 
330 	if (fAppListMenuItem && (fAppListMenuItem->Frame().Contains(loc) || both))
331 		init_tracking_hook(fAppListMenuItem, hookFunction, state);
332 }
333 
334 
335 const BBitmap*
336 TBarMenuBar::FetchTeamIcon()
337 {
338 	const BBitmap* teamIcon = NULL;
339 
340 	if (fTeamIconData == NULL || fTeamIconSize == 0) {
341 		// we haven't fetched vector icon data yet, fetch it
342 		fTeamIconData = (const uint8*)AppResSet()->FindResource(
343 			B_VECTOR_ICON_TYPE, R_TeamIconVector, &fTeamIconSize);
344 	}
345 
346 	if (fTeamIconData != NULL && fTeamIconSize > 0) {
347 		// seems valid, scale bitmap according to font size
348 		float iconHeight = std::max(kTeamIconBitmapHeight,
349 			ceilf(kTeamIconBitmapHeight * be_plain_font->Size() / 12.f));
350 		// but limit by be_bold_font_size
351 		iconHeight = std::min(iconHeight,
352 			ceilf(kTeamIconBitmapHeight * be_bold_font->Size() / 12.f));
353 		BRect iconRect = BRect(0, 0, iconHeight, iconHeight);
354 		iconRect.InsetBy(-1, -1);
355 			// grow icon by 1px so that it renders nicely at 12pt font size
356 		BBitmap* icon = new(std::nothrow) BBitmap(iconRect, B_RGBA32);
357 		if (icon != NULL && BIconUtils::GetVectorIcon(fTeamIconData,
358 				fTeamIconSize, icon) == B_OK) {
359 			// rasterize vector icon into a bitmap at the scaled size
360 			teamIcon = icon;
361 		}
362 	}
363 
364 	return teamIcon;
365 }
366