166dee31aSJérôme Duval/*
223ca081aSJohn Scipione * Copyright 2003-2013 Haiku, Inc. All Rights Reserved.
366dee31aSJérôme Duval * Distributed under the terms of the MIT License.
412e1daa3SJérôme Duval *
512e1daa3SJérôme Duval * Authors:
67cae4a1eSAxel Dörfler *		Michael Phipps
7642090fdSAxel Dörfler *		Axel D��rfler, axeld@pinc-software.de
866dee31aSJérôme Duval */
966dee31aSJérôme Duval
105d74f3c1SAxel Dörfler#include "ScreenCornerSelector.h"
1123ca081aSJohn Scipione
1223ca081aSJohn Scipione#include <stdio.h>
137cae4a1eSAxel Dörfler
1452a38012Sejakowatz#include <Rect.h>
1552a38012Sejakowatz#include <Point.h>
1652a38012Sejakowatz#include <Shape.h>
17642090fdSAxel Dörfler#include <Screen.h>
18642090fdSAxel Dörfler#include <Window.h>
197cae4a1eSAxel Dörfler
2023ca081aSJohn Scipione#include "Constants.h"
2123ca081aSJohn Scipione#include "Utility.h"
2252a38012Sejakowatz
237cae4a1eSAxel Dörfler
24642090fdSAxel Dörflerstatic const float kAspectRatio = 4.0f / 3.0f;
25642090fdSAxel Dörflerstatic const float kMonitorBorderSize = 3.0f;
26642090fdSAxel Dörflerstatic const float kArrowSize = 11.0f;
27642090fdSAxel Dörflerstatic const float kStopSize = 15.0f;
287cae4a1eSAxel Dörfler
29642090fdSAxel Dörfler
3023ca081aSJohn ScipioneScreenCornerSelector::ScreenCornerSelector(BRect frame, const char* name,
3123ca081aSJohn Scipione	BMessage* message, uint32 resizingMode)
3223ca081aSJohn Scipione	:
3323ca081aSJohn Scipione	BControl(frame, name, NULL, message, resizingMode,
3423ca081aSJohn Scipione		B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE),
35642090fdSAxel Dörfler	fCurrentCorner(NO_CORNER),
36642090fdSAxel Dörfler	fPreviousCorner(-1)
37642090fdSAxel Dörfler{
38f0650dc9Slooncraz	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
39642090fdSAxel Dörfler}
40642090fdSAxel Dörfler
41642090fdSAxel Dörfler
42642090fdSAxel DörflerBRect
43642090fdSAxel DörflerScreenCornerSelector::_MonitorFrame() const
447cae4a1eSAxel Dörfler{
45642090fdSAxel Dörfler	float width = Bounds().Width();
46642090fdSAxel Dörfler	float height = Bounds().Height();
47642090fdSAxel Dörfler
48642090fdSAxel Dörfler	if (width / kAspectRatio > height)
49642090fdSAxel Dörfler		width = height * kAspectRatio;
50642090fdSAxel Dörfler	else if (height * kAspectRatio > width)
51642090fdSAxel Dörfler		height = width / kAspectRatio;
527cae4a1eSAxel Dörfler
537f5bbbdcSAxel Dörfler	return BRect((Bounds().Width() - width) / 2,
547f5bbbdcSAxel Dörfler		(Bounds().Height() - height) / 2,
55642090fdSAxel Dörfler		(Bounds().Width() + width) / 2, (Bounds().Height() + height) / 2);
567cae4a1eSAxel Dörfler}
577cae4a1eSAxel Dörfler
587cae4a1eSAxel Dörfler
59642090fdSAxel DörflerBRect
60642090fdSAxel DörflerScreenCornerSelector::_InnerFrame(BRect monitorFrame) const
61642090fdSAxel Dörfler{
62642090fdSAxel Dörfler	return monitorFrame.InsetByCopy(kMonitorBorderSize + 3,
63642090fdSAxel Dörfler		kMonitorBorderSize + 3);
64642090fdSAxel Dörfler}
657cae4a1eSAxel Dörfler
667cae4a1eSAxel Dörfler
67642090fdSAxel DörflerBRect
68642090fdSAxel DörflerScreenCornerSelector::_CenterFrame(BRect innerFrame) const
6966dee31aSJérôme Duval{
70642090fdSAxel Dörfler	return innerFrame.InsetByCopy(kArrowSize, kArrowSize);
7166dee31aSJérôme Duval}
7266dee31aSJérôme Duval
7366dee31aSJérôme Duval
747cae4a1eSAxel Dörflervoid
7523ca081aSJohn ScipioneScreenCornerSelector::Draw(BRect updateRect)
76f141dd57SMichael Phipps{
77642090fdSAxel Dörfler	rgb_color darkColor = {160, 160, 160, 255};
78642090fdSAxel Dörfler	rgb_color blackColor = {0, 0, 0, 255};
79642090fdSAxel Dörfler	rgb_color redColor = {228, 0, 0, 255};
80642090fdSAxel Dörfler
81642090fdSAxel Dörfler	BRect outerRect = _MonitorFrame();
82642090fdSAxel Dörfler	BRect innerRect(outerRect.InsetByCopy(kMonitorBorderSize + 2,
83642090fdSAxel Dörfler		kMonitorBorderSize + 2));
84642090fdSAxel Dörfler
85642090fdSAxel Dörfler	SetDrawingMode(B_OP_OVER);
86642090fdSAxel Dörfler
8723ca081aSJohn Scipione	if (!_InnerFrame(outerRect).Contains(updateRect)) {
88642090fdSAxel Dörfler		// frame & background
897f5bbbdcSAxel Dörfler
90642090fdSAxel Dörfler		// if the focus is changing, we don't redraw the whole view, but only
91642090fdSAxel Dörfler		// the part that's affected by the change
92642090fdSAxel Dörfler		if (!IsFocusChanging()) {
93642090fdSAxel Dörfler			SetHighColor(darkColor);
947f5bbbdcSAxel Dörfler			FillRoundRect(outerRect, kMonitorBorderSize * 3 / 2,
957f5bbbdcSAxel Dörfler				kMonitorBorderSize * 3 / 2);
96642090fdSAxel Dörfler		}
977f5bbbdcSAxel Dörfler
98642090fdSAxel Dörfler		if (IsFocus() && Window()->IsActive())
99642090fdSAxel Dörfler			SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
100642090fdSAxel Dörfler		else
101642090fdSAxel Dörfler			SetHighColor(blackColor);
1027f5bbbdcSAxel Dörfler
1037f5bbbdcSAxel Dörfler		StrokeRoundRect(outerRect, kMonitorBorderSize * 3 / 2,
1047f5bbbdcSAxel Dörfler			kMonitorBorderSize * 3 / 2);
1057f5bbbdcSAxel Dörfler
106642090fdSAxel Dörfler		if (IsFocusChanging())
107642090fdSAxel Dörfler			return;
1087f5bbbdcSAxel Dörfler
109642090fdSAxel Dörfler		// power light
1107f5bbbdcSAxel Dörfler
111642090fdSAxel Dörfler		SetHighColor(redColor);
112642090fdSAxel Dörfler		BPoint powerPos(outerRect.left + kMonitorBorderSize * 2, outerRect.bottom
113642090fdSAxel Dörfler			- kMonitorBorderSize);
114642090fdSAxel Dörfler		StrokeLine(powerPos, BPoint(powerPos.x + 2, powerPos.y));
115642090fdSAxel Dörfler	}
116642090fdSAxel Dörfler
1177118f158SAdrien Destugues	if (!IsFocusChanging()) {
1187118f158SAdrien Destugues		SetHighColor(210, 210, 255);
1197118f158SAdrien Destugues		FillRoundRect(innerRect, kMonitorBorderSize, kMonitorBorderSize);
1207118f158SAdrien Destugues	}
1217118f158SAdrien Destugues
1227118f158SAdrien Destugues	if (IsFocus() && Window()->IsActive())
1237118f158SAdrien Destugues		SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
1247118f158SAdrien Destugues	else
1257118f158SAdrien Destugues		SetHighColor(blackColor);
1267118f158SAdrien Destugues	StrokeRoundRect(innerRect, kMonitorBorderSize, kMonitorBorderSize);
1277118f158SAdrien Destugues
128642090fdSAxel Dörfler	innerRect = _InnerFrame(outerRect);
129642090fdSAxel Dörfler
130642090fdSAxel Dörfler	if (fCurrentCorner != NO_CORNER)
131642090fdSAxel Dörfler		_DrawArrow(innerRect);
132642090fdSAxel Dörfler	else
133642090fdSAxel Dörfler		_DrawStop(innerRect);
134642090fdSAxel Dörfler
135642090fdSAxel Dörfler	SetDrawingMode(B_OP_COPY);
136642090fdSAxel Dörfler}
137642090fdSAxel Dörfler
138642090fdSAxel Dörfler
139642090fdSAxel Dörflerint32
140642090fdSAxel DörflerScreenCornerSelector::Value()
141642090fdSAxel Dörfler{
142642090fdSAxel Dörfler	return (int32)fCurrentCorner;
14352a38012Sejakowatz}
14452a38012Sejakowatz
145f7f8f8fdSMichael Phipps
1467cae4a1eSAxel Dörflervoid
147642090fdSAxel DörflerScreenCornerSelector::SetValue(int32 corner)
148642090fdSAxel Dörfler{
149642090fdSAxel Dörfler	switch (corner) {
150642090fdSAxel Dörfler		case UP_LEFT_CORNER:
151642090fdSAxel Dörfler		case UP_RIGHT_CORNER:
152642090fdSAxel Dörfler		case DOWN_LEFT_CORNER:
153642090fdSAxel Dörfler		case DOWN_RIGHT_CORNER:
154642090fdSAxel Dörfler		case NO_CORNER:
155642090fdSAxel Dörfler			break;
156642090fdSAxel Dörfler
157642090fdSAxel Dörfler		default:
158642090fdSAxel Dörfler			corner = NO_CORNER;
159642090fdSAxel Dörfler	}
160642090fdSAxel Dörfler	if ((screen_corner)corner == fCurrentCorner)
161642090fdSAxel Dörfler		return;
162642090fdSAxel Dörfler
163642090fdSAxel Dörfler	fCurrentCorner = (screen_corner)corner;
164642090fdSAxel Dörfler	Invalidate(_InnerFrame(_MonitorFrame()));
165642090fdSAxel Dörfler	Invoke();
166642090fdSAxel Dörfler}
167642090fdSAxel Dörfler
168642090fdSAxel Dörfler
169642090fdSAxel Dörflerscreen_corner
170642090fdSAxel DörflerScreenCornerSelector::Corner() const
17152a38012Sejakowatz{
172642090fdSAxel Dörfler	return fCurrentCorner;
17352a38012Sejakowatz}
17452a38012Sejakowatz
175f141dd57SMichael Phipps
176642090fdSAxel Dörflervoid
177642090fdSAxel DörflerScreenCornerSelector::SetCorner(screen_corner corner)
178f141dd57SMichael Phipps{
179642090fdSAxel Dörfler	// redirected to SetValue() to make sure only valid values are set
180642090fdSAxel Dörfler	SetValue((int32)corner);
181642090fdSAxel Dörfler}
1827cae4a1eSAxel Dörfler
1837cae4a1eSAxel Dörfler
184642090fdSAxel Dörflervoid
1857f5bbbdcSAxel DörflerScreenCornerSelector::_DrawStop(BRect innerFrame)
186642090fdSAxel Dörfler{
187642090fdSAxel Dörfler	BRect centerRect = _CenterFrame(innerFrame);
188642090fdSAxel Dörfler	float size = kStopSize;
189642090fdSAxel Dörfler	BRect rect;
190642090fdSAxel Dörfler	rect.left = centerRect.left + (centerRect.Width() - size) / 2;
191642090fdSAxel Dörfler	rect.top = centerRect.top + (centerRect.Height() - size) / 2;
192642090fdSAxel Dörfler	if (rect.left < centerRect.left || rect.top < centerRect.top) {
193642090fdSAxel Dörfler		size = centerRect.Height();
194642090fdSAxel Dörfler		rect.top = centerRect.top;
195642090fdSAxel Dörfler		rect.left = centerRect.left + (centerRect.Width() - size) / 2;
1967cae4a1eSAxel Dörfler	}
197642090fdSAxel Dörfler	rect.right = rect.left + size - 1;
1987f5bbbdcSAxel Dörfler	rect.bottom = rect.top + size - 1;
199642090fdSAxel Dörfler
200642090fdSAxel Dörfler	SetHighColor(255, 0, 0);
201642090fdSAxel Dörfler	SetPenSize(2);
202b5440720SAdrien Destugues	SetFlags(Flags() | B_SUBPIXEL_PRECISE);
203b5440720SAdrien Destugues
204642090fdSAxel Dörfler	StrokeEllipse(rect);
2057cae4a1eSAxel Dörfler
206b5440720SAdrien Destugues	size -= sin(M_PI / 4) * size + 2;
207642090fdSAxel Dörfler	rect.InsetBy(size, size);
2080030de4aSStephan Aßmus	StrokeLine(rect.RightTop(), rect.LeftBottom());
209642090fdSAxel Dörfler
210b5440720SAdrien Destugues	SetFlags(Flags() & ~B_SUBPIXEL_PRECISE);
211642090fdSAxel Dörfler	SetPenSize(1);
2127cae4a1eSAxel Dörfler}
2137cae4a1eSAxel Dörfler
2147cae4a1eSAxel Dörfler
2157cae4a1eSAxel Dörflervoid
2167f5bbbdcSAxel DörflerScreenCornerSelector::_DrawArrow(BRect innerFrame)
217642090fdSAxel Dörfler{
218642090fdSAxel Dörfler	float size = kArrowSize;
2197f5bbbdcSAxel Dörfler	float sizeX = fCurrentCorner == UP_LEFT_CORNER
2207f5bbbdcSAxel Dörfler		|| fCurrentCorner == DOWN_LEFT_CORNER ? size : -size;
2217f5bbbdcSAxel Dörfler	float sizeY = fCurrentCorner == UP_LEFT_CORNER
2227f5bbbdcSAxel Dörfler		|| fCurrentCorner == UP_RIGHT_CORNER ? size : -size;
223642090fdSAxel Dörfler
224642090fdSAxel Dörfler	innerFrame.InsetBy(2, 2);
225642090fdSAxel Dörfler	BPoint origin(sizeX < 0 ? innerFrame.right : innerFrame.left,
226642090fdSAxel Dörfler		sizeY < 0 ? innerFrame.bottom : innerFrame.top);
227642090fdSAxel Dörfler
228642090fdSAxel Dörfler	SetHighColor(kBlack);
229642090fdSAxel Dörfler	FillTriangle(BPoint(origin.x, origin.y), BPoint(origin.x, origin.y + sizeY),
230642090fdSAxel Dörfler		BPoint(origin.x + sizeX, origin.y));
231642090fdSAxel Dörfler}
2327cae4a1eSAxel Dörfler
233642090fdSAxel Dörfler
234642090fdSAxel Dörflerscreen_corner
2357f5bbbdcSAxel DörflerScreenCornerSelector::_ScreenCorner(BPoint point,
2367f5bbbdcSAxel Dörfler	screen_corner previousCorner) const
237642090fdSAxel Dörfler{
238642090fdSAxel Dörfler	BRect innerFrame = _InnerFrame(_MonitorFrame());
239642090fdSAxel Dörfler
240642090fdSAxel Dörfler	if (!innerFrame.Contains(point))
241642090fdSAxel Dörfler		return previousCorner;
242642090fdSAxel Dörfler
243642090fdSAxel Dörfler	if (_CenterFrame(innerFrame).Contains(point))
244642090fdSAxel Dörfler		return NO_CORNER;
245642090fdSAxel Dörfler
246642090fdSAxel Dörfler	float centerX = innerFrame.left + innerFrame.Width() / 2;
247642090fdSAxel Dörfler	float centerY = innerFrame.top + innerFrame.Height() / 2;
248642090fdSAxel Dörfler	if (point.x < centerX)
249642090fdSAxel Dörfler		return point.y < centerY ? UP_LEFT_CORNER : DOWN_LEFT_CORNER;
250642090fdSAxel Dörfler
251642090fdSAxel Dörfler	return point.y < centerY ? UP_RIGHT_CORNER : DOWN_RIGHT_CORNER;
25252a38012Sejakowatz}
25352a38012Sejakowatz
25452a38012Sejakowatz
2557cae4a1eSAxel Dörflervoid
2567f5bbbdcSAxel DörflerScreenCornerSelector::MouseDown(BPoint where)
257642090fdSAxel Dörfler{
258642090fdSAxel Dörfler	fPreviousCorner = Value();
259642090fdSAxel Dörfler
260642090fdSAxel Dörfler	SetValue(_ScreenCorner(where, (screen_corner)fPreviousCorner));
261642090fdSAxel Dörfler	SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
262642090fdSAxel Dörfler}
263642090fdSAxel Dörfler
264642090fdSAxel Dörfler
265642090fdSAxel Dörflervoid
2667f5bbbdcSAxel DörflerScreenCornerSelector::MouseUp(BPoint where)
267642090fdSAxel Dörfler{
268642090fdSAxel Dörfler	fPreviousCorner = -1;
269642090fdSAxel Dörfler}
270642090fdSAxel Dörfler
271642090fdSAxel Dörfler
272642090fdSAxel Dörflervoid
2737f5bbbdcSAxel DörflerScreenCornerSelector::MouseMoved(BPoint where, uint32 transit,
2747f5bbbdcSAxel Dörfler	const BMessage* dragMessage)
275642090fdSAxel Dörfler{
276642090fdSAxel Dörfler	if (fPreviousCorner == -1)
277642090fdSAxel Dörfler		return;
278642090fdSAxel Dörfler
279642090fdSAxel Dörfler	SetValue(_ScreenCorner(where, (screen_corner)fPreviousCorner));
280642090fdSAxel Dörfler}
281642090fdSAxel Dörfler
282642090fdSAxel Dörfler
283642090fdSAxel Dörflervoid
284642090fdSAxel DörflerScreenCornerSelector::KeyDown(const char* bytes, int32 numBytes)
285642090fdSAxel Dörfler{
286642090fdSAxel Dörfler	switch (bytes[0]) {
287642090fdSAxel Dörfler		// arrow keys
288642090fdSAxel Dörfler
289642090fdSAxel Dörfler		case B_LEFT_ARROW:
290642090fdSAxel Dörfler		case '4':
291642090fdSAxel Dörfler			if (Corner() == UP_RIGHT_CORNER)
292642090fdSAxel Dörfler				SetCorner(UP_LEFT_CORNER);
293642090fdSAxel Dörfler			else if (Corner() == DOWN_RIGHT_CORNER)
294642090fdSAxel Dörfler				SetCorner(DOWN_LEFT_CORNER);
295642090fdSAxel Dörfler			break;
296642090fdSAxel Dörfler		case B_RIGHT_ARROW:
297642090fdSAxel Dörfler		case '6':
298642090fdSAxel Dörfler			if (Corner() == UP_LEFT_CORNER)
299642090fdSAxel Dörfler				SetCorner(UP_RIGHT_CORNER);
300642090fdSAxel Dörfler			else if (Corner() == DOWN_LEFT_CORNER)
301642090fdSAxel Dörfler				SetCorner(DOWN_RIGHT_CORNER);
302642090fdSAxel Dörfler			break;
303642090fdSAxel Dörfler		case B_UP_ARROW:
304642090fdSAxel Dörfler		case '8':
305642090fdSAxel Dörfler			if (Corner() == DOWN_LEFT_CORNER)
306642090fdSAxel Dörfler				SetCorner(UP_LEFT_CORNER);
307642090fdSAxel Dörfler			else if (Corner() == DOWN_RIGHT_CORNER)
308642090fdSAxel Dörfler				SetCorner(UP_RIGHT_CORNER);
309642090fdSAxel Dörfler			break;
310642090fdSAxel Dörfler		case B_DOWN_ARROW:
311642090fdSAxel Dörfler		case '2':
312642090fdSAxel Dörfler			if (Corner() == UP_LEFT_CORNER)
313642090fdSAxel Dörfler				SetCorner(DOWN_LEFT_CORNER);
314642090fdSAxel Dörfler			else if (Corner() == UP_RIGHT_CORNER)
315642090fdSAxel Dörfler				SetCorner(DOWN_RIGHT_CORNER);
316642090fdSAxel Dörfler			break;
317642090fdSAxel Dörfler
318642090fdSAxel Dörfler		// numlock keys
319642090fdSAxel Dörfler
320642090fdSAxel Dörfler		case B_HOME:
321642090fdSAxel Dörfler		case '7':
322642090fdSAxel Dörfler			SetCorner(UP_LEFT_CORNER);
323642090fdSAxel Dörfler			break;
324642090fdSAxel Dörfler		case B_PAGE_UP:
325642090fdSAxel Dörfler		case '9':
326642090fdSAxel Dörfler			SetCorner(UP_RIGHT_CORNER);
327642090fdSAxel Dörfler			break;
328642090fdSAxel Dörfler		case B_PAGE_DOWN:
329642090fdSAxel Dörfler		case '3':
330642090fdSAxel Dörfler			SetCorner(DOWN_RIGHT_CORNER);
331642090fdSAxel Dörfler			break;
332642090fdSAxel Dörfler		case B_END:
333642090fdSAxel Dörfler		case '1':
334642090fdSAxel Dörfler			SetCorner(DOWN_LEFT_CORNER);
335642090fdSAxel Dörfler			break;
336642090fdSAxel Dörfler
337642090fdSAxel Dörfler		default:
338642090fdSAxel Dörfler			BControl::KeyDown(bytes, numBytes);
339f141dd57SMichael Phipps	}
34052a38012Sejakowatz}
341642090fdSAxel Dörfler
342