BambuStudio/slic3r/GUI/DragCanvas.cpp

250 lines
7.4 KiB
C++

#include "DragCanvas.hpp"
#include "wxExtensions.hpp"
#include "GUI_App.hpp"
namespace Slic3r { namespace GUI {
#define CANVAS_WIDTH FromDIP(240)
#define SHAPE_SIZE FromDIP(20)
#define SHAPE_GAP (2 * SHAPE_SIZE)
#define LINE_HEIGHT (SHAPE_SIZE + FromDIP(5))
static const wxColour CANVAS_BORDER_COLOR = wxColour(0xCECECE);
DragCanvas::DragCanvas(wxWindow* parent, const std::vector<std::string>& colors, const std::vector<int>& order)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
, m_drag_mode(DragMode::NONE)
, m_max_shape_pos(wxPoint(0, 0))
{
SetBackgroundColour(*wxWHITE);
m_arrow_bmp = create_scaled_bitmap("plate_settings_arrow", this, 16);
set_shape_list(colors, order);
Bind(wxEVT_PAINT, &DragCanvas::on_paint, this);
Bind(wxEVT_ERASE_BACKGROUND, &DragCanvas::on_erase, this);
Bind(wxEVT_LEFT_DOWN, &DragCanvas::on_mouse, this);
Bind(wxEVT_LEFT_UP, &DragCanvas::on_mouse, this);
Bind(wxEVT_MOTION, &DragCanvas::on_mouse, this);
Bind(wxEVT_ENTER_WINDOW, &DragCanvas::on_mouse, this);
Bind(wxEVT_LEAVE_WINDOW, &DragCanvas::on_mouse, this);
}
DragCanvas::~DragCanvas()
{
for (int i = 0; i < m_dragshape_list.size(); i++) {
delete m_dragshape_list[i];
}
m_dragshape_list.clear();
if (m_drag_image)
delete m_drag_image;
}
void DragCanvas::set_shape_list(const std::vector<std::string>& colors, const std::vector<int>& order)
{
m_dragshape_list.clear();
for (int i = 0; i < order.size(); i++) {
wxBitmap* bmp = get_extruder_color_icon(colors[order[i] - 1], std::to_string(order[i]), SHAPE_SIZE, SHAPE_SIZE);
DragShape* shape = new DragShape(*bmp, order[i]);
m_dragshape_list.push_back(shape);
}
// wrapping lines
for (int i = 0; i < order.size(); i++) {
int shape_pos_x = FromDIP(10) + i * SHAPE_GAP;
int shape_pos_y = FromDIP(5);
while (shape_pos_x + SHAPE_SIZE > CANVAS_WIDTH) {
shape_pos_x -= CANVAS_WIDTH;
shape_pos_y += LINE_HEIGHT;
int row = shape_pos_y / LINE_HEIGHT + 1;
if (row > 1) {
if (row % 2 == 0) {
shape_pos_x += (SHAPE_GAP - SHAPE_SIZE);
}
else {
shape_pos_x -= (SHAPE_GAP - SHAPE_SIZE);
shape_pos_x += SHAPE_GAP;
}
}
}
m_max_shape_pos.x = std::max(m_max_shape_pos.x, shape_pos_x);
m_max_shape_pos.y = std::max(m_max_shape_pos.y, shape_pos_y);
m_dragshape_list[i]->SetPosition(wxPoint(shape_pos_x, shape_pos_y));
}
int rows = m_max_shape_pos.y / LINE_HEIGHT + 1;
SetMinSize(wxSize(CANVAS_WIDTH, LINE_HEIGHT * rows + FromDIP(5)));
}
std::vector<int> DragCanvas::get_shape_list_order()
{
std::vector<int> res;
std::vector<DragShape*> ordered_list = get_ordered_shape_list();
res.reserve(ordered_list.size());
for (auto& item : ordered_list) {
res.push_back(item->get_index());
}
return res;
}
std::vector<DragShape*> DragCanvas::get_ordered_shape_list()
{
std::vector<DragShape*> ordered_list = m_dragshape_list;
std::sort(ordered_list.begin(), ordered_list.end(), [](const DragShape* l, const DragShape* r) {
if (l->GetPosition().y < r->GetPosition().y)
return true;
else if (l->GetPosition().y == r->GetPosition().y) {
return l->GetPosition().x < r->GetPosition().x;
}
else {
return false;
}
});
return ordered_list;
}
void DragCanvas::on_paint(wxPaintEvent& event)
{
wxPaintDC dc(this);
for (int i = 0; i < m_dragshape_list.size(); i++) {
m_dragshape_list[i]->paint(dc, m_dragshape_list[i] == m_slot_shape);
auto arrow_pos = m_dragshape_list[i]->GetPosition() - wxSize(SHAPE_GAP - SHAPE_SIZE, 0);
if (arrow_pos.x < 0) {
arrow_pos.x = m_max_shape_pos.x;
arrow_pos.y -= LINE_HEIGHT;
}
arrow_pos += wxSize((SHAPE_GAP - SHAPE_SIZE - m_arrow_bmp.GetWidth() / dc.GetContentScaleFactor()) / 2, (SHAPE_SIZE - m_arrow_bmp.GetHeight() / dc.GetContentScaleFactor()) / 2);
dc.DrawBitmap(m_arrow_bmp, arrow_pos);
}
}
void DragCanvas::on_erase(wxEraseEvent& event)
{
wxSize size = GetSize();
if (event.GetDC())
{
auto& dc = *(event.GetDC());
dc.SetPen(CANVAS_BORDER_COLOR);
dc.SetBrush(*wxWHITE_BRUSH);
dc.DrawRectangle({ 0,0 }, size);
}
else
{
wxClientDC dc(this);
dc.SetPen(CANVAS_BORDER_COLOR);
dc.SetBrush(*wxWHITE_BRUSH);
dc.DrawRectangle({ 0,0 }, size);
}
}
void DragCanvas::on_mouse(wxMouseEvent& event)
{
if (event.LeftDown())
{
DragShape* shape = find_shape(event.GetPosition());
if (shape)
{
m_drag_mode = DragMode::DRAGGING;
m_drag_start_pos = event.GetPosition();
m_dragging_shape = shape;
if (m_drag_image) {
delete m_drag_image;
m_drag_image = nullptr;
}
m_drag_image = new wxDragImage(m_dragging_shape->GetBitmap());
wxPoint offset = m_drag_start_pos - m_dragging_shape->GetPosition();
bool success = m_drag_image->BeginDrag(offset, this);
if (!success)
{
delete m_drag_image;
m_drag_image = nullptr;
m_drag_mode = DragMode::NONE;
}
}
}
else if (event.Dragging() && m_drag_mode == DragMode::DRAGGING)
{
DragShape* shape = find_shape(event.GetPosition());
if (shape) {
if (shape != m_dragging_shape) {
m_slot_shape = shape;
Refresh();
Update();
}
}
else {
if (m_slot_shape) {
m_slot_shape = nullptr;
Refresh();
Update();
}
}
m_drag_image->Move(event.GetPosition());
m_drag_image->Show();
}
else if (event.LeftUp() && m_drag_mode != DragMode::NONE)
{
m_drag_mode = DragMode::NONE;
if (m_drag_image) {
m_drag_image->Hide();
m_drag_image->EndDrag();
// swap position
if (m_slot_shape && m_dragging_shape) {
auto highlighted_pos = m_slot_shape->GetPosition();
m_slot_shape->SetPosition(m_dragging_shape->GetPosition());
m_dragging_shape->SetPosition(highlighted_pos);
m_slot_shape = nullptr;
m_dragging_shape = nullptr;
}
}
Refresh();
Update();
}
}
DragShape* DragCanvas::find_shape(const wxPoint& pt) const
{
for (auto& shape : m_dragshape_list) {
if (shape->hit_test(pt))
return shape;
}
return nullptr;
}
DragShape::DragShape(const wxBitmap& bitmap, int index)
: m_bitmap(bitmap)
, m_pos(wxPoint(0,0))
, m_index(index)
{
}
bool DragShape::hit_test(const wxPoint& pt) const
{
wxRect rect(wxRect(m_pos.x, m_pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight()));
return rect.Contains(pt.x, pt.y);
}
void DragShape::paint(wxDC& dc, bool highlight)
{
dc.DrawBitmap(m_bitmap, m_pos);
if (highlight)
{
dc.SetPen(*wxWHITE_PEN);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(m_pos.x, m_pos.y, m_bitmap.GetWidth(), m_bitmap.GetHeight());
}
}
}}