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