371 lines
12 KiB
C++
371 lines
12 KiB
C++
#include "AxisCtrlButton.hpp"
|
|
#include "Label.hpp"
|
|
#include "libslic3r/libslic3r.h"
|
|
|
|
#include <wx/dcclient.h>
|
|
#include <wx/dcgraph.h>
|
|
|
|
StateColor blank_bg(StateColor(std::make_pair(wxColour("#FFFFFF"), (int)StateColor::Normal)));
|
|
static const wxColour BUTTON_BG_COL = wxColour("#EEEEEE");
|
|
static const wxColour BUTTON_IN_BG_COL = wxColour("#CECECE");
|
|
|
|
//static const wxColour bd = wxColour(0, 174, 66);
|
|
static const wxColour bd = wxColour(0x9A5F21);
|
|
static const wxColour text_num_color = wxColour(0x898989);
|
|
static const wxColour BUTTON_PRESS_COL = wxColour(172, 172, 172);
|
|
static const double sqrt2 = std::sqrt(2);
|
|
|
|
BEGIN_EVENT_TABLE(AxisCtrlButton, wxPanel)
|
|
EVT_LEFT_DOWN(AxisCtrlButton::mouseDown)
|
|
EVT_LEFT_UP(AxisCtrlButton::mouseReleased)
|
|
EVT_MOTION(AxisCtrlButton::mouseMoving)
|
|
EVT_PAINT(AxisCtrlButton::paintEvent)
|
|
END_EVENT_TABLE()
|
|
|
|
#define OUTER_SIZE FromDIP(105)
|
|
#define INNER_SIZE FromDIP(58)
|
|
#define HOME_SIZE FromDIP(23)
|
|
#define BLANK_SIZE FromDIP(24)
|
|
#define GAP_SIZE FromDIP(4)
|
|
|
|
AxisCtrlButton::AxisCtrlButton(wxWindow *parent, ScalableBitmap &icon, long stlye)
|
|
: wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, stlye)
|
|
, r_outer(OUTER_SIZE)
|
|
, r_inner(INNER_SIZE)
|
|
, r_home(HOME_SIZE)
|
|
, r_blank(BLANK_SIZE)
|
|
, gap(GAP_SIZE)
|
|
, last_pos(UNDEFINED)
|
|
, current_pos(UNDEFINED) // don't change init value
|
|
, text_color(std::make_pair(0x6B6B6B, (int) StateColor::Disabled), std::make_pair(*wxBLACK, (int) StateColor::Normal))
|
|
, state_handler(this)
|
|
{
|
|
m_icon = icon;
|
|
wxWindow::SetBackgroundColour(parent->GetBackgroundColour());
|
|
|
|
border_color.append(bd, StateColor::Hovered);
|
|
|
|
background_color.append(BUTTON_BG_COL, StateColor::Disabled);
|
|
background_color.append(BUTTON_PRESS_COL, StateColor::Pressed);
|
|
background_color.append(BUTTON_BG_COL, StateColor::Hovered);
|
|
background_color.append(BUTTON_BG_COL, StateColor::Normal);
|
|
background_color.append(BUTTON_BG_COL, StateColor::Enabled);
|
|
|
|
inner_background_color.append(BUTTON_IN_BG_COL, StateColor::Disabled);
|
|
inner_background_color.append(BUTTON_PRESS_COL, StateColor::Pressed);
|
|
inner_background_color.append(BUTTON_IN_BG_COL, StateColor::Hovered);
|
|
inner_background_color.append(BUTTON_IN_BG_COL, StateColor::Normal);
|
|
inner_background_color.append(BUTTON_IN_BG_COL, StateColor::Enabled);
|
|
|
|
state_handler.attach({ &border_color, &background_color });
|
|
state_handler.update_binds();
|
|
}
|
|
|
|
void AxisCtrlButton::updateParams() {
|
|
r_outer = OUTER_SIZE;
|
|
r_inner = INNER_SIZE;
|
|
r_home = HOME_SIZE;
|
|
r_blank = BLANK_SIZE;
|
|
gap = GAP_SIZE;
|
|
}
|
|
|
|
void AxisCtrlButton::SetMinSize(const wxSize& size)
|
|
{
|
|
wxSize cur_size = GetSize();
|
|
if (size.GetWidth() > 0 && size.GetHeight() > 0) {
|
|
stretch = std::min((double)size.GetWidth() / cur_size.x,(double)size.GetHeight() / cur_size.y);
|
|
minSize = size;
|
|
updateParams();
|
|
}
|
|
else if (size.GetWidth() > 0) {
|
|
stretch = (double)size.GetWidth() / cur_size.x;
|
|
minSize.x = size.x;
|
|
updateParams();
|
|
}
|
|
else if (size.GetHeight() > 0) {
|
|
stretch = (double)size.GetHeight() / cur_size.y;
|
|
minSize.y = size.y;
|
|
updateParams();
|
|
}
|
|
else {
|
|
stretch = 1.0;
|
|
minSize = wxSize(228, 228);
|
|
}
|
|
wxWindow::SetMinSize(minSize);
|
|
center = wxPoint(minSize.x / 2, minSize.y / 2);
|
|
}
|
|
|
|
void AxisCtrlButton::SetTextColor(StateColor const &color)
|
|
{
|
|
text_color = color;
|
|
state_handler.update_binds();
|
|
Refresh();
|
|
}
|
|
|
|
void AxisCtrlButton::SetBorderColor(StateColor const& color)
|
|
{
|
|
border_color = color;
|
|
state_handler.update_binds();
|
|
Refresh();
|
|
}
|
|
|
|
void AxisCtrlButton::SetBackgroundColor(StateColor const& color)
|
|
{
|
|
background_color = color;
|
|
state_handler.update_binds();
|
|
Refresh();
|
|
}
|
|
|
|
void AxisCtrlButton::SetInnerBackgroundColor(StateColor const& color)
|
|
{
|
|
inner_background_color = color;
|
|
state_handler.update_binds();
|
|
Refresh();
|
|
}
|
|
|
|
void AxisCtrlButton::SetBitmap(ScalableBitmap &bmp)
|
|
{
|
|
m_icon = bmp;
|
|
}
|
|
|
|
void AxisCtrlButton::Rescale() {
|
|
Refresh();
|
|
}
|
|
|
|
void AxisCtrlButton::paintEvent(wxPaintEvent& evt)
|
|
{
|
|
// depending on your system you may need to look at double-buffered dcs
|
|
wxPaintDC dc(this);
|
|
wxGCDC gcdc(dc);
|
|
render(gcdc);
|
|
}
|
|
|
|
/*
|
|
* Here we do the actual rendering. I put it in a separate
|
|
* method so that it can work no matter what type of DC
|
|
* (e.g. wxPaintDC or wxClientDC) is used.
|
|
*/
|
|
void AxisCtrlButton::render(wxDC& dc)
|
|
{
|
|
wxGraphicsContext* gc = dc.GetGraphicsContext();
|
|
|
|
int states = state_handler.states();
|
|
wxSize size = GetSize();
|
|
|
|
gc->PushState();
|
|
gc->Translate(center.x, center.y);
|
|
|
|
//draw the outer ring
|
|
wxGraphicsPath outer_path = gc->CreatePath();
|
|
outer_path.AddCircle(0, 0, r_outer);
|
|
outer_path.AddCircle(0, 0, r_inner);
|
|
gc->SetPen(StateColor::darkModeColorFor(BUTTON_BG_COL));
|
|
gc->SetBrush(StateColor::darkModeColorFor(BUTTON_BG_COL));
|
|
gc->DrawPath(outer_path);
|
|
|
|
//draw the inner ring
|
|
wxGraphicsPath inner_path = gc->CreatePath();
|
|
inner_path.AddCircle(0, 0, r_inner);
|
|
inner_path.AddCircle(0, 0, r_blank);
|
|
gc->SetPen(StateColor::darkModeColorFor(BUTTON_IN_BG_COL));
|
|
gc->SetBrush(StateColor::darkModeColorFor(BUTTON_IN_BG_COL));
|
|
gc->DrawPath(inner_path);
|
|
|
|
//draw an arc in corresponding position
|
|
if (current_pos != CurrentPos::UNDEFINED) {
|
|
wxGraphicsPath path = gc->CreatePath();
|
|
if (current_pos < 4) {
|
|
path.AddArc(0, 0, r_outer, (5 - 2 * current_pos) * PI / 4, (7 - 2 * current_pos) * PI / 4, true);
|
|
path.AddArc(0, 0, r_inner, (7 - 2 * current_pos) * PI / 4, (5 - 2 * current_pos) * PI / 4, false);
|
|
path.CloseSubpath();
|
|
gc->SetBrush(wxBrush(background_color.colorForStates(states)));
|
|
}
|
|
else if (current_pos < 8) {
|
|
path.AddArc(0, 0, r_inner, (5 - 2 * current_pos) * PI / 4, (7 - 2 * current_pos) * PI / 4, true);
|
|
path.AddArc(0, 0, r_blank, (7 - 2 * current_pos) * PI / 4, (5 - 2 * current_pos) * PI / 4, false);
|
|
path.CloseSubpath();
|
|
gc->SetBrush(wxBrush(inner_background_color.colorForStates(states)));
|
|
}
|
|
gc->SetPen(wxPen(border_color.colorForStates(states),2));
|
|
gc->DrawPath(path);
|
|
}
|
|
|
|
//draw rectangle gap
|
|
gc->SetPen(blank_bg.colorForStates(StateColor::Normal));
|
|
gc->SetBrush(blank_bg.colorForStates(StateColor::Normal));
|
|
gc->PushState();
|
|
gc->Rotate(-PI / 4);
|
|
gc->DrawRectangle(-sqrt2 * size.x / 2, -sqrt2 * gap / 2, sqrt2 * size.x, sqrt2 * gap);
|
|
gc->Rotate(-PI / 2);
|
|
gc->DrawRectangle(-sqrt2 * size.x / 2, -sqrt2 * gap / 2, sqrt2 * size.x, sqrt2 * gap);
|
|
gc->PopState();
|
|
|
|
// draw the home circle
|
|
wxGraphicsPath home_path = gc->CreatePath();
|
|
home_path.AddCircle(0, 0, r_home);
|
|
home_path.CloseSubpath();
|
|
gc->PushState();
|
|
if (current_pos == 8) {
|
|
gc->SetPen(wxPen(border_color.colorForStates(states), 2));
|
|
gc->SetBrush(wxBrush(background_color.colorForStates(states)));
|
|
} else {
|
|
gc->SetPen(StateColor::darkModeColorFor(BUTTON_BG_COL));
|
|
gc->SetBrush(StateColor::darkModeColorFor(BUTTON_BG_COL));
|
|
}
|
|
gc->DrawPath(home_path);
|
|
|
|
if (m_icon.bmp().IsOk()) {
|
|
gc->DrawBitmap(m_icon.bmp(), -1 * m_icon.GetBmpWidth() / 2, -1 * m_icon.GetBmpHeight() / 2, m_icon.GetBmpWidth(), m_icon.GetBmpHeight());
|
|
}
|
|
gc->PopState();
|
|
|
|
//draw linear border of the arc
|
|
if (current_pos != CurrentPos::UNDEFINED) {
|
|
gc->PushState();
|
|
gc->SetPen(wxPen(border_color.colorForStates(states), 2));
|
|
|
|
if (current_pos == 8) {
|
|
wxGraphicsPath line_path = gc->CreatePath();
|
|
line_path.AddCircle(0, 0, r_home);
|
|
gc->StrokePath(line_path);
|
|
} else {
|
|
wxGraphicsPath line_path1 = gc->CreatePath();
|
|
wxGraphicsPath line_path2 = gc->CreatePath();
|
|
if (current_pos < 4) {
|
|
line_path1.MoveToPoint(r_inner, -sqrt2 * gap / 2);
|
|
line_path1.AddLineToPoint(r_outer, -sqrt2 * gap / 2);
|
|
line_path2.MoveToPoint(-r_inner, -sqrt2 * gap / 2);
|
|
line_path2.AddLineToPoint(-r_outer, -sqrt2 * gap / 2);
|
|
} else if (current_pos < 8) {
|
|
line_path1.MoveToPoint(r_blank, -sqrt2 * gap / 2);
|
|
line_path1.AddLineToPoint(r_inner, -sqrt2 * gap / 2);
|
|
line_path2.MoveToPoint(-r_blank, -sqrt2 * gap / 2);
|
|
line_path2.AddLineToPoint(-r_inner, -sqrt2 * gap / 2);
|
|
}
|
|
gc->Rotate(-(1 + 2 * current_pos) * PI / 4);
|
|
gc->StrokePath(line_path1);
|
|
gc->Rotate(PI / 2);
|
|
gc->StrokePath(line_path2);
|
|
}
|
|
gc->PopState();
|
|
}
|
|
|
|
//draw text
|
|
if (!IsEnabled())
|
|
gc->SetFont(Label::Body_12, text_color.colorForStates(StateColor::Disabled));
|
|
else
|
|
gc->SetFont(Label::Head_12, text_color.colorForStates(states));
|
|
wxDouble w, h;
|
|
gc->GetTextExtent("Y", &w, &h);
|
|
gc->DrawText(wxT("Y"), -w / 2, -r_outer + (r_outer - r_inner) / 2 - h / 2);
|
|
gc->GetTextExtent("-X", &w, &h);
|
|
gc->DrawText(wxT("-X"), -r_outer + (r_outer - r_inner) / 2 - w / 2, - h / 2);
|
|
gc->GetTextExtent("-Y", &w, &h);
|
|
gc->DrawText(wxT("-Y"), -w / 2, r_outer - (r_outer - r_inner) / 2 - h / 2);
|
|
gc->GetTextExtent("X", &w, &h);
|
|
gc->DrawText(wxT("X"), r_outer - (r_outer - r_inner) / 2 - w / 2, -h / 2);
|
|
|
|
gc->SetFont(Label::Body_12, text_num_color);
|
|
|
|
gc->PushState();
|
|
gc->Rotate(PI / 4);
|
|
gc->GetTextExtent("+10", &w, &h);
|
|
gc->DrawText(wxT("+10"), sqrt2 * gap, -r_outer + (r_outer - r_inner) / 2 - h / 2);
|
|
gc->GetTextExtent("+1", &w, &h);
|
|
gc->DrawText(wxT("+1"), sqrt2 * gap, -r_inner + (r_inner - r_blank) / 2 - h / 2);
|
|
gc->GetTextExtent("-1", &w, &h);
|
|
gc->DrawText(wxT("-1"), sqrt2 * gap, r_inner - (r_inner - r_blank) / 2 - h / 2);
|
|
gc->GetTextExtent("-10", &w, &h);
|
|
gc->DrawText(wxT("-10"), sqrt2 * gap, r_outer - (r_outer - r_inner) / 2 - h / 2);
|
|
gc->PopState();
|
|
|
|
|
|
gc->PopState();
|
|
}
|
|
|
|
void AxisCtrlButton::mouseDown(wxMouseEvent& event)
|
|
{
|
|
event.Skip();
|
|
pressedDown = true;
|
|
SetFocus();
|
|
CaptureMouse();
|
|
}
|
|
|
|
void AxisCtrlButton::mouseReleased(wxMouseEvent& event)
|
|
{
|
|
event.Skip();
|
|
if (pressedDown) {
|
|
pressedDown = false;
|
|
ReleaseMouse();
|
|
if (wxRect({ 0, 0 }, GetSize()).Contains(event.GetPosition()))
|
|
sendButtonEvent();
|
|
}
|
|
}
|
|
|
|
void AxisCtrlButton::mouseMoving(wxMouseEvent& event)
|
|
{
|
|
if (pressedDown)
|
|
return;
|
|
wxPoint mouse_pos(event.GetX(), event.GetY());
|
|
wxPoint transformed_mouse_pos = mouse_pos - center;
|
|
double r_temp = transformed_mouse_pos.x * transformed_mouse_pos.x + transformed_mouse_pos.y * transformed_mouse_pos.y;
|
|
if (r_temp > r_outer * r_outer) {
|
|
current_pos = CurrentPos::UNDEFINED;
|
|
}
|
|
else if (r_temp > r_inner * r_inner) {
|
|
if (transformed_mouse_pos.y < transformed_mouse_pos.x - gap && transformed_mouse_pos.y < -transformed_mouse_pos.x - gap)
|
|
{
|
|
current_pos = CurrentPos::OUTER_UP;
|
|
}
|
|
else if (transformed_mouse_pos.y > transformed_mouse_pos.x + gap && transformed_mouse_pos.y < -transformed_mouse_pos.x - gap)
|
|
{
|
|
current_pos = CurrentPos::OUTER_LEFT;
|
|
}
|
|
else if (transformed_mouse_pos.y > transformed_mouse_pos.x + gap && transformed_mouse_pos.y > -transformed_mouse_pos.x + gap)
|
|
{
|
|
current_pos = CurrentPos::OUTER_DOWN;
|
|
}
|
|
else if (transformed_mouse_pos.y < transformed_mouse_pos.x - gap && transformed_mouse_pos.y > -transformed_mouse_pos.x + gap)
|
|
{
|
|
current_pos = CurrentPos::OUTER_RIGHT;
|
|
}
|
|
else {
|
|
current_pos = CurrentPos::UNDEFINED;
|
|
}
|
|
}
|
|
else if (r_temp > r_blank * r_blank) {
|
|
if (transformed_mouse_pos.y < transformed_mouse_pos.x - gap && transformed_mouse_pos.y < -transformed_mouse_pos.x - gap)
|
|
{
|
|
current_pos = CurrentPos::INNER_UP;
|
|
}
|
|
else if (transformed_mouse_pos.y > transformed_mouse_pos.x + gap && transformed_mouse_pos.y < -transformed_mouse_pos.x - gap)
|
|
{
|
|
current_pos = CurrentPos::INNER_LEFT;
|
|
}
|
|
else if (transformed_mouse_pos.y > transformed_mouse_pos.x + gap && transformed_mouse_pos.y > -transformed_mouse_pos.x + gap)
|
|
{
|
|
current_pos = CurrentPos::INNER_DOWN;
|
|
}
|
|
else if (transformed_mouse_pos.y < transformed_mouse_pos.x - gap && transformed_mouse_pos.y > -transformed_mouse_pos.x + gap)
|
|
{
|
|
current_pos = CurrentPos::INNER_RIGHT;
|
|
}
|
|
else {
|
|
current_pos = CurrentPos::UNDEFINED;
|
|
}
|
|
} else if (r_temp <= r_home * r_home) {
|
|
current_pos = INNER_HOME;
|
|
}
|
|
if (last_pos != current_pos) {
|
|
last_pos = current_pos;
|
|
Refresh();
|
|
}
|
|
}
|
|
|
|
void AxisCtrlButton::sendButtonEvent()
|
|
{
|
|
wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
|
|
event.SetEventObject(this);
|
|
event.SetInt(current_pos);
|
|
GetEventHandler()->ProcessEvent(event);
|
|
} |