xref: /haiku/src/apps/deskbar/BarMenuBar.cpp (revision fb885767b6f46f38a0a522c0394550b814227627)
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 
TSeparatorItem()67 TSeparatorItem::TSeparatorItem()
68 	:
69 	BSeparatorItem()
70 {
71 }
72 
73 
74 void
Draw()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 
TBarMenuBar(BRect frame,const char * name,TBarView * barView)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 	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 
~TBarMenuBar()142 TBarMenuBar::~TBarMenuBar()
143 {
144 }
145 
146 
147 void
SmartResize(float width,float height)148 TBarMenuBar::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 
171 bool
AddTeamMenu()172 TBarMenuBar::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 
194 bool
RemoveTeamMenu()195 TBarMenuBar::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 
213 bool
AddSeparatorItem()214 TBarMenuBar::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 
235 bool
RemoveSeperatorItem()236 TBarMenuBar::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 
254 void
Draw(BRect updateRect)255 TBarMenuBar::Draw(BRect updateRect)
256 {
257 	// skip the fancy BMenuBar drawing code
258 	BMenu::Draw(updateRect);
259 }
260 
261 
262 void
DrawBackground(BRect updateRect)263 TBarMenuBar::DrawBackground(BRect updateRect)
264 {
265 	BMenu::DrawBackground(updateRect);
266 }
267 
268 
269 void
MouseMoved(BPoint where,uint32 code,const BMessage * message)270 TBarMenuBar::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 
300 static void
init_tracking_hook(BMenuItem * item,bool (* hookFunction)(BMenu *,void *),void * state)301 init_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 
315 void
InitTrackingHook(bool (* hookFunction)(BMenu *,void *),void * state,bool both)316 TBarMenuBar::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 
333 const BBitmap*
FetchTeamIcon()334 TBarMenuBar::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