#include "DirectionSelector.h" namespace ui { DirectionSelector::DirectionSelector(ui::Point position, float radius): ui::Component(position, ui::Point(radius * 2, radius * 2)), radius(radius), maxRadius(radius - (radius / 4)), useSnapPoints(false), snapPointRadius(0), snapPoints(std::vector<ui::Point>()), autoReturn(false), backgroundColor(ui::Colour(0, 0, 0, 63)), foregroundColor(ui::Colour(63, 63, 63, 127)), borderColor(ui::Colour(255, 255, 255)), snapPointColor(ui::Colour(63, 63, 63, 127)), updateCallback(nullptr), changeCallback(nullptr), mouseDown(false), mouseHover(false), altDown(false), offset(ui::Point(0, 0)) { } void DirectionSelector::CheckHovering(int x, int y) { mouseHover = std::hypot((offset.X + radius) - x, (offset.Y + radius) - y) < radius / 4; } void DirectionSelector::SetSnapPoints(int newRadius, int points) { snapPointRadius = newRadius; snapPoints.clear(); snapPoints.push_back(ui::Point(0, 0)); for (int i = 1; i < points; i++) { int dist = ((float)i / (float)(points - 1)) * maxRadius; snapPoints.push_back(ui::Point(0, dist)); snapPoints.push_back(ui::Point(0, -1 * dist)); snapPoints.push_back(ui::Point(-1 * dist, 0)); snapPoints.push_back(ui::Point(dist, 0)); } useSnapPoints = true; } void DirectionSelector::ClearSnapPoints() { useSnapPoints = false; snapPoints.clear(); } float DirectionSelector::GetXValue() { return offset.X / maxRadius; } float DirectionSelector::GetYValue() { return offset.Y / maxRadius; } float DirectionSelector::GetTotalValue() { return std::hypot(offset.X, offset.Y) / maxRadius; } void DirectionSelector::SetPositionAbs(float absx, float absy) { SetPosition(absx - radius, absy - radius); } void DirectionSelector::SetPosition(float x, float y) { if (std::hypot(x, y) > maxRadius) { offset.X = (maxRadius * x) / std::hypot(x, y); offset.Y = (maxRadius * y) / std::hypot(x, y); } else { offset.X = x; offset.Y = y; } if (useSnapPoints && !altDown) { for (const ui::Point& i : snapPoints) if (std::hypot(i.X - offset.X, i.Y - offset.Y) <= snapPointRadius) { offset.X = i.X; offset.Y = i.Y; } } if (updateCallback) updateCallback(GetXValue(), GetYValue()); } void DirectionSelector::SetValues(float x, float y) { SetPosition(x * maxRadius, y * maxRadius); } void DirectionSelector::Draw(const ui::Point& screenPos) { Graphics * g = GetGraphics(); ui::Point center = screenPos + radius; g->fillcircle(center.X, center.Y, radius, radius, backgroundColor.Red, backgroundColor.Green, backgroundColor.Blue, backgroundColor.Alpha); g->drawcircle(center.X, center.Y, radius, radius, borderColor.Red, borderColor.Green, borderColor.Blue, borderColor.Alpha); for (const ui::Point& i : snapPoints) g->fillrect( (center.X + i.X) - (radius / 30), (center.Y + i.Y) - (radius / 30), radius / 10, radius / 10, snapPointColor.Red, snapPointColor.Green, snapPointColor.Blue, altDown ? (int)(snapPointColor.Alpha / 2) : snapPointColor.Alpha ); g->fillcircle(center.X + offset.X, center.Y + offset.Y, radius / 4, radius / 4, foregroundColor.Red, foregroundColor.Green, foregroundColor.Blue, mouseHover ? std::min((int)(foregroundColor.Alpha * 1.5f), 255) : foregroundColor.Alpha); g->drawcircle(center.X + offset.X, center.Y + offset.Y, radius / 4, radius / 4, borderColor.Red, borderColor.Green, borderColor.Blue, borderColor.Alpha); } void DirectionSelector::OnMouseMoved(int x, int y, int dx, int dy) { if (mouseDown) SetPositionAbs(x, y); CheckHovering(x, y); } void DirectionSelector::OnMouseClick(int x, int y, unsigned button) { mouseDown = true; SetPositionAbs(x, y); CheckHovering(x, y); } void DirectionSelector::OnMouseUp(int x, int y, unsigned button) { mouseDown = false; if (autoReturn) SetPosition(0, 0); CheckHovering(x - Position.X, y - Position.Y); if (changeCallback) changeCallback(GetXValue(), GetYValue()); } }