This repository has been archived on 2025-03-20. You can view files and clone it, but cannot push or open issues or pull requests.
The-Powder-Toy/src/gui/interface/DirectionSelector.cpp
catsoften 6aa68adbf4
Add custom gravity mode and replace hardcoded gravity interactions (#820)
Co-authored-by: Tamás Bálint Misius <lbphacker@gmail.com>
2022-07-31 08:19:16 +02:00

151 lines
3.8 KiB
C++

#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());
}
}