BambuStudio/slic3r/GUI/Widgets/StaticBox.cpp

222 lines
6.2 KiB
C++

#include "StaticBox.hpp"
#include "../GUI.hpp"
#include <wx/dcclient.h>
#include <wx/dcgraph.h>
BEGIN_EVENT_TABLE(StaticBox, wxWindow)
// catch paint events
//EVT_ERASE_BACKGROUND(StaticBox::eraseEvent)
EVT_PAINT(StaticBox::paintEvent)
END_EVENT_TABLE()
/*
* Called by the system of by wxWidgets when the panel needs
* to be redrawn. You can also trigger this call by
* calling Refresh()/Update().
*/
StaticBox::StaticBox()
: state_handler(this)
, radius(8)
{
border_color = StateColor(
std::make_pair(0xF0F0F1, (int) StateColor::Disabled),
std::make_pair(0x303A3C, (int) StateColor::Normal));
}
StaticBox::StaticBox(wxWindow* parent,
wxWindowID id,
const wxPoint & pos,
const wxSize & size, long style)
: StaticBox()
{
Create(parent, id, pos, size, style);
}
bool StaticBox::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)
{
if (style & wxBORDER_NONE)
border_width = 0;
wxWindow::Create(parent, id, pos, size, style);
state_handler.attach({&border_color, &background_color, &background_color2});
state_handler.update_binds();
SetBackgroundColour(GetParentBackgroundColor(parent));
return true;
}
void StaticBox::SetCornerRadius(double radius)
{
this->radius = radius;
Refresh();
}
void StaticBox::SetBorderWidth(int width)
{
border_width = width;
Refresh();
}
void StaticBox::SetBorderColor(StateColor const &color)
{
border_color = color;
state_handler.update_binds();
Refresh();
}
void StaticBox::SetBorderColorNormal(wxColor const &color)
{
border_color.setColorForStates(color, 0);
Refresh();
}
void StaticBox::SetBackgroundColor(StateColor const &color)
{
background_color = color;
state_handler.update_binds();
Refresh();
}
void StaticBox::SetBackgroundColorNormal(wxColor const &color)
{
background_color.setColorForStates(color, 0);
Refresh();
}
void StaticBox::SetBackgroundColor2(StateColor const &color)
{
background_color2 = color;
state_handler.update_binds();
Refresh();
}
wxColor StaticBox::GetParentBackgroundColor(wxWindow* parent)
{
if (auto box = dynamic_cast<StaticBox*>(parent)) {
if (box->background_color.count() > 0) {
if (box->background_color2.count() == 0)
return box->background_color.defaultColor();
auto s = box->background_color.defaultColor();
auto e = box->background_color2.defaultColor();
int r = (s.Red() + e.Red()) / 2;
int g = (s.Green() + e.Green()) / 2;
int b = (s.Blue() + e.Blue()) / 2;
return wxColor(r, g, b);
}
}
if (parent)
return parent->GetBackgroundColour();
return *wxWHITE;
}
void StaticBox::eraseEvent(wxEraseEvent& evt)
{
// for transparent background, but not work
#ifdef __WXMSW__
wxDC *dc = evt.GetDC();
wxSize size = GetSize();
wxClientDC dc2(GetParent());
dc->Blit({0, 0}, size, &dc2, GetPosition());
#endif
}
void StaticBox::paintEvent(wxPaintEvent& evt)
{
// depending on your system you may need to look at double-buffered dcs
wxPaintDC dc(this);
render(dc);
}
/*
* 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 StaticBox::render(wxDC& dc)
{
#ifdef __WXMSW__
if (radius == 0) {
doRender(dc);
return;
}
wxSize size = GetSize();
if (size.x <= 0 || size.y <= 0)
return;
wxMemoryDC memdc(&dc);
if (!memdc.IsOk()) {
doRender(dc);
return;
}
wxBitmap bmp(size.x, size.y);
memdc.SelectObject(bmp);
//memdc.Blit({0, 0}, size, &dc, {0, 0});
memdc.SetBackground(wxBrush(GetBackgroundColour()));
memdc.Clear();
{
wxGCDC dc2(memdc);
doRender(dc2);
}
memdc.SelectObject(wxNullBitmap);
dc.DrawBitmap(bmp, 0, 0);
#else
doRender(dc);
#endif
}
void StaticBox::doRender(wxDC& dc)
{
wxSize size = GetSize();
int states = state_handler.states();
if (background_color2.count() == 0) {
if ((border_width && border_color.count() > 0) || background_color.count() > 0) {
wxRect rc(0, 0, size.x, size.y);
if (border_width && border_color.count() > 0) {
if (dc.GetContentScaleFactor() == 1.0) {
int d = floor(border_width / 2.0);
int d2 = floor(border_width - 1);
rc.x += d;
rc.width -= d2;
rc.y += d;
rc.height -= d2;
} else {
int d = 1;
rc.x += d;
rc.width -= d;
rc.y += d;
rc.height -= d;
}
dc.SetPen(wxPen(border_color.colorForStates(states), border_width));
} else {
dc.SetPen(wxPen(background_color.colorForStates(states)));
}
if (background_color.count() > 0)
dc.SetBrush(wxBrush(background_color.colorForStates(states)));
else
dc.SetBrush(wxBrush(GetBackgroundColour()));
if (radius == 0) {
dc.DrawRectangle(rc);
}
else {
dc.DrawRoundedRectangle(rc, radius - border_width);
}
}
}
else {
wxColor start = background_color.colorForStates(states);
wxColor stop = background_color2.colorForStates(states);
int r = start.Red(), g = start.Green(), b = start.Blue();
int dr = (int) stop.Red() - r, dg = (int) stop.Green() - g, db = (int) stop.Blue() - b;
int lr = 0, lg = 0, lb = 0;
for (int y = 0; y < size.y; ++y) {
dc.SetPen(wxPen(wxColor(r, g, b)));
dc.DrawLine(0, y, size.x, y);
lr += dr; while (lr >= size.y) { ++r, lr -= size.y; } while (lr <= -size.y) { --r, lr += size.y; }
lg += dg; while (lg >= size.y) { ++g, lg -= size.y; } while (lg <= -size.y) { --g, lg += size.y; }
lb += db; while (lb >= size.y) { ++b, lb -= size.y; } while (lb <= -size.y) { --b, lb += size.y; }
}
}
}