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