xref: /haiku/src/preferences/screensaver/ScreenCornerSelector.cpp (revision 1149fa6ece3567c466008a04ae8a830a63bafdaa)
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 	SetViewColor(ui_color(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 			SetHighColor(210, 210, 255);
108 			FillRoundRect(innerRect, kMonitorBorderSize, kMonitorBorderSize);
109 		}
110 
111 		if (IsFocus() && Window()->IsActive())
112 			SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
113 		else
114 			SetHighColor(blackColor);
115 		StrokeRoundRect(innerRect, kMonitorBorderSize, kMonitorBorderSize);
116 
117 		if (IsFocusChanging())
118 			return;
119 
120 		// power light
121 
122 		SetHighColor(redColor);
123 		BPoint powerPos(outerRect.left + kMonitorBorderSize * 2, outerRect.bottom
124 			- kMonitorBorderSize);
125 		StrokeLine(powerPos, BPoint(powerPos.x + 2, powerPos.y));
126 	}
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 	StrokeEllipse(rect);
203 
204 	size -= ceilf(sin(M_PI / 4) * size + 2);
205 	rect.InsetBy(size, size);
206 	StrokeLine(rect.RightTop(), rect.LeftBottom());
207 
208 	SetPenSize(1);
209 }
210 
211 
212 void
213 ScreenCornerSelector::_DrawArrow(BRect innerFrame)
214 {
215 	float size = kArrowSize;
216 	float sizeX = fCurrentCorner == UP_LEFT_CORNER
217 		|| fCurrentCorner == DOWN_LEFT_CORNER ? size : -size;
218 	float sizeY = fCurrentCorner == UP_LEFT_CORNER
219 		|| fCurrentCorner == UP_RIGHT_CORNER ? size : -size;
220 
221 	innerFrame.InsetBy(2, 2);
222 	BPoint origin(sizeX < 0 ? innerFrame.right : innerFrame.left,
223 		sizeY < 0 ? innerFrame.bottom : innerFrame.top);
224 
225 	SetHighColor(kBlack);
226 	FillTriangle(BPoint(origin.x, origin.y), BPoint(origin.x, origin.y + sizeY),
227 		BPoint(origin.x + sizeX, origin.y));
228 }
229 
230 
231 screen_corner
232 ScreenCornerSelector::_ScreenCorner(BPoint point,
233 	screen_corner previousCorner) const
234 {
235 	BRect innerFrame = _InnerFrame(_MonitorFrame());
236 
237 	if (!innerFrame.Contains(point))
238 		return previousCorner;
239 
240 	if (_CenterFrame(innerFrame).Contains(point))
241 		return NO_CORNER;
242 
243 	float centerX = innerFrame.left + innerFrame.Width() / 2;
244 	float centerY = innerFrame.top + innerFrame.Height() / 2;
245 	if (point.x < centerX)
246 		return point.y < centerY ? UP_LEFT_CORNER : DOWN_LEFT_CORNER;
247 
248 	return point.y < centerY ? UP_RIGHT_CORNER : DOWN_RIGHT_CORNER;
249 }
250 
251 
252 void
253 ScreenCornerSelector::MouseDown(BPoint where)
254 {
255 	fPreviousCorner = Value();
256 
257 	SetValue(_ScreenCorner(where, (screen_corner)fPreviousCorner));
258 	SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
259 }
260 
261 
262 void
263 ScreenCornerSelector::MouseUp(BPoint where)
264 {
265 	fPreviousCorner = -1;
266 }
267 
268 
269 void
270 ScreenCornerSelector::MouseMoved(BPoint where, uint32 transit,
271 	const BMessage* dragMessage)
272 {
273 	if (fPreviousCorner == -1)
274 		return;
275 
276 	SetValue(_ScreenCorner(where, (screen_corner)fPreviousCorner));
277 }
278 
279 
280 void
281 ScreenCornerSelector::KeyDown(const char* bytes, int32 numBytes)
282 {
283 	switch (bytes[0]) {
284 		// arrow keys
285 
286 		case B_LEFT_ARROW:
287 		case '4':
288 			if (Corner() == UP_RIGHT_CORNER)
289 				SetCorner(UP_LEFT_CORNER);
290 			else if (Corner() == DOWN_RIGHT_CORNER)
291 				SetCorner(DOWN_LEFT_CORNER);
292 			break;
293 		case B_RIGHT_ARROW:
294 		case '6':
295 			if (Corner() == UP_LEFT_CORNER)
296 				SetCorner(UP_RIGHT_CORNER);
297 			else if (Corner() == DOWN_LEFT_CORNER)
298 				SetCorner(DOWN_RIGHT_CORNER);
299 			break;
300 		case B_UP_ARROW:
301 		case '8':
302 			if (Corner() == DOWN_LEFT_CORNER)
303 				SetCorner(UP_LEFT_CORNER);
304 			else if (Corner() == DOWN_RIGHT_CORNER)
305 				SetCorner(UP_RIGHT_CORNER);
306 			break;
307 		case B_DOWN_ARROW:
308 		case '2':
309 			if (Corner() == UP_LEFT_CORNER)
310 				SetCorner(DOWN_LEFT_CORNER);
311 			else if (Corner() == UP_RIGHT_CORNER)
312 				SetCorner(DOWN_RIGHT_CORNER);
313 			break;
314 
315 		// numlock keys
316 
317 		case B_HOME:
318 		case '7':
319 			SetCorner(UP_LEFT_CORNER);
320 			break;
321 		case B_PAGE_UP:
322 		case '9':
323 			SetCorner(UP_RIGHT_CORNER);
324 			break;
325 		case B_PAGE_DOWN:
326 		case '3':
327 			SetCorner(DOWN_RIGHT_CORNER);
328 			break;
329 		case B_END:
330 		case '1':
331 			SetCorner(DOWN_LEFT_CORNER);
332 			break;
333 
334 		default:
335 			BControl::KeyDown(bytes, numBytes);
336 	}
337 }
338 
339