xref: /haiku/src/apps/deskbar/TeamMenu.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
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 "TeamMenu.h"
38 
39 #include <algorithm>
40 #include <strings.h>
41 
42 #include <Application.h>
43 #include <Collator.h>
44 #include <ControlLook.h>
45 #include <Debug.h>
46 #include <Mime.h>
47 #include <Roster.h>
48 
49 #include "BarApp.h"
50 #include "BarMenuBar.h"
51 #include "BarView.h"
52 #include "DeskbarUtils.h"
53 #include "StatusView.h"
54 #include "TeamMenuItem.h"
55 
56 
57 //	#pragma mark - TTeamMenuItem
58 
59 
60 TTeamMenu::TTeamMenu(TBarView* barView)
61 	:
62 	BMenu("Team Menu"),
63 	fBarView(barView)
64 {
65 	SetItemMargins(0.0f, 0.0f, 0.0f, 0.0f);
66 	SetFont(be_plain_font);
67 }
68 
69 
70 int
71 TTeamMenu::CompareByName(const void* first, const void* second)
72 {
73 	BCollator collator;
74 	BLocale::Default()->GetCollator(&collator);
75 
76 	return collator.Compare(
77 		(*(static_cast<BarTeamInfo* const*>(first)))->name,
78 		(*(static_cast<BarTeamInfo* const*>(second)))->name);
79 }
80 
81 
82 void
83 TTeamMenu::AttachedToWindow()
84 {
85 	RemoveItems(0, CountItems(), true);
86 		// remove all items
87 
88 	BMessenger self(this);
89 	BList teamList;
90 	TBarApp::Subscribe(self, &teamList);
91 
92 	bool dragging = fBarView != NULL && fBarView->Dragging();
93 	desk_settings* settings = static_cast<TBarApp*>(be_app)->Settings();
94 	const int32 iconSize = static_cast<TBarApp*>(be_app)->TeamIconSize();
95 	const float iconPadding = be_control_look->ComposeSpacing(kIconPadding);
96 	float iconOnlyWidth = iconSize + iconPadding;
97 	if (settings->hideLabels)
98 		iconOnlyWidth += iconPadding; // add an extra icon padding
99 	const int32 large = be_control_look->ComposeIconSize(B_LARGE_ICON)
100 		.IntegerWidth() + 1;
101 	const int32 min = be_control_look->ComposeIconSize(kMinimumIconSize)
102 		.IntegerWidth() + 1;
103 
104 	// calculate the minimum item width based on font and icon size
105 	float minItemWidth = 0;
106 	if (settings->hideLabels) {
107 		minItemWidth = std::max(floorf(gMinimumWindowWidth / 2),
108 			iconOnlyWidth);
109 	} else {
110 		float labelWidth = gMinimumWindowWidth - iconOnlyWidth
111 			+ (be_plain_font->Size() - 12) * 4;
112 		if (iconSize <= large) // label wraps after 32x32
113 			labelWidth += iconSize - min;
114 		minItemWidth = iconOnlyWidth + labelWidth;
115 	}
116 
117 	float maxItemWidth = minItemWidth;
118 
119 	int32 teamCount = teamList.CountItems();
120 	if (!settings->hideLabels) {
121 		// go through list and find the widest label
122 		for (int32 i = 0; i < teamCount; i++) {
123 			BarTeamInfo* barInfo = (BarTeamInfo*)teamList.ItemAt(i);
124 			float labelWidth = StringWidth(barInfo->name);
125 			// label wraps after 32x32
126 			float itemWidth = iconSize > large
127 				? std::max(labelWidth, iconOnlyWidth)
128 				: labelWidth + iconOnlyWidth + min
129 					+ (be_plain_font->Size() - 12) * 4;
130 			maxItemWidth = std::max(maxItemWidth, itemWidth);
131 		}
132 
133 		// but not too wide
134 		maxItemWidth = std::min(maxItemWidth, gMaximumWindowWidth);
135 	}
136 
137 	SetMaxContentWidth(maxItemWidth);
138 
139 	if (settings->sortRunningApps)
140 		teamList.SortItems(TTeamMenu::CompareByName);
141 
142 	// go through list and add the items
143 	for (int32 i = 0; i < teamCount; i++) {
144 		// add items back
145 		BarTeamInfo* barInfo = (BarTeamInfo*)teamList.ItemAt(i);
146 		TTeamMenuItem* item = new TTeamMenuItem(barInfo->teams,
147 			barInfo->icon, barInfo->name, barInfo->sig, maxItemWidth);
148 
149 		if (settings->trackerAlwaysFirst
150 			&& strcasecmp(barInfo->sig, kTrackerSignature) == 0) {
151 			AddItem(item, 0);
152 		} else
153 			AddItem(item);
154 
155 		if (dragging && item != NULL) {
156 			bool canhandle = fBarView->AppCanHandleTypes(item->Signature());
157 			if (item->IsEnabled() != canhandle)
158 				item->SetEnabled(canhandle);
159 
160 			BMenu* menu = item->Submenu();
161 			if (menu != NULL) {
162 				menu->SetTrackingHook(fBarView->MenuTrackingHook,
163 					fBarView->GetTrackingHookData());
164 			}
165 		}
166 	}
167 
168 	if (CountItems() == 0) {
169 		BMenuItem* item = new BMenuItem("no application running", NULL);
170 		item->SetEnabled(false);
171 		AddItem(item);
172 	}
173 
174 	if (dragging && fBarView->LockLooper()) {
175 		SetTrackingHook(fBarView->MenuTrackingHook,
176 			fBarView->GetTrackingHookData());
177 		fBarView->DragStart();
178 		fBarView->UnlockLooper();
179 	}
180 
181 	BMenu::AttachedToWindow();
182 }
183 
184 
185 void
186 TTeamMenu::DetachedFromWindow()
187 {
188 	if (fBarView != NULL) {
189 		BLooper* looper = fBarView->Looper();
190 		if (looper != NULL && looper->Lock()) {
191 			fBarView->DragStop();
192 			looper->Unlock();
193 		}
194 	}
195 
196 	BMenu::DetachedFromWindow();
197 
198 	BMessenger self(this);
199 	TBarApp::Unsubscribe(self);
200 }
201 
202 
203 void
204 TTeamMenu::MessageReceived(BMessage* message)
205 {
206 	TTeamMenuItem* item = NULL;
207 
208 	switch (message->what) {
209 		case B_SOME_APP_QUIT:
210 		case kRemoveTeam:
211 		{
212 			int32 itemIndex = -1;
213 			message->FindInt32("itemIndex", &itemIndex);
214 			team_id team = -1;
215 			message->FindInt32("team", &team);
216 
217 			item = dynamic_cast<TTeamMenuItem*>(ItemAt(itemIndex));
218 			if (item != NULL && item->Teams()->HasItem((void*)(addr_t)team)) {
219 				item->Teams()->RemoveItem(team);
220 				RemoveItem(itemIndex);
221 				delete item;
222 			}
223 			break;
224 		}
225 
226 		default:
227 			BMenu::MessageReceived(message);
228 			break;
229 	}
230 }
231 
232 
233 void
234 TTeamMenu::MouseDown(BPoint where)
235 {
236 	if (fBarView == NULL || fBarView->Dragging())
237 		return BMenu::MouseDown(where);
238 
239 	BMenuItem* item = ItemAtPoint(where);
240 	if (item == NULL)
241 		return BMenu::MouseDown(where);
242 
243 	TTeamMenuItem* teamItem = dynamic_cast<TTeamMenuItem*>(item);
244 	if (teamItem == NULL || !teamItem->HandleMouseDown(where))
245 		BMenu::MouseDown(where);
246 }
247 
248 
249 BMenuItem*
250 TTeamMenu::ItemAtPoint(BPoint point)
251 {
252 	int32 itemCount = CountItems();
253 	for (int32 index = 0; index < itemCount; index++) {
254 		BMenuItem* item = ItemAt(index);
255 		if (item != NULL && item->Frame().Contains(point))
256 			return item;
257 	}
258 
259 	// no item found
260 	return NULL;
261 }
262