xref: /haiku/src/preferences/screensaver/ScreenCornerSelector.cpp (revision 4bd0c1066b227cec4b79883bdef697c7a27f2e90)
1 /*
2  * Copyright 2003-2013 Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Phipps
7  *		Axel Dörfler, axeld@pinc-software.de
8  */
9 
10 #include "ScreenCornerSelector.h"
11 
12 #include <stdio.h>
13 
14 #include <Rect.h>
15 #include <Point.h>
16 #include <Shape.h>
17 #include <Screen.h>
18 #include <Window.h>
19 
20 #include "Constants.h"
21 #include "Utility.h"
22 
23 
24 static const float kAspectRatio = 4.0f / 3.0f;
25 static const float kMonitorBorderSize = 3.0f;
26 static const float kArrowSize = 11.0f;
27 static const float kStopSize = 15.0f;
28 
29 
30 ScreenCornerSelector::ScreenCornerSelector(BRect frame, const char* name,
31 	BMessage* message, uint32 resizingMode)
32 	:
33 	BControl(frame, name, NULL, message, resizingMode,
34 		B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE),
35 	fCurrentCorner(NO_CORNER),
36 	fPreviousCorner(-1)
37 {
38 	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
39 }
40 
41 
42 BRect
43 ScreenCornerSelector::_MonitorFrame() const
44 {
45 	float width = Bounds().Width();
46 	float height = Bounds().Height();
47 
48 	if (width / kAspectRatio > height)
49 		width = height * kAspectRatio;
50 	else if (height * kAspectRatio > width)
51 		height = width / kAspectRatio;
52 
53 	return BRect((Bounds().Width() - width) / 2,
54 		(Bounds().Height() - height) / 2,
55 		(Bounds().Width() + width) / 2, (Bounds().Height() + height) / 2);
56 }
57 
58 
59 BRect
60 ScreenCornerSelector::_InnerFrame(BRect monitorFrame) const
61 {
62 	return monitorFrame.InsetByCopy(kMonitorBorderSize + 3,
63 		kMonitorBorderSize + 3);
64 }
65 
66 
67 BRect
68 ScreenCornerSelector::_CenterFrame(BRect innerFrame) const
69 {
70 	return innerFrame.InsetByCopy(kArrowSize, kArrowSize);
71 }
72 
73 
74 void
75 ScreenCornerSelector::Draw(BRect updateRect)
76 {
77 	rgb_color darkColor = {160, 160, 160, 255};
78 	rgb_color blackColor = {0, 0, 0, 255};
79 	rgb_color redColor = {228, 0, 0, 255};
80 
81 	BRect outerRect = _MonitorFrame();
82 	BRect innerRect(outerRect.InsetByCopy(kMonitorBorderSize + 2,
83 		kMonitorBorderSize + 2));
84 
85 	SetDrawingMode(B_OP_OVER);
86 
87 	if (!_InnerFrame(outerRect).Contains(updateRect)) {
88 		// frame & background
89 
90 		// if the focus is changing, we don't redraw the whole view, but only
91 		// the part that's affected by the change
92 		if (!IsFocusChanging()) {
93 			SetHighColor(darkColor);
94 			FillRoundRect(outerRect, kMonitorBorderSize * 3 / 2,
95 				kMonitorBorderSize * 3 / 2);
96 		}
97 
98 		if (IsFocus() && Window()->IsActive())
99 			SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
100 		else
101 			SetHighColor(blackColor);
102 
103 		StrokeRoundRect(outerRect, kMonitorBorderSize * 3 / 2,
104 			kMonitorBorderSize * 3 / 2);
105 
106 		if (IsFocusChanging())
107 			return;
108 
109 		// power light
110 
111 		SetHighColor(redColor);
112 		BPoint powerPos(outerRect.left + kMonitorBorderSize * 2, outerRect.bottom
113 			- kMonitorBorderSize);
114 		StrokeLine(powerPos, BPoint(powerPos.x + 2, powerPos.y));
115 	}
116 
117 	if (!IsFocusChanging()) {
118 		SetHighColor(210, 210, 255);
119 		FillRoundRect(innerRect, kMonitorBorderSize, kMonitorBorderSize);
120 	}
121 
122 	if (IsFocus() && Window()->IsActive())
123 		SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
124 	else
125 		SetHighColor(blackColor);
126 	StrokeRoundRect(innerRect, kMonitorBorderSize, kMonitorBorderSize);
127 
128 	innerRect = _InnerFrame(outerRect);
129 
130 	if (fCurrentCorner != NO_CORNER)
131 		_DrawArrow(innerRect);
132 	else
133 		_DrawStop(innerRect);
134 
135 	SetDrawingMode(B_OP_COPY);
136 }
137 
138 
139 int32
140 ScreenCornerSelector::Value()
141 {
142 	return (int32)fCurrentCorner;
143 }
144 
145 
146 void
147 ScreenCornerSelector::SetValue(int32 corner)
148 {
149 	switch (corner) {
150 		case UP_LEFT_CORNER:
151 		case UP_RIGHT_CORNER:
152 		case DOWN_LEFT_CORNER:
153 		case DOWN_RIGHT_CORNER:
154 		case NO_CORNER:
155 			break;
156 
157 		default:
158 			corner = NO_CORNER;
159 	}
160 	if ((screen_corner)corner == fCurrentCorner)
161 		return;
162 
163 	fCurrentCorner = (screen_corner)corner;
164 	Invalidate(_InnerFrame(_MonitorFrame()));
165 	Invoke();
166 }
167 
168 
169 screen_corner
170 ScreenCornerSelector::Corner() const
171 {
172 	return fCurrentCorner;
173 }
174 
175 
176 void
177 ScreenCornerSelector::SetCorner(screen_corner corner)
178 {
179 	// redirected to SetValue() to make sure only valid values are set
180 	SetValue((int32)corner);
181 }
182 
183 
184 void
185 ScreenCornerSelector::_DrawStop(BRect innerFrame)
186 {
187 	BRect centerRect = _CenterFrame(innerFrame);
188 	float size = kStopSize;
189 	BRect rect;
190 	rect.left = centerRect.left + (centerRect.Width() - size) / 2;
191 	rect.top = centerRect.top + (centerRect.Height() - size) / 2;
192 	if (rect.left < centerRect.left || rect.top < centerRect.top) {
193 		size = centerRect.Height();
194 		rect.top = centerRect.top;
195 		rect.left = centerRect.left + (centerRect.Width() - size) / 2;
196 	}
197 	rect.right = rect.left + size - 1;
198 	rect.bottom = rect.top + size - 1;
199 
200 	SetHighColor(255, 0, 0);
201 	SetPenSize(2);
202 	SetFlags(Flags() | B_SUBPIXEL_PRECISE);
203 
204 	StrokeEllipse(rect);
205 
206 	size -= sin(M_PI / 4) * size + 2;
207 	rect.InsetBy(size, size);
208 	StrokeLine(rect.RightTop(), rect.LeftBottom());
209 
210 	SetFlags(Flags() & ~B_SUBPIXEL_PRECISE);
211 	SetPenSize(1);
212 }
213 
214 
215 void
216 ScreenCornerSelector::_DrawArrow(BRect innerFrame)
217 {
218 	float size = kArrowSize;
219 	float sizeX = fCurrentCorner == UP_LEFT_CORNER
220 		|| fCurrentCorner == DOWN_LEFT_CORNER ? size : -size;
221 	float sizeY = fCurrentCorner == UP_LEFT_CORNER
222 		|| fCurrentCorner == UP_RIGHT_CORNER ? size : -size;
223 
224 	innerFrame.InsetBy(2, 2);
225 	BPoint origin(sizeX < 0 ? innerFrame.right : innerFrame.left,
226 		sizeY < 0 ? innerFrame.bottom : innerFrame.top);
227 
228 	SetHighColor(kBlack);
229 	FillTriangle(BPoint(origin.x, origin.y), BPoint(origin.x, origin.y + sizeY),
230 		BPoint(origin.x + sizeX, origin.y));
231 }
232 
233 
234 screen_corner
235 ScreenCornerSelector::_ScreenCorner(BPoint point,
236 	screen_corner previousCorner) const
237 {
238 	BRect innerFrame = _InnerFrame(_MonitorFrame());
239 
240 	if (!innerFrame.Contains(point))
241 		return previousCorner;
242 
243 	if (_CenterFrame(innerFrame).Contains(point))
244 		return NO_CORNER;
245 
246 	float centerX = innerFrame.left + innerFrame.Width() / 2;
247 	float centerY = innerFrame.top + innerFrame.Height() / 2;
248 	if (point.x < centerX)
249 		return point.y < centerY ? UP_LEFT_CORNER : DOWN_LEFT_CORNER;
250 
251 	return point.y < centerY ? UP_RIGHT_CORNER : DOWN_RIGHT_CORNER;
252 }
253 
254 
255 void
256 ScreenCornerSelector::MouseDown(BPoint where)
257 {
258 	fPreviousCorner = Value();
259 
260 	SetValue(_ScreenCorner(where, (screen_corner)fPreviousCorner));
261 	SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
262 }
263 
264 
265 void
266 ScreenCornerSelector::MouseUp(BPoint where)
267 {
268 	fPreviousCorner = -1;
269 }
270 
271 
272 void
273 ScreenCornerSelector::MouseMoved(BPoint where, uint32 transit,
274 	const BMessage* dragMessage)
275 {
276 	if (fPreviousCorner == -1)
277 		return;
278 
279 	SetValue(_ScreenCorner(where, (screen_corner)fPreviousCorner));
280 }
281 
282 
283 void
284 ScreenCornerSelector::KeyDown(const char* bytes, int32 numBytes)
285 {
286 	switch (bytes[0]) {
287 		// arrow keys
288 
289 		case B_LEFT_ARROW:
290 		case '4':
291 			if (Corner() == UP_RIGHT_CORNER)
292 				SetCorner(UP_LEFT_CORNER);
293 			else if (Corner() == DOWN_RIGHT_CORNER)
294 				SetCorner(DOWN_LEFT_CORNER);
295 			break;
296 		case B_RIGHT_ARROW:
297 		case '6':
298 			if (Corner() == UP_LEFT_CORNER)
299 				SetCorner(UP_RIGHT_CORNER);
300 			else if (Corner() == DOWN_LEFT_CORNER)
301 				SetCorner(DOWN_RIGHT_CORNER);
302 			break;
303 		case B_UP_ARROW:
304 		case '8':
305 			if (Corner() == DOWN_LEFT_CORNER)
306 				SetCorner(UP_LEFT_CORNER);
307 			else if (Corner() == DOWN_RIGHT_CORNER)
308 				SetCorner(UP_RIGHT_CORNER);
309 			break;
310 		case B_DOWN_ARROW:
311 		case '2':
312 			if (Corner() == UP_LEFT_CORNER)
313 				SetCorner(DOWN_LEFT_CORNER);
314 			else if (Corner() == UP_RIGHT_CORNER)
315 				SetCorner(DOWN_RIGHT_CORNER);
316 			break;
317 
318 		// numlock keys
319 
320 		case B_HOME:
321 		case '7':
322 			SetCorner(UP_LEFT_CORNER);
323 			break;
324 		case B_PAGE_UP:
325 		case '9':
326 			SetCorner(UP_RIGHT_CORNER);
327 			break;
328 		case B_PAGE_DOWN:
329 		case '3':
330 			SetCorner(DOWN_RIGHT_CORNER);
331 			break;
332 		case B_END:
333 		case '1':
334 			SetCorner(DOWN_LEFT_CORNER);
335 			break;
336 
337 		default:
338 			BControl::KeyDown(bytes, numBytes);
339 	}
340 }
341 
342