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 24static const float kAspectRatio = 4.0f / 3.0f; 25static const float kMonitorBorderSize = 3.0f; 26static const float kArrowSize = 11.0f; 27static const float kStopSize = 15.0f; 28 29 30ScreenCornerSelector::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 42BRect 43ScreenCornerSelector::_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 59BRect 60ScreenCornerSelector::_InnerFrame(BRect monitorFrame) const 61{ 62 return monitorFrame.InsetByCopy(kMonitorBorderSize + 3, 63 kMonitorBorderSize + 3); 64} 65 66 67BRect 68ScreenCornerSelector::_CenterFrame(BRect innerFrame) const 69{ 70 return innerFrame.InsetByCopy(kArrowSize, kArrowSize); 71} 72 73 74void 75ScreenCornerSelector::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 139int32 140ScreenCornerSelector::Value() 141{ 142 return (int32)fCurrentCorner; 143} 144 145 146void 147ScreenCornerSelector::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 169screen_corner 170ScreenCornerSelector::Corner() const 171{ 172 return fCurrentCorner; 173} 174 175 176void 177ScreenCornerSelector::SetCorner(screen_corner corner) 178{ 179 // redirected to SetValue() to make sure only valid values are set 180 SetValue((int32)corner); 181} 182 183 184void 185ScreenCornerSelector::_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 215void 216ScreenCornerSelector::_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 234screen_corner 235ScreenCornerSelector::_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 255void 256ScreenCornerSelector::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 265void 266ScreenCornerSelector::MouseUp(BPoint where) 267{ 268 fPreviousCorner = -1; 269} 270 271 272void 273ScreenCornerSelector::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 283void 284ScreenCornerSelector::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