* Copyright 2003-2013 Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Phipps
* Axel Dörfler, axeld@pinc-software.de
*/
#include "ScreenCornerSelector.h"
#include <stdio.h>
#include <Rect.h>
#include <Point.h>
#include <Shape.h>
#include <Screen.h>
#include <Window.h>
#include "Constants.h"
#include "Utility.h"
static const float kAspectRatio = 4.0f / 3.0f;
static const float kMonitorBorderSize = 3.0f;
static const float kArrowSize = 11.0f;
static const float kStopSize = 15.0f;
ScreenCornerSelector::ScreenCornerSelector(BRect frame, const char* name,
BMessage* message, uint32 resizingMode)
:
BControl(frame, name, NULL, message, resizingMode,
B_WILL_DRAW | B_NAVIGABLE | B_FULL_UPDATE_ON_RESIZE),
fCurrentCorner(NO_CORNER),
fPreviousCorner(-1)
{
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
}
BRect
ScreenCornerSelector::_MonitorFrame() const
{
float width = Bounds().Width();
float height = Bounds().Height();
if (width / kAspectRatio > height)
width = height * kAspectRatio;
else if (height * kAspectRatio > width)
height = width / kAspectRatio;
return BRect((Bounds().Width() - width) / 2,
(Bounds().Height() - height) / 2,
(Bounds().Width() + width) / 2, (Bounds().Height() + height) / 2);
}
BRect
ScreenCornerSelector::_InnerFrame(BRect monitorFrame) const
{
return monitorFrame.InsetByCopy(kMonitorBorderSize + 3,
kMonitorBorderSize + 3);
}
BRect
ScreenCornerSelector::_CenterFrame(BRect innerFrame) const
{
return innerFrame.InsetByCopy(kArrowSize, kArrowSize);
}
void
ScreenCornerSelector::Draw(BRect updateRect)
{
rgb_color darkColor = {160, 160, 160, 255};
rgb_color blackColor = {0, 0, 0, 255};
rgb_color redColor = {228, 0, 0, 255};
BRect outerRect = _MonitorFrame();
BRect innerRect(outerRect.InsetByCopy(kMonitorBorderSize + 2,
kMonitorBorderSize + 2));
SetDrawingMode(B_OP_OVER);
if (!_InnerFrame(outerRect).Contains(updateRect)) {
if (!IsFocusChanging()) {
SetHighColor(darkColor);
FillRoundRect(outerRect, kMonitorBorderSize * 3 / 2,
kMonitorBorderSize * 3 / 2);
}
if (IsFocus() && Window()->IsActive())
SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
else
SetHighColor(blackColor);
StrokeRoundRect(outerRect, kMonitorBorderSize * 3 / 2,
kMonitorBorderSize * 3 / 2);
if (IsFocusChanging())
return;
SetHighColor(redColor);
BPoint powerPos(outerRect.left + kMonitorBorderSize * 2, outerRect.bottom
- kMonitorBorderSize);
StrokeLine(powerPos, BPoint(powerPos.x + 2, powerPos.y));
}
if (!IsFocusChanging()) {
SetHighColor(210, 210, 255);
FillRoundRect(innerRect, kMonitorBorderSize, kMonitorBorderSize);
}
if (IsFocus() && Window()->IsActive())
SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
else
SetHighColor(blackColor);
StrokeRoundRect(innerRect, kMonitorBorderSize, kMonitorBorderSize);
innerRect = _InnerFrame(outerRect);
if (fCurrentCorner != NO_CORNER)
_DrawArrow(innerRect);
else
_DrawStop(innerRect);
SetDrawingMode(B_OP_COPY);
}
int32
ScreenCornerSelector::Value()
{
return (int32)fCurrentCorner;
}
void
ScreenCornerSelector::SetValue(int32 corner)
{
switch (corner) {
case UP_LEFT_CORNER:
case UP_RIGHT_CORNER:
case DOWN_LEFT_CORNER:
case DOWN_RIGHT_CORNER:
case NO_CORNER:
break;
default:
corner = NO_CORNER;
}
if ((screen_corner)corner == fCurrentCorner)
return;
fCurrentCorner = (screen_corner)corner;
Invalidate(_InnerFrame(_MonitorFrame()));
Invoke();
}
screen_corner
ScreenCornerSelector::Corner() const
{
return fCurrentCorner;
}
void
ScreenCornerSelector::SetCorner(screen_corner corner)
{
SetValue((int32)corner);
}
void
ScreenCornerSelector::_DrawStop(BRect innerFrame)
{
BRect centerRect = _CenterFrame(innerFrame);
float size = kStopSize;
BRect rect;
rect.left = centerRect.left + (centerRect.Width() - size) / 2;
rect.top = centerRect.top + (centerRect.Height() - size) / 2;
if (rect.left < centerRect.left || rect.top < centerRect.top) {
size = centerRect.Height();
rect.top = centerRect.top;
rect.left = centerRect.left + (centerRect.Width() - size) / 2;
}
rect.right = rect.left + size - 1;
rect.bottom = rect.top + size - 1;
SetHighColor(255, 0, 0);
SetPenSize(2);
SetFlags(Flags() | B_SUBPIXEL_PRECISE);
StrokeEllipse(rect);
size -= sin(M_PI / 4) * size + 2;
rect.InsetBy(size, size);
StrokeLine(rect.RightTop(), rect.LeftBottom());
SetFlags(Flags() & ~B_SUBPIXEL_PRECISE);
SetPenSize(1);
}
void
ScreenCornerSelector::_DrawArrow(BRect innerFrame)
{
float size = kArrowSize;
float sizeX = fCurrentCorner == UP_LEFT_CORNER
|| fCurrentCorner == DOWN_LEFT_CORNER ? size : -size;
float sizeY = fCurrentCorner == UP_LEFT_CORNER
|| fCurrentCorner == UP_RIGHT_CORNER ? size : -size;
innerFrame.InsetBy(2, 2);
BPoint origin(sizeX < 0 ? innerFrame.right : innerFrame.left,
sizeY < 0 ? innerFrame.bottom : innerFrame.top);
SetHighColor(kBlack);
FillTriangle(BPoint(origin.x, origin.y), BPoint(origin.x, origin.y + sizeY),
BPoint(origin.x + sizeX, origin.y));
}
screen_corner
ScreenCornerSelector::_ScreenCorner(BPoint point,
screen_corner previousCorner) const
{
BRect innerFrame = _InnerFrame(_MonitorFrame());
if (!innerFrame.Contains(point))
return previousCorner;
if (_CenterFrame(innerFrame).Contains(point))
return NO_CORNER;
float centerX = innerFrame.left + innerFrame.Width() / 2;
float centerY = innerFrame.top + innerFrame.Height() / 2;
if (point.x < centerX)
return point.y < centerY ? UP_LEFT_CORNER : DOWN_LEFT_CORNER;
return point.y < centerY ? UP_RIGHT_CORNER : DOWN_RIGHT_CORNER;
}
void
ScreenCornerSelector::MouseDown(BPoint where)
{
fPreviousCorner = Value();
SetValue(_ScreenCorner(where, (screen_corner)fPreviousCorner));
SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
}
void
ScreenCornerSelector::MouseUp(BPoint where)
{
fPreviousCorner = -1;
}
void
ScreenCornerSelector::MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage)
{
if (fPreviousCorner == -1)
return;
SetValue(_ScreenCorner(where, (screen_corner)fPreviousCorner));
}
void
ScreenCornerSelector::KeyDown(const char* bytes, int32 numBytes)
{
switch (bytes[0]) {
case B_LEFT_ARROW:
case '4':
if (Corner() == UP_RIGHT_CORNER)
SetCorner(UP_LEFT_CORNER);
else if (Corner() == DOWN_RIGHT_CORNER)
SetCorner(DOWN_LEFT_CORNER);
break;
case B_RIGHT_ARROW:
case '6':
if (Corner() == UP_LEFT_CORNER)
SetCorner(UP_RIGHT_CORNER);
else if (Corner() == DOWN_LEFT_CORNER)
SetCorner(DOWN_RIGHT_CORNER);
break;
case B_UP_ARROW:
case '8':
if (Corner() == DOWN_LEFT_CORNER)
SetCorner(UP_LEFT_CORNER);
else if (Corner() == DOWN_RIGHT_CORNER)
SetCorner(UP_RIGHT_CORNER);
break;
case B_DOWN_ARROW:
case '2':
if (Corner() == UP_LEFT_CORNER)
SetCorner(DOWN_LEFT_CORNER);
else if (Corner() == UP_RIGHT_CORNER)
SetCorner(DOWN_RIGHT_CORNER);
break;
case B_HOME:
case '7':
SetCorner(UP_LEFT_CORNER);
break;
case B_PAGE_UP:
case '9':
SetCorner(UP_RIGHT_CORNER);
break;
case B_PAGE_DOWN:
case '3':
SetCorner(DOWN_RIGHT_CORNER);
break;
case B_END:
case '1':
SetCorner(DOWN_LEFT_CORNER);
break;
default:
BControl::KeyDown(bytes, numBytes);
}
}