1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
30trademarks of Be Incorporated in the United States and other countries. Other
31brand product names are registered trademarks or trademarks of their respective
32holders.
33All 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
55static float sHPad, sVPad, sLabelOffset = 0.0f;
56
57
58//	#pragma mark - TWindowMenuItem
59
60
61TWindowMenuItem::TWindowMenuItem(const char* name, int32 id, bool minimized,
62	bool local, bool dragging)
63	:
64	TTruncatableMenuItem(name, NULL),
65	fBitmap(NULL),
66	fID(id),
67	fIsModified(false),
68	fIsMinimized(minimized),
69	fIsLocal(local),
70	fDragging(dragging),
71	fExpanded(false),
72	fRequireUpdate(false)
73{
74	_Init(name);
75}
76
77
78void
79TWindowMenuItem::GetContentSize(float* width, float* height)
80{
81	if (width != NULL) {
82		if (!fExpanded) {
83			*width = sHPad + fLabelWidth + sHPad;
84			if (fID >= 0)
85				*width += fBitmap->Bounds().Width() + sLabelOffset;
86		} else
87			*width = Frame().Width()/* - sHPad*/;
88	}
89
90	// Note: when the item is in "expanded mode", ie embedded into
91	// the Deskbar itself, then a truncated label is used in SetLabel()
92	// The code here is ignorant of this fact, but it doesn't seem to
93	// hurt anything.
94
95	if (height != NULL) {
96		*height = (fID >= 0) ? fBitmap->Bounds().Height() : 0.0f;
97		float labelHeight = fLabelAscent + fLabelDescent;
98		*height = (labelHeight > *height) ? labelHeight : *height;
99		*height += sVPad * 2;
100	}
101}
102
103
104void
105TWindowMenuItem::Draw()
106{
107	if (!fExpanded) {
108		BMenuItem::Draw();
109		return;
110	}
111
112	// TODO: Tint this smartly based on the low color, this does
113	// nothing to black.
114	rgb_color menuColor = tint_color(ui_color(B_MENU_BACKGROUND_COLOR), 1.07);
115	BRect frame(Frame());
116	BMenu* menu = Menu();
117
118	menu->PushState();
119
120	// if not selected or being tracked on, fill with gray
121	TBarView* barview = (static_cast<TBarApp*>(be_app))->BarView();
122	if ((!IsSelected() && !menu->IsRedrawAfterSticky())
123		|| barview->Dragging() || !IsEnabled()) {
124
125		rgb_color shadow = tint_color(menuColor, 1.09);
126		menu->SetHighColor(shadow);
127		frame.right = frame.left + sHPad / 2;
128		menu->FillRect(frame);
129
130		menu->SetHighColor(menuColor);
131		frame.left = frame.right + 1;
132		frame.right = Frame().right;
133		menu->FillRect(frame);
134	}
135
136	if (IsEnabled() && IsSelected() && !menu->IsRedrawAfterSticky()) {
137		// fill
138		rgb_color backColor = tint_color(menuColor,
139			B_HIGHLIGHT_BACKGROUND_TINT);
140		menu->SetLowColor(backColor);
141		menu->SetHighColor(backColor);
142		menu->FillRect(frame);
143	} else {
144		menu->SetLowColor(menuColor);
145		menu->SetHighColor(menuColor);
146	}
147
148	DrawContent();
149
150	menu->PopState();
151}
152
153
154void
155TWindowMenuItem::DrawContent()
156{
157	BMenu* menu = Menu();
158	BPoint contentLocation = ContentLocation() + BPoint(sHPad, 0);
159
160	if (fID >= 0) {
161		menu->SetDrawingMode(B_OP_OVER);
162
163		const float bitmapWidth = fBitmap->Bounds().Width(),
164			bitmapHeight = fBitmap->Bounds().Height();
165		float shiftedBy = 0.0f;
166		if (bitmapWidth > bitmapHeight) {
167			shiftedBy = (bitmapHeight + 1) / 2.0f;
168			contentLocation.x -= shiftedBy;
169		}
170
171		float height;
172		GetContentSize(NULL, &height);
173		contentLocation.y += (height - bitmapHeight) / 2;
174
175		menu->MovePenTo(contentLocation);
176		menu->DrawBitmapAsync(fBitmap);
177
178		contentLocation.x += shiftedBy;
179		contentLocation.x += (bitmapWidth - shiftedBy) + sLabelOffset;
180	}
181	contentLocation.y = ContentLocation().y + sVPad + fLabelAscent;
182
183	menu->SetDrawingMode(B_OP_COPY);
184	menu->MovePenTo(contentLocation);
185
186	if (IsSelected())
187		menu->SetHighColor(ui_color(B_MENU_SELECTED_ITEM_TEXT_COLOR));
188	else
189		menu->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR));
190
191	float labelWidth = menu->StringWidth(Label());
192	BPoint penLocation = menu->PenLocation();
193	float offset = penLocation.x - Frame().left;
194
195	menu->DrawString(Label(labelWidth + offset));
196}
197
198
199status_t
200TWindowMenuItem::Invoke(BMessage* /*message*/)
201{
202	if (!fDragging) {
203		if (fID >= 0) {
204			int32 action = (modifiers() & B_CONTROL_KEY) != 0
205				? B_MINIMIZE_WINDOW : B_BRING_TO_FRONT;
206
207			bool doZoom = false;
208			BRect zoomRect(0.0f, 0.0f, 0.0f, 0.0f);
209			BMenuItem* item;
210			if (!fExpanded)
211				item = Menu()->Superitem();
212			else
213				item = this;
214
215			if (item->Menu()->Window() != NULL) {
216				zoomRect = item->Menu()->ConvertToScreen(item->Frame());
217				doZoom = (fIsMinimized && action == B_BRING_TO_FRONT)
218					|| (!fIsMinimized && action == B_MINIMIZE_WINDOW);
219			}
220
221			do_window_action(fID, action, zoomRect, doZoom);
222		}
223	}
224	return B_OK;
225}
226
227
228void
229TWindowMenuItem::SetTo(const char* name, int32 id, bool minimized,
230	bool local, bool dragging)
231{
232	fIsModified = fIsLocal != local || fIsMinimized != minimized;
233
234	fID = id;
235	fIsMinimized = minimized;
236	fIsLocal = local;
237	fDragging = dragging;
238	fRequireUpdate = false;
239
240	_Init(name);
241}
242
243
244/*static*/ int32
245TWindowMenuItem::InsertIndexFor(BMenu* menu, int32 startIndex,
246	TWindowMenuItem* newItem)
247{
248	for (int32 index = startIndex;; index++) {
249		TWindowMenuItem* item
250			= dynamic_cast<TWindowMenuItem*>(menu->ItemAt(index));
251		if (item == NULL
252			|| NaturalCompare(item->Label(), newItem->Label()) > 0) {
253			return index;
254		}
255	}
256}
257
258
259//	#pragma mark - TWindowMenuItem private methods
260
261
262void
263TWindowMenuItem::_Init(const char* name)
264{
265	if (sHPad == 0.0f) {
266		// Initialize the padding values.
267		sHPad = be_control_look->ComposeSpacing(B_USE_ITEM_SPACING) - 1.0f;
268		sVPad = ceilf(be_control_look->ComposeSpacing(B_USE_SMALL_SPACING) / 4.0f);
269		sLabelOffset = ceilf((be_control_look->DefaultLabelSpacing() / 3.0f) * 4.0f);
270	}
271
272	TBarApp* app = static_cast<TBarApp*>(be_app);
273	fBitmap = app->FetchWindowIcon(fIsLocal, fIsMinimized);
274
275	// use menu font (parent font not available yet)
276	menu_info info;
277	get_menu_info(&info);
278	BFont font;
279	font.SetFamilyAndStyle(info.f_family, info.f_style);
280	font.SetSize(info.font_size);
281	fLabelWidth = ceilf(font.StringWidth(name));
282	font_height fontHeight;
283	font.GetHeight(&fontHeight);
284	fLabelAscent = ceilf(fontHeight.ascent);
285	fLabelDescent = ceilf(fontHeight.descent + fontHeight.leading);
286
287	SetLabel(name);
288}
289