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