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