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