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