xref: /haiku/src/apps/deskbar/WindowMenuItem.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 "WindowMenuItem.h"
38 
39 #include <Bitmap.h>
40 #include <ControlLook.h>
41 #include <Debug.h>
42 #include <NaturalCompare.h>
43 
44 #include "BarApp.h"
45 #include "BarMenuBar.h"
46 #include "BarView.h"
47 #include "ExpandoMenuBar.h"
48 #include "ResourceSet.h"
49 #include "TeamMenu.h"
50 #include "WindowMenu.h"
51 
52 #include "icons.h"
53 
54 
55 static float sHPad, sVPad, sLabelOffset = 0.0f;
56 
57 
58 //	#pragma mark - TWindowMenuItem
59 
60 
61 TWindowMenuItem::TWindowMenuItem(const char* name, int32 id, bool mini,
62 	bool currentWorkspace, bool dragging)
63 	:
64 	TTruncatableMenuItem(name, NULL),
65 	fID(id),
66 	fMini(mini),
67 	fCurrentWorkSpace(currentWorkspace),
68 	fDragging(dragging),
69 	fExpanded(false),
70 	fRequireUpdate(false),
71 	fModified(false)
72 {
73 	_Init(name);
74 }
75 
76 
77 void
78 TWindowMenuItem::GetContentSize(float* width, float* height)
79 {
80 	if (width != NULL) {
81 		if (!fExpanded) {
82 			*width = sHPad + fLabelWidth + sHPad;
83 			if (fID >= 0)
84 				*width += fBitmap->Bounds().Width() + sLabelOffset;
85 		} else
86 			*width = Frame().Width()/* - sHPad*/;
87 	}
88 
89 	// Note: when the item is in "expanded mode", ie embedded into
90 	// the Deskbar itself, then a truncated label is used in SetLabel()
91 	// The code here is ignorant of this fact, but it doesn't seem to
92 	// hurt anything.
93 
94 	if (height != NULL) {
95 		*height = (fID >= 0) ? fBitmap->Bounds().Height() : 0.0f;
96 		float labelHeight = fLabelAscent + fLabelDescent;
97 		*height = (labelHeight > *height) ? labelHeight : *height;
98 		*height += sVPad * 2;
99 	}
100 }
101 
102 
103 void
104 TWindowMenuItem::Draw()
105 {
106 	if (!fExpanded) {
107 		BMenuItem::Draw();
108 		return;
109 	}
110 
111 	// TODO: Tint this smartly based on the low color, this does
112 	// nothing to black.
113 	rgb_color menuColor = tint_color(ui_color(B_MENU_BACKGROUND_COLOR), 1.07);
114 	BRect frame(Frame());
115 	BMenu* menu = Menu();
116 
117 	menu->PushState();
118 
119 	// if not selected or being tracked on, fill with gray
120 	TBarView* barview = (static_cast<TBarApp*>(be_app))->BarView();
121 	if ((!IsSelected() && !menu->IsRedrawAfterSticky())
122 		|| barview->Dragging() || !IsEnabled()) {
123 
124 		rgb_color shadow = tint_color(menuColor, 1.09);
125 		menu->SetHighColor(shadow);
126 		frame.right = frame.left + sHPad / 2;
127 		menu->FillRect(frame);
128 
129 		menu->SetHighColor(menuColor);
130 		frame.left = frame.right + 1;
131 		frame.right = Frame().right;
132 		menu->FillRect(frame);
133 	}
134 
135 	if (IsEnabled() && IsSelected() && !menu->IsRedrawAfterSticky()) {
136 		// fill
137 		rgb_color backColor = tint_color(menuColor,
138 			B_HIGHLIGHT_BACKGROUND_TINT);
139 		menu->SetLowColor(backColor);
140 		menu->SetHighColor(backColor);
141 		menu->FillRect(frame);
142 	} else {
143 		menu->SetLowColor(menuColor);
144 		menu->SetHighColor(menuColor);
145 	}
146 
147 	DrawContent();
148 
149 	menu->PopState();
150 }
151 
152 
153 void
154 TWindowMenuItem::DrawContent()
155 {
156 	BMenu* menu = Menu();
157 	BPoint contentLocation = ContentLocation() + BPoint(sHPad, 0);
158 
159 	if (fID >= 0) {
160 		menu->SetDrawingMode(B_OP_OVER);
161 
162 		const float bitmapWidth = fBitmap->Bounds().Width(),
163 			bitmapHeight = fBitmap->Bounds().Height();
164 		float shiftedBy = 0.0f;
165 		if (bitmapWidth > bitmapHeight) {
166 			shiftedBy = (bitmapHeight + 1) / 2.0f;
167 			contentLocation.x -= shiftedBy;
168 		}
169 
170 		float height;
171 		GetContentSize(NULL, &height);
172 		contentLocation.y += (height - bitmapHeight) / 2;
173 
174 		menu->MovePenTo(contentLocation);
175 		menu->DrawBitmapAsync(fBitmap);
176 
177 		contentLocation.x += shiftedBy;
178 		contentLocation.x += (bitmapWidth - shiftedBy) + sLabelOffset;
179 	}
180 	contentLocation.y = ContentLocation().y + sVPad + fLabelAscent;
181 
182 	menu->SetDrawingMode(B_OP_COPY);
183 	menu->MovePenTo(contentLocation);
184 
185 	if (IsSelected())
186 		menu->SetHighColor(ui_color(B_MENU_SELECTED_ITEM_TEXT_COLOR));
187 	else
188 		menu->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR));
189 
190 	float labelWidth = menu->StringWidth(Label());
191 	BPoint penLocation = menu->PenLocation();
192 	float offset = penLocation.x - Frame().left;
193 
194 	menu->DrawString(Label(labelWidth + offset));
195 }
196 
197 
198 status_t
199 TWindowMenuItem::Invoke(BMessage* /*message*/)
200 {
201 	if (!fDragging) {
202 		if (fID >= 0) {
203 			int32 action = (modifiers() & B_CONTROL_KEY) != 0
204 				? B_MINIMIZE_WINDOW : B_BRING_TO_FRONT;
205 
206 			bool doZoom = false;
207 			BRect zoomRect(0.0f, 0.0f, 0.0f, 0.0f);
208 			BMenuItem* item;
209 			if (!fExpanded)
210 				item = Menu()->Superitem();
211 			else
212 				item = this;
213 
214 			if (item->Menu()->Window() != NULL) {
215 				zoomRect = item->Menu()->ConvertToScreen(item->Frame());
216 				doZoom = (fMini && action == B_BRING_TO_FRONT)
217 					|| (!fMini && action == B_MINIMIZE_WINDOW);
218 			}
219 
220 			do_window_action(fID, action, zoomRect, doZoom);
221 		}
222 	}
223 	return B_OK;
224 }
225 
226 
227 void
228 TWindowMenuItem::SetTo(const char* name, int32 id, bool mini,
229 	bool currentWorkspace, bool dragging)
230 {
231 	fModified = fCurrentWorkSpace != currentWorkspace || fMini != mini;
232 
233 	fID = id;
234 	fMini = mini;
235 	fCurrentWorkSpace = currentWorkspace;
236 	fDragging = dragging;
237 	fRequireUpdate = false;
238 
239 	_Init(name);
240 }
241 
242 
243 /*static*/ int32
244 TWindowMenuItem::InsertIndexFor(BMenu* menu, int32 startIndex,
245 	TWindowMenuItem* newItem)
246 {
247 	for (int32 index = startIndex;; index++) {
248 		TWindowMenuItem* item
249 			= dynamic_cast<TWindowMenuItem*>(menu->ItemAt(index));
250 		if (item == NULL
251 			|| NaturalCompare(item->Label(), newItem->Label()) > 0) {
252 			return index;
253 		}
254 	}
255 }
256 
257 
258 //	#pragma mark - private methods
259 
260 
261 void
262 TWindowMenuItem::_Init(const char* name)
263 {
264 	if (sHPad == 0.0f) {
265 		// Initialize the padding values.
266 		sHPad = be_control_look->ComposeSpacing(B_USE_ITEM_SPACING) - 1.0f;
267 		sVPad = ceilf(be_control_look->ComposeSpacing(B_USE_SMALL_SPACING) / 4.0f);
268 		sLabelOffset = ceilf((be_control_look->DefaultLabelSpacing() / 3.0f) * 4.0f);
269 	}
270 
271 	if (fMini) {
272 		fBitmap = fCurrentWorkSpace
273 			? AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_WindowHiddenIcon)
274 			: AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_WindowHiddenSwitchIcon);
275 	} else {
276 		fBitmap = fCurrentWorkSpace
277 			? AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_WindowShownIcon)
278 			: AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_WindowShownSwitchIcon);
279 	}
280 
281 	BFont font(be_plain_font);
282 	fLabelWidth = ceilf(font.StringWidth(name));
283 	font_height fontHeight;
284 	font.GetHeight(&fontHeight);
285 	fLabelAscent = ceilf(fontHeight.ascent);
286 	fLabelDescent = ceilf(fontHeight.descent + fontHeight.leading);
287 
288 	SetLabel(name);
289 }
290