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