xref: /haiku/src/apps/deskbar/TeamMenuItem.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 "TeamMenuItem.h"
38 
39 #include <string.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 
43 #include <algorithm>
44 
45 #include <Bitmap.h>
46 #include <ControlLook.h>
47 #include <Debug.h>
48 #include <Font.h>
49 #include <Mime.h>
50 #include <Region.h>
51 #include <Roster.h>
52 #include <Resources.h>
53 
54 #include "BarApp.h"
55 #include "BarMenuBar.h"
56 #include "BarView.h"
57 #include "ExpandoMenuBar.h"
58 #include "ResourceSet.h"
59 #include "ShowHideMenuItem.h"
60 #include "StatusView.h"
61 #include "TeamMenu.h"
62 #include "WindowMenu.h"
63 #include "WindowMenuItem.h"
64 
65 
66 const float kHPad = 8.0f;
67 const float kVPad = 2.0f;
68 const float kLabelOffset = 8.0f;
69 const float kIconPadding = 8.0f;
70 
71 
72 //	#pragma mark - TTeamMenuItem
73 
74 
75 TTeamMenuItem::TTeamMenuItem(BList* team, BBitmap* icon, char* name,
76 	char* signature, float width, float height)
77 	:
78 	TTruncatableMenuItem(new TWindowMenu(team, signature))
79 {
80 	_Init(team, icon, name, signature, width, height);
81 }
82 
83 
84 TTeamMenuItem::TTeamMenuItem(float width, float height)
85 	:
86 	TTruncatableMenuItem("", NULL)
87 {
88 	_Init(NULL, NULL, strdup(""), strdup(""), width, height);
89 }
90 
91 
92 TTeamMenuItem::~TTeamMenuItem()
93 {
94 	delete fTeam;
95 	delete fIcon;
96 	free(fSignature);
97 }
98 
99 
100 status_t
101 TTeamMenuItem::Invoke(BMessage* message)
102 {
103 	if (fBarView != NULL) {
104 		if (fBarView->InvokeItem(Signature())) {
105 			// handles drop on application
106 			return B_OK;
107 		}
108 
109 		// if the app could not handle the drag message
110 		// and we were dragging, then kill the drag
111 		// should never get here, disabled item will not invoke
112 		if (fBarView->Dragging())
113 			fBarView->DragStop();
114 	}
115 
116 	// bring to front or minimize shortcuts
117 	uint32 mods = modifiers();
118 	if (mods & B_CONTROL_KEY) {
119 		TShowHideMenuItem::TeamShowHideCommon((mods & B_SHIFT_KEY)
120 			? B_MINIMIZE_WINDOW : B_BRING_TO_FRONT, Teams());
121 	}
122 
123 	return BMenuItem::Invoke(message);
124 }
125 
126 
127 void
128 TTeamMenuItem::SetOverrideSelected(bool selected)
129 {
130 	fOverriddenSelected = selected;
131 	Highlight(selected);
132 }
133 
134 
135 void
136 TTeamMenuItem::SetIcon(BBitmap* icon) {
137 	delete fIcon;
138 	fIcon = icon;
139 }
140 
141 
142 void
143 TTeamMenuItem::GetContentSize(float* width, float* height)
144 {
145 	BMenuItem::GetContentSize(width, height);
146 
147 	if (fOverrideWidth != -1.0f)
148 		*width = fOverrideWidth;
149 	else {
150 		bool hideLabels = static_cast<TBarApp*>(be_app)->Settings()->hideLabels;
151 		float iconSize = static_cast<TBarApp*>(be_app)->IconSize();
152 		float iconOnlyWidth = kIconPadding + iconSize + kIconPadding;
153 
154 		if (fBarView->MiniState()) {
155 			if (hideLabels)
156 				*width = iconOnlyWidth;
157 			else
158 				*width = gMinimumWindowWidth - (kDragRegionWidth + kGutter) * 2;
159 		} else if (!fBarView->Vertical()) {
160 			TExpandoMenuBar* menu = static_cast<TExpandoMenuBar*>(Menu());
161 			*width = menu->MaxHorizontalItemWidth();
162 		} else
163 			*width = static_cast<TBarApp*>(be_app)->Settings()->width;
164 	}
165 
166 	if (fOverrideHeight != -1.0f)
167 		*height = fOverrideHeight;
168 	else
169 		*height = fBarView->TeamMenuItemHeight();
170 }
171 
172 
173 void
174 TTeamMenuItem::Draw()
175 {
176 	BRect frame = Frame();
177 	BMenu* menu = Menu();
178 
179 	menu->PushState();
180 
181 	rgb_color menuColor = ui_color(B_MENU_BACKGROUND_COLOR);
182 	bool canHandle = !fBarView->Dragging()
183 		|| fBarView->AppCanHandleTypes(Signature());
184 	uint32 flags = 0;
185 	if (_IsSelected() && canHandle)
186 		flags |= BControlLook::B_ACTIVATED;
187 
188 	uint32 borders = BControlLook::B_TOP_BORDER;
189 	if (fBarView->Vertical()) {
190 		menu->SetHighColor(tint_color(menuColor, B_DARKEN_1_TINT));
191 		borders |= BControlLook::B_LEFT_BORDER
192 			| BControlLook::B_RIGHT_BORDER;
193 		menu->StrokeLine(frame.LeftBottom(), frame.RightBottom());
194 		frame.bottom--;
195 
196 		be_control_look->DrawMenuBarBackground(menu, frame, frame,
197 			menuColor, flags, borders);
198 	} else {
199 		if (flags & BControlLook::B_ACTIVATED)
200 			menu->SetHighColor(tint_color(menuColor, B_DARKEN_3_TINT));
201 		else
202 			menu->SetHighColor(tint_color(menuColor, 1.22));
203 		borders |= BControlLook::B_BOTTOM_BORDER;
204 		menu->StrokeLine(frame.LeftTop(), frame.LeftBottom());
205 		frame.left++;
206 
207 		be_control_look->DrawButtonBackground(menu, frame, frame,
208 			menuColor, flags, borders);
209 	}
210 
211 	menu->MovePenTo(ContentLocation());
212 	DrawContent();
213 
214 	menu->PopState();
215 }
216 
217 
218 void
219 TTeamMenuItem::DrawContent()
220 {
221 	BMenu* menu = Menu();
222 	BRect frame = Frame();
223 
224 	if (fIcon != NULL) {
225 		if (fIcon->ColorSpace() == B_RGBA32) {
226 			menu->SetDrawingMode(B_OP_ALPHA);
227 			menu->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
228 		} else
229 			menu->SetDrawingMode(B_OP_OVER);
230 
231 		BRect iconBounds = fIcon != NULL ? fIcon->Bounds()
232 			: BRect(0, 0, kMinimumIconSize - 1, kMinimumIconSize - 1);
233 		BRect updateRect = iconBounds;
234 		BPoint contentLocation = ContentLocation();
235 		BPoint drawLocation = contentLocation + BPoint(kHPad, kVPad);
236 
237 		if (static_cast<TBarApp*>(be_app)->Settings()->hideLabels
238 			|| (fBarView->Vertical() && iconBounds.Width() > 32)) {
239 			// determine icon location (centered horizontally)
240 			float offsetx = contentLocation.x
241 				+ floorf((frame.Width() - iconBounds.Width()) / 2);
242 			float offsety = contentLocation.y + kVPad + kGutter;
243 
244 			// draw icon
245 			updateRect.OffsetTo(BPoint(offsetx, offsety));
246 			menu->DrawBitmapAsync(fIcon, updateRect);
247 
248 			// determine label position (below icon)
249 			drawLocation.x = floorf((frame.Width() - fLabelWidth) / 2);
250 			drawLocation.y = frame.top + kVPad + iconBounds.Height() + kVPad;
251 		} else {
252 			// determine icon location (centered vertically)
253 			float offsetx = contentLocation.x + kHPad;
254 			float offsety = contentLocation.y +
255 				floorf((frame.Height() - iconBounds.Height()) / 2);
256 
257 			// draw icon
258 			updateRect.OffsetTo(BPoint(offsetx, offsety));
259 			menu->DrawBitmapAsync(fIcon, updateRect);
260 
261 			// determine label position (centered vertically)
262 			drawLocation.x += iconBounds.Width() + kLabelOffset;
263 			drawLocation.y = frame.top
264 				+ ceilf((frame.Height() - fLabelHeight) / 2);
265 		}
266 
267 		menu->MovePenTo(drawLocation);
268 	}
269 
270 	// override the drawing of the content when the item is disabled
271 	// the wrong lowcolor is used when the item is disabled since the
272 	// text color does not change
273 	menu->SetDrawingMode(B_OP_OVER);
274 	menu->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR));
275 
276 	bool canHandle = !fBarView->Dragging()
277 		|| fBarView->AppCanHandleTypes(Signature());
278 	if (_IsSelected() && IsEnabled() && canHandle)
279 		menu->SetLowColor(tint_color(ui_color(B_MENU_BACKGROUND_COLOR),
280 			B_HIGHLIGHT_BACKGROUND_TINT));
281 	else
282 		menu->SetLowColor(ui_color(B_MENU_BACKGROUND_COLOR));
283 
284 	if (IsSelected())
285 		menu->SetHighColor(ui_color(B_MENU_SELECTED_ITEM_TEXT_COLOR));
286 	else
287 		menu->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR));
288 
289 	menu->MovePenBy(0, fLabelAscent);
290 
291 	// draw label
292 	if (!static_cast<TBarApp*>(be_app)->Settings()->hideLabels) {
293 		float labelWidth = menu->StringWidth(Label());
294 		BPoint penLocation = menu->PenLocation();
295 		// truncate to max width
296 		float offset = penLocation.x - frame.left;
297 		menu->DrawString(Label(labelWidth + offset));
298 	}
299 
300 	// draw expander arrow
301 	if (fBarView->Vertical()
302 		&& static_cast<TBarApp*>(be_app)->Settings()->superExpando
303 		&& fBarView->ExpandoState()) {
304 		DrawExpanderArrow();
305 	}
306 }
307 
308 
309 void
310 TTeamMenuItem::DrawExpanderArrow()
311 {
312 	BRect frame = Frame();
313 	BRect rect(0.0f, 0.0f, kSwitchWidth, kHPad + 2.0f);
314 	rect.OffsetTo(BPoint(frame.right - rect.Width(),
315 		ContentLocation().y + ((frame.Height() - rect.Height()) / 2)));
316 
317 	float colorTint = B_DARKEN_3_TINT;
318 	rgb_color bgColor = ui_color(B_MENU_BACKGROUND_COLOR);
319 	if (bgColor.red + bgColor.green + bgColor.blue <= 128 * 3)
320 		colorTint = B_LIGHTEN_2_TINT;
321 
322 	be_control_look->DrawArrowShape(Menu(), rect, Menu()->Frame(),
323 		bgColor, fArrowDirection, 0, colorTint);
324 }
325 
326 
327 void
328 TTeamMenuItem::ToggleExpandState(bool resizeWindow)
329 {
330 	fExpanded = !fExpanded;
331 	fArrowDirection = fExpanded ? BControlLook::B_DOWN_ARROW
332 		: BControlLook::B_RIGHT_ARROW;
333 
334 	if (fExpanded) {
335 		// Populate Menu() with the stuff from SubMenu().
336 		TWindowMenu* sub = (static_cast<TWindowMenu*>(Submenu()));
337 		if (sub != NULL) {
338 			// force the menu to update it's contents.
339 			bool locked = sub->LockLooper();
340 				// if locking the looper failed, the menu is just not visible
341 			sub->AttachedToWindow();
342 			if (locked)
343 				sub->UnlockLooper();
344 
345 			if (sub->CountItems() > 1) {
346 				TExpandoMenuBar* parent = static_cast<TExpandoMenuBar*>(Menu());
347 				int myindex = parent->IndexOf(this) + 1;
348 
349 				TWindowMenuItem* windowItem = NULL;
350 				int32 childIndex = 0;
351 				int32 totalChildren = sub->CountItems() - 4;
352 					// hide, show, close, separator.
353 				for (; childIndex < totalChildren; childIndex++) {
354 					windowItem = static_cast<TWindowMenuItem*>
355 						(sub->RemoveItem((int32)0));
356 					parent->AddItem(windowItem, myindex + childIndex);
357 					windowItem->SetExpanded(true);
358 				}
359 				sub->SetExpanded(true, myindex + childIndex);
360 
361 				if (resizeWindow)
362 					parent->SizeWindow(-1);
363 			}
364 		}
365 	} else {
366 		// Remove the goodies from the Menu() that should be in the SubMenu();
367 		TWindowMenu* sub = static_cast<TWindowMenu*>(Submenu());
368 		if (sub != NULL) {
369 			TExpandoMenuBar* parent = static_cast<TExpandoMenuBar*>(Menu());
370 
371 			TWindowMenuItem* windowItem = NULL;
372 			int32 childIndex = parent->IndexOf(this) + 1;
373 			while (parent->SubmenuAt(childIndex) == NULL
374 				&& childIndex < parent->CountItems()) {
375 				windowItem = static_cast<TWindowMenuItem*>(
376 					parent->RemoveItem(childIndex));
377 				sub->AddItem(windowItem, 0);
378 				windowItem->SetExpanded(false);
379 			}
380 			sub->SetExpanded(false, 0);
381 
382 			if (resizeWindow)
383 				parent->SizeWindow(1);
384 		}
385 	}
386 }
387 
388 
389 TWindowMenuItem*
390 TTeamMenuItem::ExpandedWindowItem(int32 id)
391 {
392 	if (!fExpanded) {
393 		// Paranoia
394 		return NULL;
395 	}
396 
397 	TExpandoMenuBar* parent = static_cast<TExpandoMenuBar*>(Menu());
398 	int childIndex = parent->IndexOf(this) + 1;
399 
400 	while (!parent->SubmenuAt(childIndex)
401 		&& childIndex < parent->CountItems()) {
402 		TWindowMenuItem* item
403 			= static_cast<TWindowMenuItem*>(parent->ItemAt(childIndex));
404 		if (item->ID() == id)
405 			return item;
406 
407 		childIndex++;
408 	}
409 	return NULL;
410 }
411 
412 
413 BRect
414 TTeamMenuItem::ExpanderBounds() const
415 {
416 	BRect bounds(Frame());
417 	bounds.left = bounds.right - kSwitchWidth;
418 	return bounds;
419 }
420 
421 
422 //	#pragma mark - Private methods
423 
424 
425 void
426 TTeamMenuItem::_Init(BList* team, BBitmap* icon, char* name, char* signature,
427 	float width, float height)
428 {
429 	fTeam = team;
430 	fIcon = icon;
431 	fSignature = signature;
432 
433 	if (name == NULL) {
434 		char temp[32];
435 		snprintf(temp, sizeof(temp), "team %ld", (addr_t)team->ItemAt(0));
436 		name = strdup(temp);
437 	}
438 
439 	SetLabel(name);
440 
441 	fOverrideWidth = width;
442 	fOverrideHeight = height;
443 
444 	fBarView = static_cast<TBarApp*>(be_app)->BarView();
445 
446 	BFont font(be_plain_font);
447 	fLabelWidth = ceilf(font.StringWidth(name));
448 	font_height fontHeight;
449 	font.GetHeight(&fontHeight);
450 	fLabelAscent = ceilf(fontHeight.ascent);
451 	fLabelDescent = ceilf(fontHeight.descent + fontHeight.leading);
452 	fLabelHeight = fLabelAscent + fLabelDescent;
453 
454 	fOverriddenSelected = false;
455 
456 	fExpanded = false;
457 	fArrowDirection = BControlLook::B_RIGHT_ARROW;
458 }
459 
460 
461 bool
462 TTeamMenuItem::_IsSelected() const
463 {
464 	return IsSelected() || fOverriddenSelected;
465 }
466