xref: /haiku/src/apps/deskbar/WindowMenuItem.cpp (revision 7749d0bb0c358a3279b1b9cc76d8376e900130a5)
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 #include "WindowMenuItem.h"
37 
38 #include <stdio.h>
39 
40 #include <Bitmap.h>
41 #include <Debug.h>
42 
43 #include "BarApp.h"
44 #include "BarMenuBar.h"
45 #include "ExpandoMenuBar.h"
46 #include "icons.h"
47 #include "ResourceSet.h"
48 #include "TeamMenu.h"
49 #include "WindowMenu.h"
50 
51 
52 const float kHPad = 10.0f;
53 const float kVPad = 2.0f;
54 const float kLabelOffset = 8.0f;
55 const BRect kIconRect(1.0f, 1.0f, 13.0f, 14.0f);
56 
57 
58 TWindowMenuItem::TWindowMenuItem(const char* title, int32 id, bool mini,
59 		bool currentWorkspace, bool dragging)
60 	:
61 	BMenuItem(title, NULL),
62 	fID(id),
63 	fMini(mini),
64 	fCurrentWorkSpace(currentWorkspace),
65 	fDragging(dragging),
66 	fExpanded(false),
67 	fRequireUpdate(false),
68 	fModified(false),
69 	fFullTitle("")
70 {
71 	Initialize(title);
72 }
73 
74 
75 void
76 TWindowMenuItem::Initialize(const char* title)
77 {
78 	if (fMini) {
79 		fBitmap = fCurrentWorkSpace
80 			? AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_WindowHiddenIcon)
81 			: AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_WindowHiddenSwitchIcon);
82 	} else {
83 		fBitmap = fCurrentWorkSpace
84 			? AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_WindowShownIcon)
85 			: AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_WindowShownSwitchIcon);
86 	}
87 
88 	BFont font(be_plain_font);
89 	fTitleWidth = ceilf(font.StringWidth(title));
90 	fFullTitle = title;
91 	font_height fontHeight;
92 	font.GetHeight(&fontHeight);
93 	fTitleAscent = ceilf(fontHeight.ascent);
94 	fTitleDescent = ceilf(fontHeight.descent + fontHeight.leading);
95 }
96 
97 
98 void
99 TWindowMenuItem::SetTo(const char* title, int32 id, bool mini,
100 	bool currentWorkspace, bool dragging)
101 {
102 	fModified = fCurrentWorkSpace != currentWorkspace || fMini != mini;
103 
104 	fID = id;
105 	fMini = mini;
106 	fCurrentWorkSpace = currentWorkspace;
107 	fDragging = dragging;
108 	fRequireUpdate = false;
109 
110 	Initialize(title);
111 }
112 
113 
114 bool
115 TWindowMenuItem::ChangedState()
116 {
117 	return fModified;
118 }
119 
120 
121 void
122 TWindowMenuItem::SetLabel(const char* string)
123 {
124 	fFullTitle = string;
125 	BString truncatedTitle = fFullTitle;
126 
127 	if (fExpanded && Menu()) {
128 		BPoint contLoc = ContentLocation() + BPoint(kHPad, kVPad);
129 		contLoc.x += kIconRect.Width() + kLabelOffset;
130 
131 		be_plain_font->TruncateString(&truncatedTitle, B_TRUNCATE_MIDDLE,
132 			Frame().Width() - contLoc.x - 3.0f);
133 	}
134 
135 	if (strcmp(Label(), truncatedTitle.String()) != 0)
136 		BMenuItem::SetLabel(truncatedTitle.String());
137 }
138 
139 
140 const char*
141 TWindowMenuItem::FullTitle() const
142 {
143 	return fFullTitle.String();
144 }
145 
146 
147 /*static*/ int32
148 TWindowMenuItem::InsertIndexFor(BMenu* menu, int32 startIndex,
149 	TWindowMenuItem* newItem)
150 {
151 	for (int32 index = startIndex;; index++) {
152 		TWindowMenuItem* item
153 			= dynamic_cast<TWindowMenuItem*>(menu->ItemAt(index));
154 		if (item == NULL
155 			|| strcasecmp(item->FullTitle(), newItem->FullTitle()) > 0)
156 			return index;
157 	}
158 }
159 
160 
161 int32
162 TWindowMenuItem::ID()
163 {
164 	return fID;
165 }
166 
167 
168 void
169 TWindowMenuItem::GetContentSize(float* width, float* height)
170 {
171 	if (width != NULL) {
172 		if (!fExpanded) {
173 			*width = kHPad + fTitleWidth + kHPad;
174 			if (fID >= 0)
175 				*width += fBitmap->Bounds().Width() + kLabelOffset;
176 		} else
177 			*width = Frame().Width()/* - kHPad*/;
178 	}
179 
180 	// Note: when the item is in "expanded mode", ie embedded into
181 	// the Deskbar itself, then a truncated label is used in SetLabel()
182 	// The code here is ignorant of this fact, but it doesn't seem to
183 	// hurt anything.
184 
185 	if (height != NULL) {
186 		*height = (fID >= 0) ? fBitmap->Bounds().Height() : 0.0f;
187 		float labelHeight = fTitleAscent + fTitleDescent;
188 		*height = (labelHeight > *height) ? labelHeight : *height;
189 		*height += kVPad * 2;
190 	}
191 }
192 
193 
194 void
195 TWindowMenuItem::Draw()
196 {
197 	if (!fExpanded) {
198 		BMenuItem::Draw();
199 		return;
200 	}
201 
202 	rgb_color menuColor = tint_color(Menu()->ViewColor(), 1.07);
203 	BRect frame(Frame());
204 	BMenu* menu = Menu();
205 
206 	menu->PushState();
207 
208 	// if not selected or being tracked on, fill with gray
209 	TBarView* barview = (static_cast<TBarApp*>(be_app))->BarView();
210 	if ((!IsSelected() && !menu->IsRedrawAfterSticky())
211 		|| barview->Dragging() || !IsEnabled()) {
212 
213 		rgb_color shadow = tint_color(menuColor, 1.09);
214 		menu->SetHighColor(shadow);
215 		frame.right = frame.left + kHPad / 2;
216 		menu->FillRect(frame);
217 
218 		menu->SetHighColor(menuColor);
219 		frame.left = frame.right + 1;
220 		frame.right = Frame().right;
221 		menu->FillRect(frame);
222 	}
223 
224 	if (IsEnabled() && IsSelected() && !menu->IsRedrawAfterSticky()) {
225 		// fill
226 		menu->SetHighColor(tint_color(menuColor,
227 			B_HIGHLIGHT_BACKGROUND_TINT));
228 		menu->FillRect(frame);
229 	} else
230 		menu->SetLowColor(menuColor);
231 
232 	DrawContent();
233 	menu->PopState();
234 }
235 
236 
237 void
238 TWindowMenuItem::DrawContent()
239 {
240 	BMenu* menu = Menu();
241 	menu->PushState();
242 
243 	BRect frame(Frame());
244 	BPoint contLoc = ContentLocation() + BPoint(kHPad, kVPad);
245 	//if (fExpanded)
246 	//	contLoc.x += kHPad;
247 
248 	if (fID >= 0) {
249 		menu->SetDrawingMode(B_OP_OVER);
250 
251 		float width = fBitmap->Bounds().Width();
252 
253 		if (width > 16)
254 			contLoc.x -= 8;
255 
256 		menu->MovePenTo(contLoc);
257 		menu->DrawBitmapAsync(fBitmap);
258 
259 		if (width > 16)
260 			contLoc.x += 8;
261 
262 		contLoc.x += kIconRect.Width() + kLabelOffset;
263 	}
264 
265 	menu->SetDrawingMode(B_OP_COPY);
266 
267 	contLoc.y = frame.top
268 		+ ((frame.Height() - fTitleAscent - fTitleDescent) / 2) + 1.0f;
269 
270 	menu->MovePenTo(contLoc);
271 	// Set the pen color so that the label is always visible.
272 	menu->SetHighColor(0, 0, 0);
273 
274 	BMenuItem::DrawContent();
275 
276 	menu->PopState();
277 }
278 
279 
280 status_t
281 TWindowMenuItem::Invoke(BMessage* /*message*/)
282 {
283 	if (!fDragging) {
284 		if (fID >= 0) {
285 			int32 action = (modifiers() & B_CONTROL_KEY) != 0
286 				? B_MINIMIZE_WINDOW : B_BRING_TO_FRONT;
287 
288 			bool doZoom = false;
289 			BRect zoomRect(0.0f, 0.0f, 0.0f, 0.0f);
290 			BMenuItem* item;
291 			if (!fExpanded)
292 				item = Menu()->Superitem();
293 			else
294 				item = this;
295 
296 			if (item->Menu()->Window() != NULL) {
297 				zoomRect = item->Menu()->ConvertToScreen(item->Frame());
298 				doZoom = (fMini && action == B_BRING_TO_FRONT)
299 					|| (!fMini && action == B_MINIMIZE_WINDOW);
300 			}
301 
302 			do_window_action(fID, action, zoomRect, doZoom);
303 		}
304 	}
305 	return B_OK;
306 }
307 
308 
309 void
310 TWindowMenuItem::ExpandedItem(bool status)
311 {
312 	if (fExpanded != status) {
313 		fExpanded = status;
314 		SetLabel(fFullTitle.String());
315 	}
316 }
317 
318 
319 void
320 TWindowMenuItem::SetRequireUpdate()
321 {
322 	fRequireUpdate = true;
323 }
324 
325 
326 bool
327 TWindowMenuItem::RequiresUpdate()
328 {
329 	return fRequireUpdate;
330 }
331 
332