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