Calibratioon
BIN
resources/calib/PressureAdvance/pressure_advance_test.stl
Normal file
BIN
resources/calib/PressureAdvance/tower_with_seam.stl
Normal file
BIN
resources/calib/filament_flow/flowrate-test-pass1.3mf
Normal file
BIN
resources/calib/filament_flow/flowrate-test-pass2.3mf
Normal file
4
resources/icons/check_half.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1" y="1" width="16" height="16" rx="1" fill="#009688"/>
|
||||
<path d="M4 9L14 9" stroke="white" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 228 B |
4
resources/icons/check_half_disabled.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1" y="1" width="16" height="16" rx="1" fill="#CECECE"/>
|
||||
<line x1="4.37881" y1="8.93516" x2="13.6213" y2="8.93515" stroke="white" stroke-width="1.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 285 B |
4
resources/icons/check_half_focused.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1" y="1" width="16" height="16" rx="1" fill="#4db6ac"/>
|
||||
<path d="M4 9L14 9" stroke="white" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 232 B |
3
resources/icons/check_off.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1.5" y="1.5" width="15" height="15" rx="0.5" stroke="#ACACAC"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 176 B |
3
resources/icons/check_off_disabled.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1.5" y="1.5" width="15" height="15" rx="0.5" fill="#CECECE" stroke="#ACACAC"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 191 B |
3
resources/icons/check_off_focused.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1.5" y="1.5" width="15" height="15" rx="0.5" stroke="#009688"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 176 B |
4
resources/icons/check_on.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1" y="1" width="16" height="16" rx="1" fill="#009688"/>
|
||||
<path d="M4.35537 8.5374L8.30284 11.9361C8.71855 12.294 9.34501 12.2502 9.70687 11.838L14.8175 6.01521" stroke="white" stroke-width="1.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 331 B |
4
resources/icons/check_on_disabled.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1" y="1" width="16" height="16" rx="1" fill="#CECECE"/>
|
||||
<path d="M4.35537 8.5374L8.30284 11.9361C8.71855 12.294 9.34501 12.2502 9.70687 11.838L14.8175 6.01521" stroke="white" stroke-width="1.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 331 B |
4
resources/icons/check_on_focused.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1" y="1" width="16" height="16" rx="1" fill="#4db6ac"/>
|
||||
<path d="M4.35537 8.5374L8.30284 11.9361C8.71855 12.294 9.34501 12.2502 9.70687 11.838L14.8175 6.01521" stroke="white" stroke-width="1.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 331 B |
4
resources/icons/checked.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 8.9375L6.45062 11.6772C6.67263 11.8535 6.99663 11.8101 7.16447 11.5817L12 5" stroke="white" stroke-linecap="round"/>
|
||||
<path d="M3 8.9375L6.45062 11.6772C6.67263 11.8535 6.99663 11.8101 7.16447 11.5817L12 5" stroke="white" stroke-opacity="0.2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 382 B |
@@ -35,6 +35,8 @@ set(SLIC3R_SOURCES
|
||||
BuildVolume.cpp
|
||||
BuildVolume.hpp
|
||||
BoostAdapter.hpp
|
||||
calib.cpp
|
||||
calib.hpp
|
||||
clipper.cpp
|
||||
clipper.hpp
|
||||
ClipperUtils.cpp
|
||||
|
||||
@@ -162,6 +162,25 @@ std::string GCodeWriter::set_bed_temperature(unsigned int temperature, bool wait
|
||||
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
|
||||
//B34
|
||||
std::string GCodeWriter::set_pressure_advance(double pa) const
|
||||
{
|
||||
std::ostringstream gcode;
|
||||
if (pa < 0)
|
||||
return gcode.str();
|
||||
else{
|
||||
if (FLAVOR_IS(gcfKlipper))
|
||||
gcode << "SET_PRESSURE_ADVANCE ADVANCE=" << std::setprecision(4) << pa << "; Override pressure advance value\n";
|
||||
else if(FLAVOR_IS(gcfRepRapFirmware))
|
||||
gcode << ("M572 D0 S") << std::setprecision(4) << pa << "; Override pressure advance value\n";
|
||||
else
|
||||
gcode << "M900 K" <<std::setprecision(4)<< pa << "; Override pressure advance value\n";
|
||||
}
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
//B24
|
||||
std::string GCodeWriter::set_volume_temperature(unsigned int temperature, bool wait)
|
||||
{
|
||||
|
||||
@@ -45,6 +45,8 @@ public:
|
||||
std::string postamble() const;
|
||||
std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const;
|
||||
std::string set_bed_temperature(unsigned int temperature, bool wait = false);
|
||||
//B34
|
||||
std::string set_pressure_advance(double pa) const;
|
||||
//B24
|
||||
std::string set_volume_temperature(unsigned int temperature, bool wait = false);
|
||||
std::string set_print_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Print, acceleration); }
|
||||
|
||||
919
src/libslic3r/calib.cpp
Normal file
@@ -0,0 +1,919 @@
|
||||
#include "calib.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "Model.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Calculate the optimal Pressure Advance speed
|
||||
float CalibPressureAdvance::find_optimal_PA_speed(const DynamicPrintConfig &config, double line_width, double layer_height,
|
||||
int filament_idx) {
|
||||
const double general_suggested_min_speed = 100.0;
|
||||
double filament_max_volumetric_speed = config.option<ConfigOptionFloats>("filament_max_volumetric_speed")->get_at(0);
|
||||
Flow pattern_line = Flow(line_width, layer_height, config.option<ConfigOptionFloats>("nozzle_diameter")->get_at(0));
|
||||
auto pa_speed = std::min(std::max(general_suggested_min_speed,config.option<ConfigOptionFloat>("outer_wall_speed")->value), filament_max_volumetric_speed / pattern_line.mm3_per_mm());
|
||||
|
||||
return std::floor(pa_speed);
|
||||
}
|
||||
|
||||
std::string CalibPressureAdvance::move_to(Vec2d pt, GCodeWriter& writer, std::string comment)
|
||||
{
|
||||
std::stringstream gcode;
|
||||
|
||||
gcode << writer.retract();
|
||||
gcode << writer.travel_to_xy(pt, comment);
|
||||
gcode << writer.unretract();
|
||||
|
||||
m_last_pos = Vec3d(pt.x(), pt.y(), 0);
|
||||
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
double CalibPressureAdvance::e_per_mm(
|
||||
double line_width,
|
||||
double layer_height,
|
||||
float nozzle_diameter,
|
||||
float filament_diameter,
|
||||
float print_flow_ratio
|
||||
) const
|
||||
{
|
||||
const Flow line_flow = Flow(line_width, layer_height, nozzle_diameter);
|
||||
const double filament_area = M_PI * std::pow(filament_diameter / 2, 2);
|
||||
|
||||
return line_flow.mm3_per_mm() / filament_area * print_flow_ratio;
|
||||
}
|
||||
|
||||
std::string CalibPressureAdvance::convert_number_to_string(double num) const
|
||||
{
|
||||
auto sNumber = std::to_string(num);
|
||||
sNumber.erase(sNumber.find_last_not_of('0') + 1, std::string::npos);
|
||||
sNumber.erase(sNumber.find_last_not_of('.') + 1, std::string::npos);
|
||||
|
||||
return sNumber;
|
||||
}
|
||||
|
||||
std::string CalibPressureAdvance::draw_digit(
|
||||
double startx,
|
||||
double starty,
|
||||
char c,
|
||||
CalibPressureAdvance::DrawDigitMode mode,
|
||||
double line_width,
|
||||
double e_per_mm,
|
||||
GCodeWriter& writer
|
||||
)
|
||||
{
|
||||
const double len = m_digit_segment_len;
|
||||
const double gap = line_width / 2.0;
|
||||
|
||||
const auto dE = e_per_mm * len;
|
||||
const auto two_dE = dE * 2;
|
||||
|
||||
Vec2d p0, p1, p2, p3, p4, p5;
|
||||
Vec2d p0_5, p4_5;
|
||||
Vec2d gap_p0_toward_p3, gap_p2_toward_p3;
|
||||
Vec2d dot_direction;
|
||||
|
||||
if (mode == CalibPressureAdvance::DrawDigitMode::Bottom_To_Top) {
|
||||
// 1-------2-------5
|
||||
// | | |
|
||||
// | | |
|
||||
// 0-------3-------4
|
||||
p0 = Vec2d(startx, starty);
|
||||
p0_5 = Vec2d(startx, starty + len / 2);
|
||||
p1 = Vec2d(startx, starty + len);
|
||||
p2 = Vec2d(startx + len, starty + len);
|
||||
p3 = Vec2d(startx + len, starty);
|
||||
p4 = Vec2d(startx + len * 2, starty);
|
||||
p4_5 = Vec2d(startx + len * 2, starty + len / 2);
|
||||
p5 = Vec2d(startx + len * 2, starty + len);
|
||||
|
||||
gap_p0_toward_p3 = p0 + Vec2d(gap, 0);
|
||||
gap_p2_toward_p3 = p2 + Vec2d(0, gap);
|
||||
|
||||
dot_direction = Vec2d(-len / 2, 0);
|
||||
} else {
|
||||
// 0-------1
|
||||
// | |
|
||||
// 3-------2
|
||||
// | |
|
||||
// 4-------5
|
||||
p0 = Vec2d(startx, starty);
|
||||
p0_5 = Vec2d(startx + len / 2, starty);
|
||||
p1 = Vec2d(startx + len, starty);
|
||||
p2 = Vec2d(startx + len, starty - len);
|
||||
p3 = Vec2d(startx, starty - len);
|
||||
p4 = Vec2d(startx, starty - len * 2);
|
||||
p4_5 = Vec2d(startx + len / 2, starty - len * 2);
|
||||
p5 = Vec2d(startx + len, starty - len * 2);
|
||||
|
||||
gap_p0_toward_p3 = p0 - Vec2d(0, gap);
|
||||
gap_p2_toward_p3 = p2 - Vec2d(gap, 0);
|
||||
|
||||
dot_direction = Vec2d(0, len / 2);
|
||||
}
|
||||
|
||||
std::stringstream gcode;
|
||||
|
||||
switch (c) {
|
||||
case '0':
|
||||
gcode << move_to(p0, writer, "Glyph: 0");
|
||||
gcode << writer.extrude_to_xy(p1, dE);
|
||||
gcode << writer.extrude_to_xy(p5, two_dE);
|
||||
gcode << writer.extrude_to_xy(p4, dE);
|
||||
gcode << writer.extrude_to_xy(gap_p0_toward_p3, two_dE);
|
||||
break;
|
||||
case '1':
|
||||
gcode << move_to(p0_5, writer, "Glyph: 1");
|
||||
gcode << writer.extrude_to_xy(p4_5, two_dE);
|
||||
break;
|
||||
case '2':
|
||||
gcode << move_to(p0, writer, "Glyph: 2");
|
||||
gcode << writer.extrude_to_xy(p1, dE);
|
||||
gcode << writer.extrude_to_xy(p2, dE);
|
||||
gcode << writer.extrude_to_xy(p3, dE);
|
||||
gcode << writer.extrude_to_xy(p4, dE);
|
||||
gcode << writer.extrude_to_xy(p5, dE);
|
||||
break;
|
||||
case '3':
|
||||
gcode << move_to(p0, writer, "Glyph: 3");
|
||||
gcode << writer.extrude_to_xy(p1, dE);
|
||||
gcode << writer.extrude_to_xy(p5, two_dE);
|
||||
gcode << writer.extrude_to_xy(p4, dE);
|
||||
gcode << move_to(gap_p2_toward_p3, writer);
|
||||
gcode << writer.extrude_to_xy(p3, dE);
|
||||
break;
|
||||
case '4':
|
||||
gcode << move_to(p0, writer, "Glyph: 4");
|
||||
gcode << writer.extrude_to_xy(p3, dE);
|
||||
gcode << writer.extrude_to_xy(p2, dE);
|
||||
gcode << move_to(p1, writer);
|
||||
gcode << writer.extrude_to_xy(p5, two_dE);
|
||||
break;
|
||||
case '5':
|
||||
gcode << move_to(p1, writer, "Glyph: 5");
|
||||
gcode << writer.extrude_to_xy(p0, dE);
|
||||
gcode << writer.extrude_to_xy(p3, dE);
|
||||
gcode << writer.extrude_to_xy(p2, dE);
|
||||
gcode << writer.extrude_to_xy(p5, dE);
|
||||
gcode << writer.extrude_to_xy(p4, dE);
|
||||
break;
|
||||
case '6':
|
||||
gcode << move_to(p1, writer, "Glyph: 6");
|
||||
gcode << writer.extrude_to_xy(p0, dE);
|
||||
gcode << writer.extrude_to_xy(p4, two_dE);
|
||||
gcode << writer.extrude_to_xy(p5, dE);
|
||||
gcode << writer.extrude_to_xy(p2, dE);
|
||||
gcode << writer.extrude_to_xy(p3, dE);
|
||||
break;
|
||||
case '7':
|
||||
gcode << move_to(p0, writer, "Glyph: 7");
|
||||
gcode << writer.extrude_to_xy(p1, dE);
|
||||
gcode << writer.extrude_to_xy(p5, two_dE);
|
||||
break;
|
||||
case '8':
|
||||
gcode << move_to(p2, writer, "Glyph: 8");
|
||||
gcode << writer.extrude_to_xy(p3, dE);
|
||||
gcode << writer.extrude_to_xy(p4, dE);
|
||||
gcode << writer.extrude_to_xy(p5, dE);
|
||||
gcode << writer.extrude_to_xy(p1, two_dE);
|
||||
gcode << writer.extrude_to_xy(p0, dE);
|
||||
gcode << writer.extrude_to_xy(p3, dE);
|
||||
break;
|
||||
case '9':
|
||||
gcode << move_to(p5, writer, "Glyph: 9");
|
||||
gcode << writer.extrude_to_xy(p1, two_dE);
|
||||
gcode << writer.extrude_to_xy(p0, dE);
|
||||
gcode << writer.extrude_to_xy(p3, dE);
|
||||
gcode << writer.extrude_to_xy(p2, dE);
|
||||
break;
|
||||
case '.':
|
||||
gcode << move_to(p4_5, writer, "Glyph: .");
|
||||
gcode << writer.extrude_to_xy(p4_5 + dot_direction, dE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
std::string CalibPressureAdvance::draw_number(
|
||||
double startx,
|
||||
double starty,
|
||||
double value,
|
||||
CalibPressureAdvance::DrawDigitMode mode,
|
||||
double line_width,
|
||||
double e_per_mm,
|
||||
double speed,
|
||||
GCodeWriter& writer
|
||||
)
|
||||
{
|
||||
auto sNumber = convert_number_to_string(value);
|
||||
std::stringstream gcode;
|
||||
gcode << writer.set_speed(speed);
|
||||
|
||||
for (std::string::size_type i = 0; i < sNumber.length(); ++i) {
|
||||
if (i > m_max_number_len) {
|
||||
break;
|
||||
}
|
||||
switch (mode) {
|
||||
case DrawDigitMode::Bottom_To_Top:
|
||||
gcode << draw_digit(
|
||||
startx,
|
||||
starty + i * number_spacing(),
|
||||
sNumber[i],
|
||||
mode,
|
||||
line_width,
|
||||
e_per_mm,
|
||||
writer
|
||||
);
|
||||
break;
|
||||
default:
|
||||
gcode << draw_digit(
|
||||
startx + i * number_spacing(),
|
||||
starty,
|
||||
sNumber[i],
|
||||
mode,
|
||||
line_width,
|
||||
e_per_mm,
|
||||
writer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
std::string CalibPressureAdvanceLine::generate_test(double start_pa /*= 0*/, double step_pa /*= 0.002*/, int count /*= 10*/)
|
||||
{
|
||||
BoundingBoxf bed_ext = get_extents(mp_gcodegen->config().bed_shape.values);
|
||||
if (is_delta()) {
|
||||
CalibPressureAdvanceLine::delta_scale_bed_ext(bed_ext);
|
||||
}
|
||||
|
||||
auto bed_sizes = mp_gcodegen->config().bed_shape.values;
|
||||
const auto &w = bed_ext.size().x();
|
||||
const auto &h = bed_ext.size().y();
|
||||
count = std::min(count, int((h - 10) / m_space_y));
|
||||
|
||||
m_length_long = 40 + std::min(w - 120.0, 0.0);
|
||||
|
||||
auto startx = (w - m_length_short * 2 - m_length_long - 20) / 2;
|
||||
auto starty = (h - count * m_space_y) / 2;
|
||||
if (is_delta()) {
|
||||
CalibPressureAdvanceLine::delta_modify_start(startx, starty, count);
|
||||
}
|
||||
|
||||
return print_pa_lines(startx, starty, start_pa, step_pa, count);
|
||||
}
|
||||
|
||||
bool CalibPressureAdvanceLine::is_delta() const
|
||||
{
|
||||
return mp_gcodegen->config().bed_shape.values.size() > 4;
|
||||
}
|
||||
|
||||
std::string CalibPressureAdvanceLine::print_pa_lines(double start_x, double start_y, double start_pa, double step_pa, int num)
|
||||
{
|
||||
auto& writer = mp_gcodegen->writer();
|
||||
const auto& config = mp_gcodegen->config();
|
||||
|
||||
const auto filament_diameter = config.filament_diameter.get_at(0);
|
||||
const auto print_flow_ratio = 1;
|
||||
|
||||
const double e_per_mm = CalibPressureAdvance::e_per_mm(
|
||||
m_line_width,
|
||||
m_height_layer,
|
||||
m_nozzle_diameter,
|
||||
filament_diameter,
|
||||
print_flow_ratio
|
||||
);
|
||||
const double thin_e_per_mm = CalibPressureAdvance::e_per_mm(
|
||||
m_thin_line_width,
|
||||
m_height_layer,
|
||||
m_nozzle_diameter,
|
||||
filament_diameter,
|
||||
print_flow_ratio
|
||||
);
|
||||
const double number_e_per_mm = CalibPressureAdvance::e_per_mm(
|
||||
m_number_line_width,
|
||||
m_height_layer,
|
||||
m_nozzle_diameter,
|
||||
filament_diameter,
|
||||
print_flow_ratio
|
||||
);
|
||||
|
||||
const double fast = CalibPressureAdvance::speed_adjust(m_fast_speed);
|
||||
const double slow = CalibPressureAdvance::speed_adjust(m_slow_speed);
|
||||
std::stringstream gcode;
|
||||
gcode << mp_gcodegen->writer().travel_to_z(m_height_layer);
|
||||
double y_pos = start_y;
|
||||
|
||||
// prime line
|
||||
auto prime_x = start_x - 2;
|
||||
gcode << move_to(Vec2d(prime_x, y_pos + (num - 4) * m_space_y), writer);
|
||||
gcode << writer.set_speed(slow);
|
||||
gcode << writer.extrude_to_xy(Vec2d(prime_x, y_pos + 3 * m_space_y), e_per_mm * m_space_y * num * 1.1);
|
||||
|
||||
for (int i = 0; i < num; ++i) {
|
||||
gcode << writer.set_pressure_advance(start_pa + i * step_pa);
|
||||
gcode << move_to(Vec2d(start_x, y_pos + i * m_space_y), writer);
|
||||
gcode << writer.set_speed(slow);
|
||||
gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short, y_pos + i * m_space_y), e_per_mm * m_length_short);
|
||||
gcode << writer.set_speed(fast);
|
||||
gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short + m_length_long, y_pos + i * m_space_y), e_per_mm * m_length_long);
|
||||
gcode << writer.set_speed(slow);
|
||||
gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short + m_length_long + m_length_short, y_pos + i * m_space_y), e_per_mm * m_length_short);
|
||||
}
|
||||
gcode << writer.set_pressure_advance(0.0);
|
||||
|
||||
if (m_draw_numbers) {
|
||||
// draw indicator lines
|
||||
gcode << writer.set_speed(fast);
|
||||
gcode << move_to(Vec2d(start_x + m_length_short, y_pos + (num - 1) * m_space_y + 2), writer);
|
||||
gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short, y_pos + (num - 1) * m_space_y + 7), thin_e_per_mm * 7);
|
||||
gcode << move_to(Vec2d(start_x + m_length_short + m_length_long, y_pos + (num - 1) * m_space_y + 7), writer);
|
||||
gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short + m_length_long, y_pos + (num - 1) * m_space_y + 2), thin_e_per_mm * 7);
|
||||
|
||||
for (int i = 0; i < num; i += 2) {
|
||||
gcode << draw_number(
|
||||
start_x + m_length_short + m_length_long + m_length_short + 3,
|
||||
y_pos + i * m_space_y + m_space_y / 2,
|
||||
start_pa + i * step_pa,
|
||||
m_draw_digit_mode,
|
||||
m_number_line_width,
|
||||
number_e_per_mm,
|
||||
3600,
|
||||
writer
|
||||
);
|
||||
}
|
||||
}
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
void CalibPressureAdvanceLine::delta_modify_start(double& startx, double& starty, int count)
|
||||
{
|
||||
startx = -startx;
|
||||
starty = -(count * m_space_y) / 2;
|
||||
}
|
||||
|
||||
CalibPressureAdvancePattern::CalibPressureAdvancePattern(
|
||||
const Calib_Params& params,
|
||||
const DynamicPrintConfig& config,
|
||||
bool is_bbl_machine,
|
||||
Model& model,
|
||||
const Vec3d& origin
|
||||
) :
|
||||
m_params(params)
|
||||
{
|
||||
this->m_draw_digit_mode = DrawDigitMode::Bottom_To_Top;
|
||||
|
||||
refresh_setup(config, is_bbl_machine, model, origin);
|
||||
};
|
||||
|
||||
void CalibPressureAdvancePattern::generate_custom_gcodes(
|
||||
const DynamicPrintConfig& config,
|
||||
bool is_bbl_machine,
|
||||
Model& model,
|
||||
const Vec3d& origin
|
||||
)
|
||||
{
|
||||
std::stringstream gcode;
|
||||
gcode << "; start pressure advance pattern for layer\n";
|
||||
|
||||
refresh_setup(config, is_bbl_machine, model, origin);
|
||||
|
||||
gcode << move_to(Vec2d(m_starting_point.x(), m_starting_point.y()), m_writer, "Move to start XY position");
|
||||
gcode << m_writer.travel_to_z(height_first_layer(), "Move to start Z position");
|
||||
gcode << m_writer.set_pressure_advance(m_params.start);
|
||||
|
||||
const DrawBoxOptArgs default_box_opt_args(*this);
|
||||
|
||||
// create anchoring frame
|
||||
gcode << draw_box(
|
||||
m_starting_point.x(),
|
||||
m_starting_point.y(),
|
||||
print_size_x(),
|
||||
frame_size_y(),
|
||||
default_box_opt_args
|
||||
);
|
||||
|
||||
// create tab for numbers
|
||||
DrawBoxOptArgs draw_box_opt_args = default_box_opt_args;
|
||||
draw_box_opt_args.is_filled = true;
|
||||
draw_box_opt_args.num_perimeters = wall_count();
|
||||
gcode << draw_box(
|
||||
m_starting_point.x(),
|
||||
m_starting_point.y() + frame_size_y() + line_spacing_first_layer(),
|
||||
glyph_tab_max_x() - m_starting_point.x(),
|
||||
max_numbering_height() + line_spacing_first_layer() + m_glyph_padding_vertical * 2,
|
||||
draw_box_opt_args
|
||||
);
|
||||
|
||||
std::vector<CustomGCode::Item> gcode_items;
|
||||
const DrawLineOptArgs default_line_opt_args(*this);
|
||||
const int num_patterns = get_num_patterns(); // "cache" for use in loops
|
||||
|
||||
// draw pressure advance pattern
|
||||
for (int i = 0; i < m_num_layers; ++i) {
|
||||
if (i > 0) {
|
||||
gcode << "; end pressure advance pattern for layer\n";
|
||||
CustomGCode::Item item;
|
||||
item.print_z = height_first_layer() + (i - 1) * height_layer();
|
||||
item.type = CustomGCode::Type::Custom;
|
||||
item.extra = gcode.str();
|
||||
gcode_items.push_back(item);
|
||||
|
||||
gcode = std::stringstream(); // reset for next layer contents
|
||||
gcode << "; start pressure advance pattern for layer\n";
|
||||
|
||||
const double layer_height = height_first_layer() + (i * height_layer());
|
||||
gcode << m_writer.travel_to_z(layer_height, "Move to layer height");
|
||||
}
|
||||
|
||||
// line numbering
|
||||
if (i == 1) {
|
||||
gcode << m_writer.set_pressure_advance(m_params.start);
|
||||
|
||||
double number_e_per_mm = e_per_mm(
|
||||
line_width(),
|
||||
height_layer(),
|
||||
m_config.option<ConfigOptionFloats>("nozzle_diameter")->get_at(0),
|
||||
m_config.option<ConfigOptionFloats>("filament_diameter")->get_at(0),
|
||||
m_config.option<ConfigOptionFloats>("filament_flow_ratio")->get_at(0)
|
||||
);
|
||||
|
||||
// glyph on every other line
|
||||
for (int j = 0; j < num_patterns; j += 2) {
|
||||
gcode << draw_number(
|
||||
glyph_start_x(j),
|
||||
m_starting_point.y() + frame_size_y() + m_glyph_padding_vertical + line_width(),
|
||||
m_params.start + (j * m_params.step),
|
||||
m_draw_digit_mode,
|
||||
line_width(),
|
||||
number_e_per_mm,
|
||||
speed_first_layer(),
|
||||
m_writer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DrawLineOptArgs draw_line_opt_args = default_line_opt_args;
|
||||
|
||||
double to_x = m_starting_point.x() + pattern_shift();
|
||||
double to_y = m_starting_point.y();
|
||||
double side_length = m_wall_side_length;
|
||||
|
||||
// shrink first layer to fit inside frame
|
||||
if (i == 0) {
|
||||
double shrink =
|
||||
(
|
||||
line_spacing_first_layer() * (wall_count() - 1) +
|
||||
(line_width_first_layer() * (1 - m_encroachment))
|
||||
) / std::sin(to_radians(m_corner_angle) / 2)
|
||||
;
|
||||
side_length = m_wall_side_length - shrink;
|
||||
to_x += shrink * std::sin(to_radians(90) - to_radians(m_corner_angle) / 2);
|
||||
to_y +=
|
||||
line_spacing_first_layer() * (wall_count() - 1) +
|
||||
(line_width_first_layer() * (1 - m_encroachment))
|
||||
;
|
||||
}
|
||||
|
||||
double initial_x = to_x;
|
||||
double initial_y = to_y;
|
||||
|
||||
gcode << move_to(Vec2d(to_x, to_y), m_writer, "Move to pattern start");
|
||||
|
||||
for (int j = 0; j < num_patterns; ++j) {
|
||||
// increment pressure advance
|
||||
gcode << m_writer.set_pressure_advance(m_params.start + (j * m_params.step));
|
||||
|
||||
for (int k = 0; k < wall_count(); ++k) {
|
||||
to_x += std::cos(to_radians(m_corner_angle) / 2) * side_length;
|
||||
to_y += std::sin(to_radians(m_corner_angle) / 2) * side_length;
|
||||
|
||||
draw_line_opt_args = default_line_opt_args;
|
||||
draw_line_opt_args.height = i == 0 ? height_first_layer() : height_layer();
|
||||
draw_line_opt_args.line_width = line_width(); // don't use line_width_first_layer so results are consistent across all layers
|
||||
draw_line_opt_args.speed = i == 0 ? speed_adjust(speed_first_layer()) : speed_adjust(speed_perimeter());
|
||||
draw_line_opt_args.comment = "Print pattern wall";
|
||||
gcode << draw_line(Vec2d(to_x, to_y), draw_line_opt_args);
|
||||
|
||||
to_x -= std::cos(to_radians(m_corner_angle) / 2) * side_length;
|
||||
to_y += std::sin(to_radians(m_corner_angle) / 2) * side_length;
|
||||
|
||||
gcode << draw_line(Vec2d(to_x, to_y), draw_line_opt_args);
|
||||
|
||||
to_y = initial_y;
|
||||
if (k != wall_count() - 1) {
|
||||
// perimeters not done yet. move to next perimeter
|
||||
to_x += line_spacing_angle();
|
||||
gcode << move_to(Vec2d(to_x, to_y), m_writer, "Move to start next pattern wall");
|
||||
} else if (j != num_patterns - 1) {
|
||||
// patterns not done yet. move to next pattern
|
||||
to_x += m_pattern_spacing + line_width();
|
||||
gcode << move_to(Vec2d(to_x, to_y), m_writer, "Move to next pattern");
|
||||
} else if (i != m_num_layers - 1) {
|
||||
// layers not done yet. move back to start
|
||||
to_x = initial_x;
|
||||
gcode << move_to(Vec2d(to_x, to_y), m_writer, "Move back to start position");
|
||||
} else {
|
||||
// everything done
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gcode << m_writer.set_pressure_advance(m_params.start);
|
||||
gcode << "; end pressure advance pattern for layer\n";
|
||||
|
||||
CustomGCode::Item item;
|
||||
item.print_z = max_layer_z();
|
||||
item.type = CustomGCode::Type::Custom;
|
||||
item.extra = gcode.str();
|
||||
gcode_items.push_back(item);
|
||||
|
||||
CustomGCode::Info info;
|
||||
info.mode = CustomGCode::Mode::SingleExtruder;
|
||||
info.gcodes = gcode_items;
|
||||
|
||||
//model.plates_custom_gcodes[model.curr_plate_index] = info;
|
||||
}
|
||||
|
||||
void CalibPressureAdvancePattern::refresh_setup(
|
||||
const DynamicPrintConfig& config,
|
||||
bool is_bbl_machine,
|
||||
const Model& model,
|
||||
const Vec3d& origin
|
||||
)
|
||||
{
|
||||
m_config = config;
|
||||
m_config.apply(model.objects.front()->config.get(), true);
|
||||
m_config.apply(model.objects.front()->volumes.front()->config.get(), true);
|
||||
|
||||
m_is_delta = (m_config.option<ConfigOptionPoints>("bed_shape")->values.size() > 4);
|
||||
|
||||
_refresh_starting_point(model);
|
||||
_refresh_writer(is_bbl_machine, model, origin);
|
||||
}
|
||||
|
||||
void CalibPressureAdvancePattern::_refresh_starting_point(const Model& model)
|
||||
{
|
||||
ModelObject* obj = model.objects.front();
|
||||
//BoundingBoxf3 bbox =
|
||||
// obj->instance_bounding_box(
|
||||
// *obj->instances.front(),
|
||||
// false
|
||||
// )
|
||||
//;
|
||||
|
||||
m_starting_point = Vec3d(0, 0, 0);
|
||||
m_starting_point.y() += m_handle_spacing;
|
||||
|
||||
if (m_is_delta) {
|
||||
m_starting_point.x() *= -1;
|
||||
m_starting_point.y() -= (frame_size_y() / 2);
|
||||
}
|
||||
}
|
||||
|
||||
void CalibPressureAdvancePattern::_refresh_writer(
|
||||
bool is_bbl_machine,
|
||||
const Model& model,
|
||||
const Vec3d& origin
|
||||
)
|
||||
{
|
||||
PrintConfig print_config;
|
||||
print_config.apply(m_config, true);
|
||||
|
||||
m_writer.apply_print_config(print_config);
|
||||
//m_writer.set_xy_offset(origin(0), origin(1));
|
||||
|
||||
const unsigned int extruder_id = model.objects.front()->volumes.front()->extruder_id();
|
||||
m_writer.set_extruders({ extruder_id });
|
||||
m_writer.set_extruder(extruder_id);
|
||||
}
|
||||
|
||||
std::string CalibPressureAdvancePattern::draw_line(
|
||||
Vec2d to_pt,
|
||||
DrawLineOptArgs opt_args
|
||||
)
|
||||
{
|
||||
const double e_per_mm = CalibPressureAdvance::e_per_mm(
|
||||
opt_args.line_width,
|
||||
opt_args.height,
|
||||
m_config.option<ConfigOptionFloats>("nozzle_diameter")->get_at(0),
|
||||
m_config.option<ConfigOptionFloats>("filament_diameter")->get_at(0),
|
||||
m_config.option<ConfigOptionFloats>("filament_flow_ratio")->get_at(0)
|
||||
);
|
||||
|
||||
const double length = get_distance(Vec2d(m_last_pos.x(), m_last_pos.y()), to_pt);
|
||||
auto dE = e_per_mm * length;
|
||||
|
||||
std::stringstream gcode;
|
||||
|
||||
gcode << m_writer.set_speed(opt_args.speed);
|
||||
gcode << m_writer.extrude_to_xy(to_pt, dE, opt_args.comment);
|
||||
|
||||
m_last_pos = Vec3d(to_pt.x(), to_pt.y(), 0);
|
||||
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
std::string CalibPressureAdvancePattern::draw_box(
|
||||
double min_x,
|
||||
double min_y,
|
||||
double size_x,
|
||||
double size_y,
|
||||
DrawBoxOptArgs opt_args
|
||||
)
|
||||
{
|
||||
std::stringstream gcode;
|
||||
|
||||
double x = min_x;
|
||||
double y = min_y;
|
||||
const double max_x = min_x + size_x;
|
||||
const double max_y = min_y + size_y;
|
||||
|
||||
const double spacing = opt_args.line_width - opt_args.height * (1 - M_PI / 4);
|
||||
|
||||
// if number of perims exceeds size of box, reduce it to max
|
||||
const int max_perimeters =
|
||||
std::min(
|
||||
// this is the equivalent of number of perims for concentric fill
|
||||
std::floor(size_x * std::sin(to_radians(45))) / (spacing / std::sin(to_radians(45))),
|
||||
std::floor(size_y * std::sin(to_radians(45))) / (spacing / std::sin(to_radians(45)))
|
||||
)
|
||||
;
|
||||
|
||||
opt_args.num_perimeters = std::min(opt_args.num_perimeters, max_perimeters);
|
||||
|
||||
gcode << move_to(Vec2d(min_x, min_y), m_writer, "Move to box start");
|
||||
|
||||
DrawLineOptArgs line_opt_args(*this);
|
||||
line_opt_args.height = opt_args.height;
|
||||
line_opt_args.line_width = opt_args.line_width;
|
||||
line_opt_args.speed = opt_args.speed;
|
||||
|
||||
for (int i = 0; i < opt_args.num_perimeters; ++i) {
|
||||
if (i != 0) { // after first perimeter, step inwards to start next perimeter
|
||||
x += spacing;
|
||||
y += spacing;
|
||||
gcode << move_to(Vec2d(x, y), m_writer, "Step inwards to print next perimeter");
|
||||
}
|
||||
|
||||
y += size_y - i * spacing * 2;
|
||||
line_opt_args.comment = "Draw perimeter (up)";
|
||||
gcode << draw_line(Vec2d(x, y), line_opt_args);
|
||||
|
||||
x += size_x - i * spacing * 2;
|
||||
line_opt_args.comment = "Draw perimeter (right)";
|
||||
gcode << draw_line(Vec2d(x, y), line_opt_args);
|
||||
|
||||
y -= size_y - i * spacing * 2;
|
||||
line_opt_args.comment = "Draw perimeter (down)";
|
||||
gcode << draw_line(Vec2d(x, y), line_opt_args);
|
||||
|
||||
x -= size_x - i * spacing * 2;
|
||||
line_opt_args.comment = "Draw perimeter (left)";
|
||||
gcode << draw_line(Vec2d(x, y), line_opt_args);
|
||||
}
|
||||
|
||||
if (!opt_args.is_filled) {
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
// create box infill
|
||||
const double spacing_45 = spacing / std::sin(to_radians(45));
|
||||
|
||||
const double bound_modifier =
|
||||
(spacing * (opt_args.num_perimeters - 1)) +
|
||||
(opt_args.line_width * (1 - m_encroachment))
|
||||
;
|
||||
const double x_min_bound = min_x + bound_modifier;
|
||||
const double x_max_bound = max_x - bound_modifier;
|
||||
const double y_min_bound = min_y + bound_modifier;
|
||||
const double y_max_bound = max_y - bound_modifier;
|
||||
const int x_count = std::floor((x_max_bound - x_min_bound) / spacing_45);
|
||||
const int y_count = std::floor((y_max_bound - y_min_bound) / spacing_45);
|
||||
|
||||
double x_remainder = std::fmod((x_max_bound - x_min_bound), spacing_45);
|
||||
double y_remainder = std::fmod((y_max_bound - y_min_bound), spacing_45);
|
||||
|
||||
x = x_min_bound;
|
||||
y = y_min_bound;
|
||||
|
||||
gcode << move_to(Vec2d(x, y), m_writer, "Move to fill start");
|
||||
|
||||
for (int i = 0; i < x_count + y_count + (x_remainder + y_remainder >= spacing_45 ? 1 : 0); ++i) { // this isn't the most robust way, but less expensive than finding line intersections
|
||||
if (i < std::min(x_count, y_count)) {
|
||||
if (i % 2 == 0) {
|
||||
x += spacing_45;
|
||||
y = y_min_bound;
|
||||
gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step right");
|
||||
|
||||
y += x - x_min_bound;
|
||||
x = x_min_bound;
|
||||
line_opt_args.comment = "Fill: Print up/left";
|
||||
gcode << draw_line(Vec2d(x, y), line_opt_args);
|
||||
} else {
|
||||
y += spacing_45;
|
||||
x = x_min_bound;
|
||||
gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step up");
|
||||
|
||||
x += y - y_min_bound;
|
||||
y = y_min_bound;
|
||||
line_opt_args.comment = "Fill: Print down/right";
|
||||
gcode << draw_line(Vec2d(x, y), line_opt_args);
|
||||
}
|
||||
} else if (i < std::max(x_count, y_count)) {
|
||||
if (x_count > y_count) {
|
||||
// box is wider than tall
|
||||
if (i % 2 == 0) {
|
||||
x += spacing_45;
|
||||
y = y_min_bound;
|
||||
gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step right");
|
||||
|
||||
x -= y_max_bound - y_min_bound;
|
||||
y = y_max_bound;
|
||||
line_opt_args.comment = "Fill: Print up/left";
|
||||
gcode << draw_line(Vec2d(x, y), line_opt_args);
|
||||
} else {
|
||||
if (i == y_count) {
|
||||
x += spacing_45 - y_remainder;
|
||||
y_remainder = 0;
|
||||
} else {
|
||||
x += spacing_45;
|
||||
}
|
||||
y = y_max_bound;
|
||||
gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step right");
|
||||
|
||||
x += y_max_bound - y_min_bound;
|
||||
y = y_min_bound;
|
||||
line_opt_args.comment = "Fill: Print down/right";
|
||||
gcode << draw_line(Vec2d(x, y), line_opt_args);
|
||||
}
|
||||
} else {
|
||||
// box is taller than wide
|
||||
if (i % 2 == 0) {
|
||||
x = x_max_bound;
|
||||
if (i == x_count) {
|
||||
y += spacing_45 - x_remainder;
|
||||
x_remainder = 0;
|
||||
} else {
|
||||
y += spacing_45;
|
||||
}
|
||||
gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step up");
|
||||
|
||||
x = x_min_bound;
|
||||
y += x_max_bound - x_min_bound;
|
||||
line_opt_args.comment = "Fill: Print up/left";
|
||||
gcode << draw_line(Vec2d(x, y), line_opt_args);
|
||||
} else {
|
||||
x = x_min_bound;
|
||||
y += spacing_45;
|
||||
gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step up");
|
||||
|
||||
x = x_max_bound;
|
||||
y -= x_max_bound - x_min_bound;
|
||||
line_opt_args.comment = "Fill: Print down/right";
|
||||
gcode << draw_line(Vec2d(x, y), line_opt_args);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (i % 2 == 0) {
|
||||
x = x_max_bound;
|
||||
if (i == x_count) {
|
||||
y += spacing_45 - x_remainder;
|
||||
} else {
|
||||
y += spacing_45;
|
||||
}
|
||||
gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step up");
|
||||
|
||||
x -= y_max_bound - y;
|
||||
y = y_max_bound;
|
||||
line_opt_args.comment = "Fill: Print up/left";
|
||||
gcode << draw_line(Vec2d(x, y), line_opt_args);
|
||||
} else {
|
||||
if (i == y_count) {
|
||||
x += spacing_45 - y_remainder;
|
||||
} else {
|
||||
x += spacing_45;
|
||||
}
|
||||
y = y_max_bound;
|
||||
gcode << move_to(Vec2d(x, y), m_writer, "Fill: Step right");
|
||||
|
||||
y -= x_max_bound - x;
|
||||
x = x_max_bound;
|
||||
line_opt_args.comment = "Fill: Print down/right";
|
||||
gcode << draw_line(Vec2d(x, y), line_opt_args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
double CalibPressureAdvancePattern::get_distance(Vec2d from, Vec2d to) const
|
||||
{
|
||||
return std::hypot((to.x() - from.x()), (to.y() - from.y()));
|
||||
}
|
||||
|
||||
double CalibPressureAdvancePattern::object_size_x() const
|
||||
{
|
||||
return get_num_patterns() * ((wall_count() - 1) * line_spacing_angle()) +
|
||||
(get_num_patterns() - 1) * (m_pattern_spacing + line_width()) +
|
||||
std::cos(to_radians(m_corner_angle) / 2) * m_wall_side_length +
|
||||
line_spacing_first_layer() * wall_count()
|
||||
;
|
||||
}
|
||||
|
||||
double CalibPressureAdvancePattern::object_size_y() const
|
||||
{
|
||||
return 2 * (std::sin(to_radians(m_corner_angle) / 2) * m_wall_side_length) +
|
||||
max_numbering_height() +
|
||||
m_glyph_padding_vertical * 2 +
|
||||
line_width_first_layer();
|
||||
}
|
||||
|
||||
double CalibPressureAdvancePattern::glyph_start_x(int pattern_i) const
|
||||
{
|
||||
// note that pattern_i is zero-based!
|
||||
// align glyph's start with first perimeter of specified pattern
|
||||
double x =
|
||||
// starting offset
|
||||
m_starting_point.x() +
|
||||
pattern_shift() +
|
||||
|
||||
// width of pattern extrusions
|
||||
pattern_i * (wall_count() - 1) * line_spacing_angle() + // center to center distance of extrusions
|
||||
pattern_i * line_width() + // endcaps. center to end on either side = 1 line width
|
||||
|
||||
// space between each pattern
|
||||
pattern_i * m_pattern_spacing
|
||||
;
|
||||
|
||||
// align to middle of pattern walls
|
||||
x += wall_count() * line_spacing_angle() / 2;
|
||||
|
||||
// shift so glyph is centered on pattern
|
||||
// m_digit_segment_len = half of X length of glyph
|
||||
x -= (glyph_length_x() / 2);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
double CalibPressureAdvancePattern::glyph_length_x() const
|
||||
{
|
||||
// half of line_width sticks out on each side
|
||||
return line_width() + (2 * m_digit_segment_len);
|
||||
}
|
||||
|
||||
double CalibPressureAdvancePattern::glyph_tab_max_x() const
|
||||
{
|
||||
// only every other glyph is shown, starting with 1
|
||||
int num = get_num_patterns();
|
||||
int max_num =
|
||||
(num % 2 == 0)
|
||||
? num - 1
|
||||
: num
|
||||
;
|
||||
|
||||
// padding at end should be same as padding at start
|
||||
double padding = glyph_start_x(0) - m_starting_point.x();
|
||||
|
||||
return
|
||||
glyph_start_x(max_num - 1) + // glyph_start_x is zero-based
|
||||
(glyph_length_x() - line_width() / 2) +
|
||||
padding
|
||||
;
|
||||
}
|
||||
|
||||
double CalibPressureAdvancePattern::max_numbering_height() const
|
||||
{
|
||||
std::string::size_type most_characters = 0;
|
||||
const int num_patterns = get_num_patterns();
|
||||
|
||||
// note: only every other number is printed
|
||||
for (std::string::size_type i = 0; i < num_patterns; i += 2) {
|
||||
std::string sNumber = convert_number_to_string(m_params.start + (i * m_params.step));
|
||||
|
||||
if (sNumber.length() > most_characters) {
|
||||
most_characters = sNumber.length();
|
||||
}
|
||||
}
|
||||
|
||||
most_characters = std::min(most_characters, m_max_number_len);
|
||||
|
||||
return (most_characters * m_digit_segment_len) + ((most_characters - 1) * m_digit_gap_len);
|
||||
}
|
||||
|
||||
double CalibPressureAdvancePattern::pattern_shift() const
|
||||
{
|
||||
return
|
||||
(wall_count() - 1) * line_spacing_first_layer() +
|
||||
line_width_first_layer() +
|
||||
m_glyph_padding_horizontal
|
||||
;
|
||||
}
|
||||
} // namespace Slic3r
|
||||
280
src/libslic3r/calib.hpp
Normal file
@@ -0,0 +1,280 @@
|
||||
#pragma once
|
||||
#define calib_pressure_advance_dd
|
||||
|
||||
#include "GCode.hpp"
|
||||
#include "GCodeWriter.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
enum class CalibMode : int {
|
||||
Calib_None = 0,
|
||||
Calib_PA_Line,
|
||||
Calib_PA_Pattern,
|
||||
Calib_PA_Tower,
|
||||
Calib_Temp_Tower,
|
||||
Calib_Vol_speed_Tower,
|
||||
Calib_VFA_Tower,
|
||||
Calib_Retraction_tower
|
||||
};
|
||||
|
||||
struct Calib_Params {
|
||||
Calib_Params() : mode(CalibMode::Calib_None) { };
|
||||
double start, end, step;
|
||||
bool print_numbers;
|
||||
CalibMode mode;
|
||||
};
|
||||
|
||||
class CalibPressureAdvance {
|
||||
public:
|
||||
static float find_optimal_PA_speed(const DynamicPrintConfig &config, double line_width, double layer_height,
|
||||
int filament_idx = 0);
|
||||
|
||||
protected:
|
||||
CalibPressureAdvance() =default;
|
||||
~CalibPressureAdvance() =default;
|
||||
|
||||
enum class DrawDigitMode {
|
||||
Left_To_Right,
|
||||
Bottom_To_Top
|
||||
};
|
||||
|
||||
void delta_scale_bed_ext(BoundingBoxf& bed_ext) const { bed_ext.scale(1.0f / 1.41421f); }
|
||||
|
||||
std::string move_to(Vec2d pt, GCodeWriter& writer, std::string comment = std::string());
|
||||
double e_per_mm(
|
||||
double line_width,
|
||||
double layer_height,
|
||||
float nozzle_diameter,
|
||||
float filament_diameter,
|
||||
float print_flow_ratio
|
||||
) const;
|
||||
double speed_adjust(int speed) const { return speed * 60; };
|
||||
|
||||
std::string convert_number_to_string(double num) const;
|
||||
double number_spacing() const { return m_digit_segment_len + m_digit_gap_len; };
|
||||
std::string draw_digit(
|
||||
double startx,
|
||||
double starty,
|
||||
char c,
|
||||
CalibPressureAdvance::DrawDigitMode mode,
|
||||
double line_width,
|
||||
double e_per_mm,
|
||||
GCodeWriter& writer
|
||||
);
|
||||
std::string draw_number(
|
||||
double startx,
|
||||
double starty,
|
||||
double value,
|
||||
CalibPressureAdvance::DrawDigitMode mode,
|
||||
double line_width,
|
||||
double e_per_mm,
|
||||
double speed,
|
||||
GCodeWriter& writer
|
||||
);
|
||||
|
||||
Vec3d m_last_pos;
|
||||
|
||||
DrawDigitMode m_draw_digit_mode {DrawDigitMode::Left_To_Right};
|
||||
const double m_digit_segment_len {2};
|
||||
const double m_digit_gap_len {1};
|
||||
const std::string::size_type m_max_number_len {5};
|
||||
};
|
||||
|
||||
class CalibPressureAdvanceLine : public CalibPressureAdvance {
|
||||
public:
|
||||
CalibPressureAdvanceLine(GCode* gcodegen) :
|
||||
mp_gcodegen(gcodegen),
|
||||
m_nozzle_diameter(gcodegen->config().nozzle_diameter.get_at(0))
|
||||
{ };
|
||||
~CalibPressureAdvanceLine() { };
|
||||
|
||||
std::string generate_test(double start_pa = 0, double step_pa = 0.002, int count = 50);
|
||||
|
||||
void set_speed(double fast = 100.0, double slow = 20.0) {
|
||||
m_slow_speed = slow;
|
||||
m_fast_speed = fast;
|
||||
}
|
||||
|
||||
const double& line_width() { return m_line_width; };
|
||||
bool is_delta() const;
|
||||
bool& draw_numbers() { return m_draw_numbers; }
|
||||
|
||||
private:
|
||||
std::string print_pa_lines(double start_x, double start_y, double start_pa, double step_pa, int num);
|
||||
|
||||
void delta_modify_start(double& startx, double& starty, int count);
|
||||
|
||||
GCode* mp_gcodegen;
|
||||
|
||||
double m_nozzle_diameter;
|
||||
double m_slow_speed, m_fast_speed;
|
||||
|
||||
const double m_height_layer {0.2};
|
||||
const double m_line_width {0.6};
|
||||
const double m_thin_line_width {0.44};
|
||||
const double m_number_line_width {0.48};
|
||||
const double m_space_y {3.5};
|
||||
|
||||
double m_length_short {20.0}, m_length_long {40.0};
|
||||
bool m_draw_numbers {true};
|
||||
};
|
||||
|
||||
struct SuggestedConfigCalibPAPattern {
|
||||
const std::vector<std::pair<std::string, double>> float_pairs {
|
||||
{"initial_layer_print_height", 0.25},
|
||||
{"layer_height", 0.2},
|
||||
{"initial_layer_speed", 30}
|
||||
};
|
||||
|
||||
const std::vector<std::pair<std::string, double>> nozzle_ratio_pairs {
|
||||
{"line_width", 112.5},
|
||||
{"initial_layer_line_width", 140}
|
||||
};
|
||||
|
||||
const std::vector<std::pair<std::string, int>> int_pairs {
|
||||
{"skirt_loops", 0},
|
||||
{"wall_loops", 3}
|
||||
};
|
||||
|
||||
const std::pair<std::string, BrimType> brim_pair {"brim_type", BrimType::btNoBrim};
|
||||
};
|
||||
|
||||
class CalibPressureAdvancePattern : public CalibPressureAdvance {
|
||||
friend struct DrawLineOptArgs;
|
||||
friend struct DrawBoxOptArgs;
|
||||
|
||||
public:
|
||||
CalibPressureAdvancePattern(
|
||||
const Calib_Params& params,
|
||||
const DynamicPrintConfig& config,
|
||||
bool is_bbl_machine,
|
||||
Model& model,
|
||||
const Vec3d& origin
|
||||
);
|
||||
|
||||
double handle_xy_size() const { return m_handle_xy_size; };
|
||||
double handle_spacing() const { return m_handle_spacing; };
|
||||
double print_size_x() const { return object_size_x() + pattern_shift(); };
|
||||
double print_size_y() const { return object_size_y(); };
|
||||
double max_layer_z() const { return height_first_layer() + ((m_num_layers - 1) * height_layer()); };
|
||||
|
||||
void generate_custom_gcodes(
|
||||
const DynamicPrintConfig& config,
|
||||
bool is_bbl_machine,
|
||||
Model& model,
|
||||
const Vec3d& origin
|
||||
);
|
||||
|
||||
protected:
|
||||
double speed_first_layer() const { return m_config.option<ConfigOptionFloat>("initial_layer_speed")->value; };
|
||||
double speed_perimeter() const { return m_config.option<ConfigOptionFloat>("outer_wall_speed")->value; };
|
||||
double line_width_first_layer() const { return m_config.get_abs_value("initial_layer_line_width"); };
|
||||
double line_width() const { return m_config.get_abs_value("line_width"); };
|
||||
int wall_count() const { return m_config.option<ConfigOptionInt>("wall_loops")->value; };
|
||||
|
||||
private:
|
||||
struct DrawLineOptArgs {
|
||||
DrawLineOptArgs(const CalibPressureAdvancePattern& p) :
|
||||
height {p.height_layer()},
|
||||
line_width {p.line_width()},
|
||||
speed {p.speed_adjust(p.speed_perimeter())}
|
||||
{ };
|
||||
|
||||
double height;
|
||||
double line_width;
|
||||
double speed;
|
||||
std::string comment {"Print line"};
|
||||
};
|
||||
|
||||
struct DrawBoxOptArgs {
|
||||
DrawBoxOptArgs(const CalibPressureAdvancePattern& p) :
|
||||
num_perimeters {p.wall_count()},
|
||||
height {p.height_first_layer()},
|
||||
line_width {p.line_width_first_layer()},
|
||||
speed {p.speed_adjust(p.speed_first_layer())}
|
||||
{ };
|
||||
|
||||
bool is_filled {false};
|
||||
int num_perimeters;
|
||||
double height;
|
||||
double line_width;
|
||||
double speed;
|
||||
};
|
||||
|
||||
void refresh_setup(
|
||||
const DynamicPrintConfig& config,
|
||||
bool is_bbl_machine,
|
||||
const Model& model,
|
||||
const Vec3d& origin
|
||||
);
|
||||
void _refresh_starting_point(const Model& model);
|
||||
void _refresh_writer(
|
||||
bool is_bbl_machine,
|
||||
const Model& model,
|
||||
const Vec3d& origin
|
||||
);
|
||||
|
||||
double height_first_layer() const { return m_config.option<ConfigOptionFloat>("initial_layer_print_height")->value; };
|
||||
double height_layer() const { return m_config.option<ConfigOptionFloat>("layer_height")->value; };
|
||||
const int get_num_patterns() const
|
||||
{
|
||||
return std::ceil((m_params.end - m_params.start) / m_params.step + 1);
|
||||
}
|
||||
|
||||
std::string draw_line(
|
||||
Vec2d to_pt,
|
||||
DrawLineOptArgs opt_args
|
||||
);
|
||||
std::string draw_box(
|
||||
double min_x,
|
||||
double min_y,
|
||||
double size_x,
|
||||
double size_y,
|
||||
DrawBoxOptArgs opt_args
|
||||
);
|
||||
|
||||
double to_radians(double degrees) const { return degrees * M_PI / 180; };
|
||||
double get_distance(Vec2d from, Vec2d to) const;
|
||||
|
||||
/*
|
||||
from slic3r documentation: spacing = extrusion_width - layer_height * (1 - PI/4)
|
||||
"spacing" = center-to-center distance of adjacent extrusions, which partially overlap
|
||||
https://manual.slic3r.org/advanced/flow-math
|
||||
https://ellis3dp.com/Print-Tuning-Guide/articles/misconceptions.html#two-04mm-perimeters--08mm
|
||||
*/
|
||||
double line_spacing() const { return line_width() - height_layer() * (1 - M_PI / 4); };
|
||||
double line_spacing_first_layer() const { return line_width_first_layer() - height_first_layer() * (1 - M_PI / 4); };
|
||||
double line_spacing_angle() const { return line_spacing() / std::sin(to_radians(m_corner_angle) / 2); };
|
||||
|
||||
double object_size_x() const;
|
||||
double object_size_y() const;
|
||||
double frame_size_y() const { return std::sin(to_radians(double(m_corner_angle) / 2)) * m_wall_side_length * 2; };
|
||||
|
||||
double glyph_start_x(int pattern_i = 0) const;
|
||||
double glyph_length_x() const;
|
||||
double glyph_tab_max_x() const;
|
||||
double max_numbering_height() const;
|
||||
|
||||
double pattern_shift() const;
|
||||
|
||||
const Calib_Params& m_params;
|
||||
|
||||
DynamicPrintConfig m_config;
|
||||
GCodeWriter m_writer;
|
||||
bool m_is_delta;
|
||||
Vec3d m_starting_point;
|
||||
|
||||
const double m_handle_xy_size {5};
|
||||
const double m_handle_spacing {2};
|
||||
const int m_num_layers {4};
|
||||
|
||||
const double m_wall_side_length {30.0};
|
||||
const int m_corner_angle {90};
|
||||
const int m_pattern_spacing {2};
|
||||
const double m_encroachment {1. / 3.};
|
||||
|
||||
const double m_glyph_padding_horizontal {1};
|
||||
const double m_glyph_padding_vertical {1};
|
||||
};
|
||||
} // namespace Slic3r
|
||||
@@ -26,8 +26,27 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/Widgets/StateHandler.hpp
|
||||
GUI/Widgets/StaticBox.cpp
|
||||
GUI/Widgets/StaticBox.hpp
|
||||
GUI/Widgets/Button.cpp
|
||||
GUI/Widgets/Button.hpp
|
||||
GUI/Widgets/CheckBoxInWT.cpp
|
||||
GUI/Widgets/CheckBoxInWT.hpp
|
||||
GUI/Widgets/ComboBox.cpp
|
||||
GUI/Widgets/ComboBox.hpp
|
||||
GUI/Widgets/TextInput.cpp
|
||||
GUI/Widgets/TextInput.hpp
|
||||
GUI/Widgets/TextCtrl.h
|
||||
GUI/Widgets/RoundedRectangle.cpp
|
||||
GUI/Widgets/RoundedRectangle.hpp
|
||||
GUI/Widgets/RadioBox.cpp
|
||||
GUI/Widgets/RadioBox.hpp
|
||||
GUI/Widgets/DropDown.cpp
|
||||
GUI/Widgets/DropDown.hpp
|
||||
GUI/Widgets/PopupWindow.cpp
|
||||
GUI/Widgets/PopupWindow.hpp
|
||||
GUI/ConfigSnapshotDialog.cpp
|
||||
GUI/ConfigSnapshotDialog.hpp
|
||||
GUI/calib_dlg.cpp
|
||||
GUI/calib_dlg.hpp
|
||||
GUI/3DScene.cpp
|
||||
GUI/3DScene.hpp
|
||||
GUI/format.hpp
|
||||
|
||||
@@ -831,7 +831,8 @@ void Preview::load_print_as_fff(bool keep_z_range)
|
||||
unsigned int number_extruders = wxGetApp().is_editor() ?
|
||||
(unsigned int)print->extruders().size() :
|
||||
m_canvas->get_gcode_extruders_count();
|
||||
std::vector<Item> gcodes = wxGetApp().is_editor() ?
|
||||
//B34
|
||||
std::vector<CustomGCode::Item> gcodes = wxGetApp().is_editor() ?
|
||||
wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes :
|
||||
m_canvas->get_custom_gcode_per_print_z();
|
||||
const bool contains_color_gcodes = std::any_of(std::begin(gcodes), std::end(gcodes),
|
||||
|
||||
@@ -880,6 +880,7 @@ void MainFrame::create_preset_tabs()
|
||||
else
|
||||
#endif
|
||||
m_tabpanel->AddPage(m_guide_view, _L("Guide"));
|
||||
|
||||
}
|
||||
|
||||
void MainFrame::add_created_tab(Tab* panel, const std::string& bmp_name /*= ""*/)
|
||||
@@ -1566,6 +1567,45 @@ void MainFrame::init_menubar_as_editor()
|
||||
|
||||
// Help menu
|
||||
auto helpMenu = generate_help_menu();
|
||||
|
||||
//B34
|
||||
//auto calibrationMenu = generate_calibration_menu();
|
||||
auto calibrationMenu = new wxMenu();
|
||||
auto flowrate_menu = new wxMenu();
|
||||
append_menu_item(flowrate_menu, wxID_ANY, _L("Pass 1"), _L("Flow rate test - Pass 1"), [this](wxCommandEvent &) {
|
||||
if (m_plater)
|
||||
m_plater->calib_flowrate(1);
|
||||
},
|
||||
"", nullptr,
|
||||
[this]() {
|
||||
return m_plater->is_view3D_shown();
|
||||
;
|
||||
},
|
||||
this);
|
||||
append_menu_item(flowrate_menu, wxID_ANY, _L("Pass 2"), _L("Flow rate test - Pass 2"), [this](wxCommandEvent &) {
|
||||
if (m_plater)
|
||||
m_plater->calib_flowrate(2);
|
||||
},
|
||||
"", nullptr,
|
||||
[this]() {
|
||||
return m_plater->is_view3D_shown();
|
||||
;
|
||||
},
|
||||
this);
|
||||
calibrationMenu->AppendSubMenu(flowrate_menu, _L("Flow rate"));
|
||||
append_menu_item(
|
||||
calibrationMenu, wxID_ANY, _L("Pressure advance"), _L("Pressure advance"),
|
||||
[this](wxCommandEvent &) {
|
||||
if (!m_pa_calib_dlg)
|
||||
m_pa_calib_dlg = new PA_Calibration_Dlg((wxWindow *) this, wxID_ANY, m_plater);
|
||||
m_pa_calib_dlg->ShowModal();
|
||||
},
|
||||
"", nullptr,
|
||||
[this]() {
|
||||
return m_plater->is_view3D_shown();
|
||||
;
|
||||
},
|
||||
this);
|
||||
|
||||
// menubar
|
||||
// assign menubar to frame after appending items, otherwise special items
|
||||
@@ -1579,6 +1619,8 @@ void MainFrame::init_menubar_as_editor()
|
||||
// Add additional menus from C++
|
||||
wxGetApp().add_config_menu(m_menubar);
|
||||
m_menubar->Append(helpMenu, _L("&Help"));
|
||||
//B34
|
||||
m_menubar->Append(calibrationMenu, _L("&Calibration"));
|
||||
|
||||
#ifdef _MSW_DARK_MODE
|
||||
if (wxGetApp().tabs_as_menu()) {
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include "PrinterWebView.hpp"
|
||||
// B28
|
||||
#include "GuideWebView.hpp"
|
||||
//B34
|
||||
#include "calib_dlg.hpp"
|
||||
|
||||
class wxBookCtrlBase;
|
||||
class wxProgressDialog;
|
||||
@@ -210,7 +212,8 @@ public:
|
||||
|
||||
|
||||
Plater *m_plater{nullptr};
|
||||
|
||||
//B34
|
||||
PA_Calibration_Dlg *m_pa_calib_dlg{nullptr};
|
||||
//B4
|
||||
wxString tem_host;
|
||||
PrinterWebView * m_printer_view{nullptr};
|
||||
|
||||
@@ -5363,6 +5363,81 @@ void Plater::add_model(bool imperial_units/* = false*/)
|
||||
if (! load_files(paths, true, false, imperial_units).empty())
|
||||
wxGetApp().mainframe->update_title();
|
||||
}
|
||||
//B34
|
||||
void Plater::add_model_calibration(bool imperial_units /* = false*/, std::string fname /* = ""*/)
|
||||
{
|
||||
std::vector<fs::path> paths;
|
||||
|
||||
if (fname.empty()) {
|
||||
wxArrayString input_files;
|
||||
wxGetApp().import_model(this, input_files);
|
||||
if (input_files.empty())
|
||||
return;
|
||||
|
||||
for (const auto &file : input_files)
|
||||
paths.emplace_back(into_path(file));
|
||||
} else {
|
||||
paths.emplace_back(fname);
|
||||
}
|
||||
|
||||
wxString snapshot_label;
|
||||
assert(!paths.empty());
|
||||
if (paths.size() == 1) {
|
||||
snapshot_label = "Import Object";
|
||||
snapshot_label += ": ";
|
||||
snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str());
|
||||
} else {
|
||||
snapshot_label = "Import Objects";
|
||||
snapshot_label += ": ";
|
||||
snapshot_label += paths.front().filename().string().c_str();
|
||||
for (size_t i = 1; i < paths.size(); ++i) {
|
||||
snapshot_label += ", ";
|
||||
snapshot_label += wxString::FromUTF8(paths[i].filename().string().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Plater::TakeSnapshot snapshot(this, snapshot_label);
|
||||
if (!load_files(paths, true, false, imperial_units).empty())
|
||||
wxGetApp().mainframe->update_title();
|
||||
}
|
||||
|
||||
//B34
|
||||
void Plater::calib_flowrate(int pass)
|
||||
{
|
||||
if (pass != 1 && pass != 2)
|
||||
return;
|
||||
const auto calib_name = wxString::Format(L"Flowrate Test - Pass%d", pass);
|
||||
new_project();
|
||||
|
||||
wxGetApp().mainframe->select_tab(size_t(0));
|
||||
|
||||
if (pass == 1)
|
||||
add_model_calibration(false,
|
||||
(boost::filesystem::path(Slic3r::resources_dir()) / "calib" / "filament_flow" / "flowrate-test-pass1.3mf").string());
|
||||
else
|
||||
add_model_calibration(false,
|
||||
(boost::filesystem::path(Slic3r::resources_dir()) / "calib" / "filament_flow" / "flowrate-test-pass2.3mf").string());
|
||||
|
||||
}
|
||||
//B34
|
||||
void Plater::calib_pa(const Calib_Params ¶ms)
|
||||
{
|
||||
const auto calib_pa_name = wxString::Format(L"Pressure Advance Test");
|
||||
new_project();
|
||||
wxGetApp().mainframe->select_tab(size_t(0));
|
||||
|
||||
switch (params.mode) {
|
||||
case CalibMode::Calib_PA_Line:
|
||||
add_model_calibration(false, Slic3r::resources_dir() + "/calib/PressureAdvance/pressure_advance_test.stl");
|
||||
break;
|
||||
//case CalibMode::Calib_PA_Pattern: _calib_pa_pattern(params); break;
|
||||
//case CalibMode::Calib_PA_Tower: _calib_pa_tower(params); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
//p->background_process.fff_print()->set_calib_params(params);
|
||||
}
|
||||
|
||||
|
||||
void Plater::import_zip_archive()
|
||||
{
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "Jobs/Job.hpp"
|
||||
#include "Jobs/Worker.hpp"
|
||||
#include "Search.hpp"
|
||||
//B34
|
||||
#include "libslic3r/Calib.hpp"
|
||||
|
||||
class wxButton;
|
||||
class ScalableButton;
|
||||
@@ -164,10 +166,17 @@ public:
|
||||
const SLAPrint& sla_print() const;
|
||||
SLAPrint& sla_print();
|
||||
|
||||
//B34
|
||||
void calib_pa(const Calib_Params ¶ms);
|
||||
void calib_flowrate(int pass);
|
||||
|
||||
|
||||
void new_project();
|
||||
void load_project();
|
||||
void load_project(const wxString& filename);
|
||||
void add_model(bool imperial_units = false);
|
||||
//B34
|
||||
void add_model_calibration(bool imperial_units = false, std::string fname = "");
|
||||
void import_zip_archive();
|
||||
void import_sl1_archive();
|
||||
void extract_config_from_project();
|
||||
|
||||
327
src/slic3r/GUI/Widgets/Button.cpp
Normal file
@@ -0,0 +1,327 @@
|
||||
#include "Button.hpp"
|
||||
#include "Label.hpp"
|
||||
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
BEGIN_EVENT_TABLE(Button, StaticBox)
|
||||
|
||||
EVT_LEFT_DOWN(Button::mouseDown)
|
||||
EVT_LEFT_UP(Button::mouseReleased)
|
||||
EVT_MOUSE_CAPTURE_LOST(Button::mouseCaptureLost)
|
||||
EVT_KEY_DOWN(Button::keyDownUp)
|
||||
EVT_KEY_UP(Button::keyDownUp)
|
||||
|
||||
// catch paint events
|
||||
EVT_PAINT(Button::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().
|
||||
*/
|
||||
|
||||
Button::Button()
|
||||
: paddingSize(10, 8)
|
||||
{
|
||||
background_color = StateColor(
|
||||
std::make_pair(0xF0F0F1, (int) StateColor::Disabled),
|
||||
std::make_pair(0x52c7b8, (int) StateColor::Hovered | StateColor::Checked),
|
||||
std::make_pair(0x009688, (int) StateColor::Checked),
|
||||
std::make_pair(*wxLIGHT_GREY, (int) StateColor::Hovered),
|
||||
std::make_pair(*wxWHITE, (int) StateColor::Normal));
|
||||
text_color = StateColor(
|
||||
std::make_pair(*wxLIGHT_GREY, (int) StateColor::Disabled),
|
||||
std::make_pair(*wxBLACK, (int) StateColor::Normal));
|
||||
}
|
||||
|
||||
Button::Button(wxWindow* parent, wxString text, wxString icon, long style, int iconSize, wxWindowID btn_id)
|
||||
: Button()
|
||||
{
|
||||
Create(parent, text, icon, style, iconSize, btn_id);
|
||||
}
|
||||
|
||||
bool Button::Create(wxWindow* parent, wxString text, wxString icon, long style, int iconSize, wxWindowID btn_id)
|
||||
{
|
||||
StaticBox::Create(parent, btn_id, wxDefaultPosition, wxDefaultSize, style);
|
||||
state_handler.attach({&text_color});
|
||||
state_handler.update_binds();
|
||||
//BBS set default font
|
||||
SetFont(Label::Body_14);
|
||||
wxWindow::SetLabel(text);
|
||||
if (!icon.IsEmpty()) {
|
||||
//BBS set button icon default size to 20
|
||||
this->active_icon = ScalableBitmap(this, icon.ToStdString(), iconSize > 0 ? iconSize : 20);
|
||||
}
|
||||
messureSize();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Button::SetLabel(const wxString& label)
|
||||
{
|
||||
wxWindow::SetLabel(label);
|
||||
messureSize();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
bool Button::SetFont(const wxFont& font)
|
||||
{
|
||||
wxWindow::SetFont(font);
|
||||
messureSize();
|
||||
Refresh();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Button::SetIcon(const wxString& icon)
|
||||
{
|
||||
if (!icon.IsEmpty()) {
|
||||
//BBS set button icon default size to 20
|
||||
this->active_icon = ScalableBitmap(this, icon.ToStdString(), this->active_icon.px_cnt());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->active_icon = ScalableBitmap();
|
||||
}
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void Button::SetInactiveIcon(const wxString &icon)
|
||||
{
|
||||
if (!icon.IsEmpty()) {
|
||||
// BBS set button icon default size to 20
|
||||
this->inactive_icon = ScalableBitmap(this, icon.ToStdString(), this->active_icon.px_cnt());
|
||||
} else {
|
||||
this->inactive_icon = ScalableBitmap();
|
||||
}
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void Button::SetMinSize(const wxSize& size)
|
||||
{
|
||||
minSize = size;
|
||||
messureSize();
|
||||
}
|
||||
|
||||
void Button::SetPaddingSize(const wxSize& size)
|
||||
{
|
||||
paddingSize = size;
|
||||
messureSize();
|
||||
}
|
||||
|
||||
void Button::SetTextColor(StateColor const& color)
|
||||
{
|
||||
text_color = color;
|
||||
state_handler.update_binds();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void Button::SetTextColorNormal(wxColor const &color)
|
||||
{
|
||||
text_color.setColorForStates(color, 0);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
bool Button::Enable(bool enable)
|
||||
{
|
||||
bool result = wxWindow::Enable(enable);
|
||||
if (result) {
|
||||
wxCommandEvent e(EVT_ENABLE_CHANGED);
|
||||
e.SetEventObject(this);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Button::SetCanFocus(bool canFocus) { this->canFocus = canFocus; }
|
||||
|
||||
void Button::SetValue(bool state)
|
||||
{
|
||||
if (GetValue() == state) return;
|
||||
state_handler.set_state(state ? StateHandler::Checked : 0, StateHandler::Checked);
|
||||
}
|
||||
|
||||
bool Button::GetValue() const { return state_handler.states() & StateHandler::Checked; }
|
||||
|
||||
void Button::Rescale()
|
||||
{
|
||||
if (this->active_icon.get_bitmap().IsOk())
|
||||
this->active_icon.msw_rescale();
|
||||
|
||||
if (this->inactive_icon.get_bitmap().IsOk())
|
||||
this->inactive_icon.msw_rescale();
|
||||
|
||||
messureSize();
|
||||
}
|
||||
|
||||
void Button::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 Button::render(wxDC& dc)
|
||||
{
|
||||
StaticBox::render(dc);
|
||||
int states = state_handler.states();
|
||||
wxSize size = GetSize();
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
// calc content size
|
||||
wxSize szIcon;
|
||||
wxSize szContent = textSize.GetSize();
|
||||
|
||||
ScalableBitmap icon;
|
||||
if (m_selected || ((states & (int)StateColor::State::Hovered) != 0))
|
||||
icon = active_icon;
|
||||
else
|
||||
icon = inactive_icon;
|
||||
int padding = 5;
|
||||
if (icon.get_bitmap().IsOk()) {
|
||||
if (szContent.y > 0) {
|
||||
//BBS norrow size between text and icon
|
||||
szContent.x += padding;
|
||||
}
|
||||
szIcon = icon.GetSize();
|
||||
szContent.x += szIcon.x;
|
||||
if (szIcon.y > szContent.y)
|
||||
szContent.y = szIcon.y;
|
||||
if (szContent.x > size.x) {
|
||||
int d = std::min(padding, szContent.x - size.x);
|
||||
padding -= d;
|
||||
szContent.x -= d;
|
||||
}
|
||||
}
|
||||
// move to center
|
||||
wxRect rcContent = { {0, 0}, size };
|
||||
wxSize offset = (size - szContent) / 2;
|
||||
if (offset.x < 0) offset.x = 0;
|
||||
rcContent.Deflate(offset.x, offset.y);
|
||||
// start draw
|
||||
wxPoint pt = rcContent.GetLeftTop();
|
||||
if (icon.get_bitmap().IsOk()) {
|
||||
pt.y += (rcContent.height - szIcon.y) / 2;
|
||||
dc.DrawBitmap(icon.get_bitmap(), pt);
|
||||
//BBS norrow size between text and icon
|
||||
pt.x += szIcon.x + padding;
|
||||
pt.y = rcContent.y;
|
||||
}
|
||||
auto text = GetLabel();
|
||||
if (!text.IsEmpty()) {
|
||||
if (pt.x + textSize.width > size.x)
|
||||
text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END, size.x - pt.x);
|
||||
pt.y += (rcContent.height - textSize.height) / 2;
|
||||
dc.SetTextForeground(text_color.colorForStates(states));
|
||||
#if 0
|
||||
dc.SetBrush(*wxLIGHT_GREY);
|
||||
dc.SetPen(wxPen(*wxLIGHT_GREY));
|
||||
dc.DrawRectangle(pt, textSize.GetSize());
|
||||
#endif
|
||||
#ifdef __WXOSX__
|
||||
pt.y -= textSize.x / 2;
|
||||
#endif
|
||||
dc.DrawText(text, pt);
|
||||
}
|
||||
}
|
||||
|
||||
void Button::messureSize()
|
||||
{
|
||||
wxClientDC dc(this);
|
||||
dc.GetTextExtent(GetLabel(), &textSize.width, &textSize.height, &textSize.x, &textSize.y);
|
||||
wxSize szContent = textSize.GetSize();
|
||||
if (this->active_icon.get_bitmap().IsOk()) {
|
||||
if (szContent.y > 0) {
|
||||
//BBS norrow size between text and icon
|
||||
szContent.x += 5;
|
||||
}
|
||||
wxSize szIcon = this->active_icon.GetSize();
|
||||
szContent.x += szIcon.x;
|
||||
if (szIcon.y > szContent.y)
|
||||
szContent.y = szIcon.y;
|
||||
}
|
||||
wxSize size = szContent + paddingSize * 2;
|
||||
if (minSize.GetHeight() > 0)
|
||||
size.SetHeight(minSize.GetHeight());
|
||||
|
||||
if (minSize.GetWidth() > size.GetWidth())
|
||||
wxWindow::SetMinSize(minSize);
|
||||
else
|
||||
wxWindow::SetMinSize(size);
|
||||
}
|
||||
|
||||
void Button::mouseDown(wxMouseEvent& event)
|
||||
{
|
||||
event.Skip();
|
||||
pressedDown = true;
|
||||
if (canFocus)
|
||||
SetFocus();
|
||||
if (!HasCapture())
|
||||
CaptureMouse();
|
||||
}
|
||||
|
||||
void Button::mouseReleased(wxMouseEvent& event)
|
||||
{
|
||||
event.Skip();
|
||||
if (pressedDown) {
|
||||
pressedDown = false;
|
||||
if (HasCapture())
|
||||
ReleaseMouse();
|
||||
if (wxRect({0, 0}, GetSize()).Contains(event.GetPosition()))
|
||||
sendButtonEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void Button::mouseCaptureLost(wxMouseCaptureLostEvent &event)
|
||||
{
|
||||
wxMouseEvent evt;
|
||||
mouseReleased(evt);
|
||||
}
|
||||
|
||||
void Button::keyDownUp(wxKeyEvent &event)
|
||||
{
|
||||
if (event.GetKeyCode() == WXK_SPACE || event.GetKeyCode() == WXK_RETURN) {
|
||||
wxMouseEvent evt(event.GetEventType() == wxEVT_KEY_UP ? wxEVT_LEFT_UP : wxEVT_LEFT_DOWN);
|
||||
event.SetEventObject(this);
|
||||
GetEventHandler()->ProcessEvent(evt);
|
||||
return;
|
||||
}
|
||||
if (event.GetEventType() == wxEVT_KEY_DOWN &&
|
||||
(event.GetKeyCode() == WXK_TAB || event.GetKeyCode() == WXK_LEFT || event.GetKeyCode() == WXK_RIGHT
|
||||
|| event.GetKeyCode() == WXK_UP || event.GetKeyCode() == WXK_DOWN))
|
||||
HandleAsNavigationKey(event);
|
||||
else
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void Button::sendButtonEvent()
|
||||
{
|
||||
wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
|
||||
event.SetEventObject(this);
|
||||
GetEventHandler()->ProcessEvent(event);
|
||||
}
|
||||
|
||||
#ifdef __WIN32__
|
||||
|
||||
WXLRESULT Button::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
|
||||
{
|
||||
if (nMsg == WM_GETDLGCODE) { return DLGC_WANTMESSAGE; }
|
||||
if (nMsg == WM_KEYDOWN) {
|
||||
wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, wParam, lParam));
|
||||
switch (wParam) {
|
||||
case WXK_RETURN: { // WXK_RETURN key is handled by default button
|
||||
GetEventHandler()->ProcessEvent(event);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return wxWindow::MSWWindowProc(nMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool Button::AcceptsFocus() const { return canFocus; }
|
||||
84
src/slic3r/GUI/Widgets/Button.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#ifndef slic3r_GUI_Button_hpp_
|
||||
#define slic3r_GUI_Button_hpp_
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
#include "StaticBox.hpp"
|
||||
|
||||
class Button : public StaticBox
|
||||
{
|
||||
wxRect textSize;
|
||||
wxSize minSize; // set by outer
|
||||
wxSize paddingSize;
|
||||
ScalableBitmap active_icon;
|
||||
ScalableBitmap inactive_icon;
|
||||
|
||||
StateColor text_color;
|
||||
|
||||
bool pressedDown = false;
|
||||
bool m_selected = true;
|
||||
bool canFocus = true;
|
||||
|
||||
static const int buttonWidth = 200;
|
||||
static const int buttonHeight = 50;
|
||||
|
||||
public:
|
||||
Button();
|
||||
|
||||
Button(wxWindow* parent, wxString text, wxString icon = "", long style = 0, int iconSize = 0, wxWindowID btn_id = wxID_ANY);
|
||||
|
||||
bool Create(wxWindow* parent, wxString text, wxString icon = "", long style = 0, int iconSize = 0, wxWindowID btn_id = wxID_ANY);
|
||||
|
||||
void SetLabel(const wxString& label) override;
|
||||
|
||||
bool SetFont(const wxFont& font) override;
|
||||
|
||||
void SetIcon(const wxString& icon);
|
||||
|
||||
void SetInactiveIcon(const wxString& icon);
|
||||
|
||||
void SetMinSize(const wxSize& size) override;
|
||||
|
||||
void SetPaddingSize(const wxSize& size);
|
||||
|
||||
void SetTextColor(StateColor const &color);
|
||||
|
||||
void SetTextColorNormal(wxColor const &color);
|
||||
|
||||
void SetSelected(bool selected = true) { m_selected = selected; }
|
||||
|
||||
bool Enable(bool enable = true) override;
|
||||
|
||||
void SetCanFocus(bool canFocus) override;
|
||||
|
||||
void SetValue(bool state);
|
||||
|
||||
bool GetValue() const;
|
||||
|
||||
void Rescale();
|
||||
|
||||
protected:
|
||||
#ifdef __WIN32__
|
||||
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
|
||||
#endif
|
||||
|
||||
bool AcceptsFocus() const override;
|
||||
|
||||
private:
|
||||
void paintEvent(wxPaintEvent& evt);
|
||||
|
||||
void render(wxDC& dc);
|
||||
|
||||
void messureSize();
|
||||
|
||||
// some useful events
|
||||
void mouseDown(wxMouseEvent& event);
|
||||
void mouseReleased(wxMouseEvent& event);
|
||||
void mouseCaptureLost(wxMouseCaptureLostEvent &event);
|
||||
void keyDownUp(wxKeyEvent &event);
|
||||
|
||||
void sendButtonEvent();
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_Button_hpp_
|
||||
125
src/slic3r/GUI/Widgets/CheckBoxInWT.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include "CheckBoxInWT.hpp"
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
|
||||
CheckBoxInWT::CheckBoxInWT(wxWindow *parent, int id)
|
||||
: wxBitmapToggleButton(parent, id, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)
|
||||
, m_on(this, "check_on", 18)
|
||||
, m_half(this, "check_half", 18)
|
||||
, m_off(this, "check_off", 18)
|
||||
, m_on_disabled(this, "check_on_disabled", 18)
|
||||
, m_half_disabled(this, "check_half_disabled", 18)
|
||||
, m_off_disabled(this, "check_off_disabled", 18)
|
||||
, m_on_focused(this, "check_on_focused", 18)
|
||||
, m_half_focused(this, "check_half_focused", 18)
|
||||
, m_off_focused(this, "check_off_focused", 18)
|
||||
{
|
||||
//SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
|
||||
if (parent)
|
||||
SetBackgroundColour(parent->GetBackgroundColour());
|
||||
Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { m_half_checked = false; update(); e.Skip(); });
|
||||
#ifdef __WXOSX__ // State not fully implement on MacOS
|
||||
Bind(wxEVT_SET_FOCUS, &CheckBoxInWT::updateBitmap, this);
|
||||
Bind(wxEVT_KILL_FOCUS, &CheckBoxInWT::updateBitmap, this);
|
||||
Bind(wxEVT_ENTER_WINDOW, &CheckBoxInWT::updateBitmap, this);
|
||||
Bind(wxEVT_LEAVE_WINDOW, &CheckBoxInWT::updateBitmap, this);
|
||||
#endif
|
||||
SetSize(m_on.GetSize());
|
||||
SetMinSize(m_on.GetSize());
|
||||
update();
|
||||
}
|
||||
|
||||
void CheckBoxInWT::SetValue(bool value)
|
||||
{
|
||||
wxBitmapToggleButton::SetValue(value);
|
||||
update();
|
||||
}
|
||||
|
||||
void CheckBoxInWT::SetHalfChecked(bool value)
|
||||
{
|
||||
m_half_checked = value;
|
||||
update();
|
||||
}
|
||||
|
||||
void CheckBoxInWT::Rescale()
|
||||
{
|
||||
m_on.msw_rescale();
|
||||
m_half.msw_rescale();
|
||||
m_off.msw_rescale();
|
||||
m_on_disabled.msw_rescale();
|
||||
m_half_disabled.msw_rescale();
|
||||
m_off_disabled.msw_rescale();
|
||||
m_on_focused.msw_rescale();
|
||||
m_half_focused.msw_rescale();
|
||||
m_off_focused.msw_rescale();
|
||||
SetSize(m_on.GetSize());
|
||||
update();
|
||||
}
|
||||
|
||||
void CheckBoxInWT::update()
|
||||
{
|
||||
SetBitmapLabel((m_half_checked ? m_half : GetValue() ? m_on : m_off).bmp());
|
||||
SetBitmapDisabled((m_half_checked ? m_half_disabled : GetValue() ? m_on_disabled : m_off_disabled).bmp());
|
||||
#ifdef __WXMSW__
|
||||
SetBitmapFocus((m_half_checked ? m_half_focused : GetValue() ? m_on_focused : m_off_focused).bmp());
|
||||
#endif
|
||||
SetBitmapCurrent((m_half_checked ? m_half_focused : GetValue() ? m_on_focused : m_off_focused).bmp());
|
||||
#ifdef __WXOSX__
|
||||
wxCommandEvent e(wxEVT_UPDATE_UI);
|
||||
updateBitmap(e);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __WXMSW__
|
||||
|
||||
CheckBoxInWT::State CheckBoxInWT::GetNormalState() const { return State_Normal; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __WXOSX__
|
||||
|
||||
bool CheckBoxInWT::Enable(bool enable)
|
||||
{
|
||||
bool result = wxBitmapToggleButton::Enable(enable);
|
||||
if (result) {
|
||||
m_disable = !enable;
|
||||
wxCommandEvent e(wxEVT_ACTIVATE);
|
||||
updateBitmap(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
wxBitmap CheckBoxInWT::DoGetBitmap(State which) const
|
||||
{
|
||||
if (m_disable) {
|
||||
return wxBitmapToggleButton::DoGetBitmap(State_Disabled);
|
||||
}
|
||||
if (m_focus) {
|
||||
return wxBitmapToggleButton::DoGetBitmap(State_Current);
|
||||
}
|
||||
return wxBitmapToggleButton::DoGetBitmap(which);
|
||||
}
|
||||
|
||||
void CheckBoxInWT::updateBitmap(wxEvent &evt)
|
||||
{
|
||||
evt.Skip();
|
||||
if (evt.GetEventType() == wxEVT_ENTER_WINDOW) {
|
||||
m_hover = true;
|
||||
} else if (evt.GetEventType() == wxEVT_LEAVE_WINDOW) {
|
||||
m_hover = false;
|
||||
} else {
|
||||
if (evt.GetEventType() == wxEVT_SET_FOCUS) {
|
||||
m_focus = true;
|
||||
} else if (evt.GetEventType() == wxEVT_KILL_FOCUS) {
|
||||
m_focus = false;
|
||||
}
|
||||
wxMouseEvent e;
|
||||
if (m_hover)
|
||||
OnEnterWindow(e);
|
||||
else
|
||||
OnLeaveWindow(e);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
55
src/slic3r/GUI/Widgets/CheckBoxInWT.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef slic3r_GUI_CheckBoxInWT_hpp_
|
||||
#define slic3r_GUI_CheckBoxInWT_hpp_
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
|
||||
#include <wx/tglbtn.h>
|
||||
|
||||
class CheckBoxInWT : public wxBitmapToggleButton
|
||||
{
|
||||
public:
|
||||
CheckBoxInWT(wxWindow *parent, int id = wxID_ANY);
|
||||
|
||||
public:
|
||||
void SetValue(bool value) override;
|
||||
|
||||
void SetHalfChecked(bool value = true);
|
||||
|
||||
void Rescale();
|
||||
|
||||
#ifdef __WXOSX__
|
||||
virtual bool Enable(bool enable = true) wxOVERRIDE;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
#ifdef __WXMSW__
|
||||
virtual State GetNormalState() const wxOVERRIDE;
|
||||
#endif
|
||||
|
||||
#ifdef __WXOSX__
|
||||
virtual wxBitmap DoGetBitmap(State which) const wxOVERRIDE;
|
||||
|
||||
void updateBitmap(wxEvent & evt);
|
||||
|
||||
bool m_disable = false;
|
||||
bool m_hover = false;
|
||||
bool m_focus = false;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void update();
|
||||
|
||||
private:
|
||||
ScalableBitmap m_on;
|
||||
ScalableBitmap m_half;
|
||||
ScalableBitmap m_off;
|
||||
ScalableBitmap m_on_disabled;
|
||||
ScalableBitmap m_half_disabled;
|
||||
ScalableBitmap m_off_disabled;
|
||||
ScalableBitmap m_on_focused;
|
||||
ScalableBitmap m_half_focused;
|
||||
ScalableBitmap m_off_focused;
|
||||
bool m_half_checked = false;
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_CheckBoxInWT_hpp_
|
||||
309
src/slic3r/GUI/Widgets/ComboBox.cpp
Normal file
@@ -0,0 +1,309 @@
|
||||
#include "ComboBox.hpp"
|
||||
#include "Label.hpp"
|
||||
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
BEGIN_EVENT_TABLE(ComboBox, TextInput)
|
||||
|
||||
EVT_LEFT_DOWN(ComboBox::mouseDown)
|
||||
EVT_LEFT_DCLICK(ComboBox::mouseDown)
|
||||
//EVT_MOUSEWHEEL(ComboBox::mouseWheelMoved)
|
||||
EVT_KEY_DOWN(ComboBox::keyDown)
|
||||
|
||||
// catch paint events
|
||||
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().
|
||||
*/
|
||||
|
||||
ComboBox::ComboBox(wxWindow * parent,
|
||||
wxWindowID id,
|
||||
const wxString &value,
|
||||
const wxPoint & pos,
|
||||
const wxSize & size,
|
||||
int n,
|
||||
const wxString choices[],
|
||||
long style)
|
||||
: drop(texts, icons)
|
||||
{
|
||||
if (style & wxCB_READONLY)
|
||||
style |= wxRIGHT;
|
||||
text_off = style & CB_NO_TEXT;
|
||||
TextInput::Create(parent, "", value, (style & CB_NO_DROP_ICON) ? "" : "drop_down", pos, size,
|
||||
style | wxTE_PROCESS_ENTER);
|
||||
drop.Create(this, style & DD_STYLE_MASK);
|
||||
|
||||
if (style & wxCB_READONLY) {
|
||||
GetTextCtrl()->Hide();
|
||||
TextInput::SetFont(Label::Body_14);
|
||||
TextInput::SetBorderColor(StateColor(std::make_pair(0xDBDBDB, (int) StateColor::Disabled),
|
||||
std::make_pair(0x009688, (int) StateColor::Hovered),
|
||||
std::make_pair(0xDBDBDB, (int) StateColor::Normal)));
|
||||
TextInput::SetBackgroundColor(StateColor(std::make_pair(0xF0F0F1, (int) StateColor::Disabled),
|
||||
std::make_pair(0xEDFAF2, (int) StateColor::Focused),
|
||||
std::make_pair(*wxWHITE, (int) StateColor::Normal)));
|
||||
TextInput::SetLabelColor(StateColor(std::make_pair(0x909090, (int) StateColor::Disabled),
|
||||
std::make_pair(0x262E30, (int) StateColor::Normal)));
|
||||
} else {
|
||||
GetTextCtrl()->Bind(wxEVT_KEY_DOWN, &ComboBox::keyDown, this);
|
||||
}
|
||||
drop.Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &e) {
|
||||
SetSelection(e.GetInt());
|
||||
e.SetEventObject(this);
|
||||
e.SetId(GetId());
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
});
|
||||
drop.Bind(EVT_DISMISS, [this](auto &) {
|
||||
drop_down = false;
|
||||
wxCommandEvent e(wxEVT_COMBOBOX_CLOSEUP);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
});
|
||||
for (int i = 0; i < n; ++i) Append(choices[i]);
|
||||
}
|
||||
|
||||
int ComboBox::GetSelection() const { return drop.GetSelection(); }
|
||||
|
||||
void ComboBox::SetSelection(int n)
|
||||
{
|
||||
drop.SetSelection(n);
|
||||
SetLabel(drop.GetValue());
|
||||
if (drop.selection >= 0)
|
||||
SetIcon(icons[drop.selection]);
|
||||
}
|
||||
|
||||
void ComboBox::SelectAndNotify(int n) {
|
||||
SetSelection(n);
|
||||
sendComboBoxEvent();
|
||||
}
|
||||
|
||||
|
||||
void ComboBox::Rescale()
|
||||
{
|
||||
TextInput::Rescale();
|
||||
drop.Rescale();
|
||||
}
|
||||
|
||||
wxString ComboBox::GetValue() const
|
||||
{
|
||||
return drop.GetSelection() >= 0 ? drop.GetValue() : GetLabel();
|
||||
}
|
||||
|
||||
void ComboBox::SetValue(const wxString &value)
|
||||
{
|
||||
drop.SetValue(value);
|
||||
SetLabel(value);
|
||||
if (drop.selection >= 0)
|
||||
SetIcon(icons[drop.selection]);
|
||||
}
|
||||
|
||||
void ComboBox::SetLabel(const wxString &value)
|
||||
{
|
||||
if (GetTextCtrl()->IsShown() || text_off)
|
||||
GetTextCtrl()->SetValue(value);
|
||||
else
|
||||
TextInput::SetLabel(value);
|
||||
}
|
||||
|
||||
wxString ComboBox::GetLabel() const
|
||||
{
|
||||
if (GetTextCtrl()->IsShown() || text_off)
|
||||
return GetTextCtrl()->GetValue();
|
||||
else
|
||||
return TextInput::GetLabel();
|
||||
}
|
||||
|
||||
void ComboBox::SetTextLabel(const wxString& label)
|
||||
{
|
||||
TextInput::SetLabel(label);
|
||||
}
|
||||
|
||||
wxString ComboBox::GetTextLabel() const
|
||||
{
|
||||
return TextInput::GetLabel();
|
||||
}
|
||||
|
||||
bool ComboBox::SetFont(wxFont const& font)
|
||||
{
|
||||
if (GetTextCtrl() && GetTextCtrl()->IsShown())
|
||||
return GetTextCtrl()->SetFont(font);
|
||||
else
|
||||
return TextInput::SetFont(font);
|
||||
}
|
||||
|
||||
int ComboBox::Append(const wxString &item, const wxBitmap &bitmap)
|
||||
{
|
||||
return Append(item, bitmap, nullptr);
|
||||
}
|
||||
|
||||
int ComboBox::Append(const wxString &item,
|
||||
const wxBitmap &bitmap,
|
||||
void * clientData)
|
||||
{
|
||||
texts.push_back(item);
|
||||
icons.push_back(bitmap);
|
||||
datas.push_back(clientData);
|
||||
types.push_back(wxClientData_None);
|
||||
drop.Invalidate();
|
||||
return texts.size() - 1;
|
||||
}
|
||||
|
||||
void ComboBox::DoClear()
|
||||
{
|
||||
texts.clear();
|
||||
icons.clear();
|
||||
datas.clear();
|
||||
types.clear();
|
||||
drop.Invalidate(true);
|
||||
}
|
||||
|
||||
void ComboBox::DoDeleteOneItem(unsigned int pos)
|
||||
{
|
||||
if (pos >= texts.size()) return;
|
||||
texts.erase(texts.begin() + pos);
|
||||
icons.erase(icons.begin() + pos);
|
||||
datas.erase(datas.begin() + pos);
|
||||
types.erase(types.begin() + pos);
|
||||
drop.Invalidate(true);
|
||||
}
|
||||
|
||||
unsigned int ComboBox::GetCount() const { return texts.size(); }
|
||||
|
||||
wxString ComboBox::GetString(unsigned int n) const
|
||||
{
|
||||
return n < texts.size() ? texts[n] : wxString{};
|
||||
}
|
||||
|
||||
void ComboBox::SetString(unsigned int n, wxString const &value)
|
||||
{
|
||||
if (n >= texts.size()) return;
|
||||
texts[n] = value;
|
||||
drop.Invalidate();
|
||||
if (n == drop.GetSelection()) SetLabel(value);
|
||||
}
|
||||
|
||||
wxBitmap ComboBox::GetItemBitmap(unsigned int n) { return icons[n]; }
|
||||
|
||||
void ComboBox::SetItemBitmap(unsigned int n, wxBitmap const &bitmap)
|
||||
{
|
||||
if (n >= texts.size()) return;
|
||||
icons[n] = bitmap;
|
||||
drop.Invalidate();
|
||||
}
|
||||
|
||||
int ComboBox::DoInsertItems(const wxArrayStringsAdapter &items,
|
||||
unsigned int pos,
|
||||
void ** clientData,
|
||||
wxClientDataType type)
|
||||
{
|
||||
if (pos > texts.size()) return -1;
|
||||
for (int i = 0; i < items.GetCount(); ++i) {
|
||||
texts.insert(texts.begin() + pos, items[i]);
|
||||
icons.insert(icons.begin() + pos, wxNullBitmap);
|
||||
datas.insert(datas.begin() + pos, clientData ? clientData[i] : NULL);
|
||||
types.insert(types.begin() + pos, type);
|
||||
++pos;
|
||||
}
|
||||
drop.Invalidate(true);
|
||||
return pos - 1;
|
||||
}
|
||||
|
||||
void *ComboBox::DoGetItemClientData(unsigned int n) const { return n < texts.size() ? datas[n] : NULL; }
|
||||
|
||||
void ComboBox::DoSetItemClientData(unsigned int n, void *data)
|
||||
{
|
||||
if (n < texts.size())
|
||||
datas[n] = data;
|
||||
}
|
||||
|
||||
void ComboBox::mouseDown(wxMouseEvent &event)
|
||||
{
|
||||
SetFocus();
|
||||
if (drop_down) {
|
||||
drop.Hide();
|
||||
} else if (drop.HasDismissLongTime()) {
|
||||
drop.autoPosition();
|
||||
drop_down = true;
|
||||
drop.Popup(&drop);
|
||||
wxCommandEvent e(wxEVT_COMBOBOX_DROPDOWN);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void ComboBox::mouseWheelMoved(wxMouseEvent &event)
|
||||
{
|
||||
event.Skip();
|
||||
if (drop_down) return;
|
||||
auto delta = event.GetWheelRotation() < 0 ? 1 : -1;
|
||||
unsigned int n = GetSelection() + delta;
|
||||
if (n < GetCount()) {
|
||||
SetSelection((int) n);
|
||||
sendComboBoxEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void ComboBox::keyDown(wxKeyEvent& event)
|
||||
{
|
||||
switch (event.GetKeyCode()) {
|
||||
case WXK_RETURN:
|
||||
case WXK_SPACE:
|
||||
if (drop_down) {
|
||||
drop.DismissAndNotify();
|
||||
} else if (drop.HasDismissLongTime()) {
|
||||
drop.autoPosition();
|
||||
drop_down = true;
|
||||
drop.Popup();
|
||||
wxCommandEvent e(wxEVT_COMBOBOX_DROPDOWN);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
}
|
||||
break;
|
||||
case WXK_UP:
|
||||
case WXK_DOWN:
|
||||
case WXK_LEFT:
|
||||
case WXK_RIGHT:
|
||||
if ((event.GetKeyCode() == WXK_UP || event.GetKeyCode() == WXK_LEFT) && GetSelection() > 0) {
|
||||
SetSelection(GetSelection() - 1);
|
||||
} else if ((event.GetKeyCode() == WXK_DOWN || event.GetKeyCode() == WXK_RIGHT) && GetSelection() + 1 < texts.size()) {
|
||||
SetSelection(GetSelection() + 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
sendComboBoxEvent();
|
||||
break;
|
||||
case WXK_TAB:
|
||||
HandleAsNavigationKey(event);
|
||||
break;
|
||||
default:
|
||||
event.Skip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ComboBox::OnEdit()
|
||||
{
|
||||
auto value = GetTextCtrl()->GetValue();
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
#ifdef __WIN32__
|
||||
|
||||
WXLRESULT ComboBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
|
||||
{
|
||||
if (nMsg == WM_GETDLGCODE) {
|
||||
return DLGC_WANTALLKEYS;
|
||||
}
|
||||
return TextInput::MSWWindowProc(nMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ComboBox::sendComboBoxEvent()
|
||||
{
|
||||
wxCommandEvent event(wxEVT_COMBOBOX, GetId());
|
||||
event.SetEventObject(this);
|
||||
event.SetInt(drop.GetSelection());
|
||||
event.SetString(drop.GetValue());
|
||||
GetEventHandler()->ProcessEvent(event);
|
||||
}
|
||||
95
src/slic3r/GUI/Widgets/ComboBox.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#ifndef slic3r_GUI_ComboBox_hpp_
|
||||
#define slic3r_GUI_ComboBox_hpp_
|
||||
|
||||
#include "TextInput.hpp"
|
||||
#include "DropDown.hpp"
|
||||
|
||||
#define CB_NO_DROP_ICON DD_NO_CHECK_ICON
|
||||
#define CB_NO_TEXT DD_NO_TEXT
|
||||
|
||||
class ComboBox : public wxWindowWithItems<TextInput, wxItemContainer>
|
||||
{
|
||||
std::vector<wxString> texts;
|
||||
std::vector<wxBitmap> icons;
|
||||
std::vector<void *> datas;
|
||||
std::vector<wxClientDataType> types;
|
||||
|
||||
DropDown drop;
|
||||
bool drop_down = false;
|
||||
bool text_off = false;
|
||||
|
||||
public:
|
||||
ComboBox(wxWindow * parent,
|
||||
wxWindowID id,
|
||||
const wxString &value = wxEmptyString,
|
||||
const wxPoint & pos = wxDefaultPosition,
|
||||
const wxSize & size = wxDefaultSize,
|
||||
int n = 0,
|
||||
const wxString choices[] = NULL,
|
||||
long style = 0);
|
||||
|
||||
DropDown & GetDropDown() { return drop; }
|
||||
|
||||
virtual bool SetFont(wxFont const & font) override;
|
||||
|
||||
public:
|
||||
int Append(const wxString &item, const wxBitmap &bitmap = wxNullBitmap);
|
||||
|
||||
int Append(const wxString &item, const wxBitmap &bitmap, void *clientData);
|
||||
|
||||
unsigned int GetCount() const override;
|
||||
|
||||
int GetSelection() const override;
|
||||
|
||||
void SetSelection(int n) override;
|
||||
|
||||
void SelectAndNotify(int n);
|
||||
|
||||
virtual void Rescale() override;
|
||||
|
||||
wxString GetValue() const;
|
||||
void SetValue(const wxString &value);
|
||||
|
||||
void SetLabel(const wxString &label) override;
|
||||
wxString GetLabel() const override;
|
||||
|
||||
void SetTextLabel(const wxString &label);
|
||||
wxString GetTextLabel() const;
|
||||
|
||||
wxString GetString(unsigned int n) const override;
|
||||
void SetString(unsigned int n, wxString const &value) override;
|
||||
|
||||
wxBitmap GetItemBitmap(unsigned int n);
|
||||
void SetItemBitmap(unsigned int n, wxBitmap const &bitmap);
|
||||
|
||||
protected:
|
||||
virtual int DoInsertItems(const wxArrayStringsAdapter &items,
|
||||
unsigned int pos,
|
||||
void ** clientData,
|
||||
wxClientDataType type) override;
|
||||
virtual void DoClear() override;
|
||||
|
||||
void DoDeleteOneItem(unsigned int pos) override;
|
||||
|
||||
void *DoGetItemClientData(unsigned int n) const override;
|
||||
void DoSetItemClientData(unsigned int n, void *data) override;
|
||||
|
||||
void OnEdit() override;
|
||||
|
||||
void sendComboBoxEvent();
|
||||
|
||||
#ifdef __WIN32__
|
||||
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
// some useful events
|
||||
void mouseDown(wxMouseEvent &event);
|
||||
void mouseWheelMoved(wxMouseEvent &event);
|
||||
void keyDown(wxKeyEvent &event);
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_ComboBox_hpp_
|
||||
492
src/slic3r/GUI/Widgets/DropDown.cpp
Normal file
@@ -0,0 +1,492 @@
|
||||
#include "DropDown.hpp"
|
||||
#include "Label.hpp"
|
||||
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
#ifdef __WXGTK__
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
wxDEFINE_EVENT(EVT_DISMISS, wxCommandEvent);
|
||||
|
||||
BEGIN_EVENT_TABLE(DropDown, PopupWindow)
|
||||
|
||||
EVT_LEFT_DOWN(DropDown::mouseDown)
|
||||
EVT_LEFT_UP(DropDown::mouseReleased)
|
||||
EVT_MOUSE_CAPTURE_LOST(DropDown::mouseCaptureLost)
|
||||
EVT_MOTION(DropDown::mouseMove)
|
||||
EVT_MOUSEWHEEL(DropDown::mouseWheelMoved)
|
||||
|
||||
// catch paint events
|
||||
EVT_PAINT(DropDown::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().
|
||||
*/
|
||||
|
||||
DropDown::DropDown(std::vector<wxString> &texts,
|
||||
std::vector<wxBitmap> &icons)
|
||||
: texts(texts)
|
||||
, icons(icons)
|
||||
, state_handler(this)
|
||||
, border_color(0xDBDBDB)
|
||||
, text_color(0x363636)
|
||||
, selector_border_color(std::make_pair(0x009688, (int) StateColor::Hovered),
|
||||
std::make_pair(*wxWHITE, (int) StateColor::Normal))
|
||||
, selector_background_color(std::make_pair(0xEDFAF2, (int) StateColor::Checked),
|
||||
std::make_pair(*wxWHITE, (int) StateColor::Normal))
|
||||
{
|
||||
}
|
||||
|
||||
DropDown::DropDown(wxWindow * parent,
|
||||
std::vector<wxString> &texts,
|
||||
std::vector<wxBitmap> &icons,
|
||||
long style)
|
||||
: DropDown(texts, icons)
|
||||
{
|
||||
Create(parent, style);
|
||||
}
|
||||
|
||||
void DropDown::Create(wxWindow * parent,
|
||||
long style)
|
||||
{
|
||||
PopupWindow::Create(parent, wxPU_CONTAINS_CONTROLS);
|
||||
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
state_handler.attach({&border_color, &text_color, &selector_border_color, &selector_background_color});
|
||||
state_handler.update_binds();
|
||||
if ((style & DD_NO_CHECK_ICON) == 0)
|
||||
check_bitmap = ScalableBitmap(this, "checked", 16);
|
||||
text_off = style & DD_NO_TEXT;
|
||||
|
||||
// BBS set default font
|
||||
SetFont(Label::Body_14);
|
||||
#ifdef __WXOSX__
|
||||
// PopupWindow releases mouse on idle, which may cause various problems,
|
||||
// such as losting mouse move, and dismissing soon on first LEFT_DOWN event.
|
||||
Bind(wxEVT_IDLE, [] (wxIdleEvent & evt) {});
|
||||
#endif
|
||||
}
|
||||
|
||||
void DropDown::Invalidate(bool clear)
|
||||
{
|
||||
if (clear) {
|
||||
selection = hover_item = -1;
|
||||
offset = wxPoint();
|
||||
}
|
||||
assert(selection < (int) texts.size());
|
||||
need_sync = true;
|
||||
}
|
||||
|
||||
void DropDown::SetSelection(int n)
|
||||
{
|
||||
assert(n < (int) texts.size());
|
||||
if (n >= (int) texts.size())
|
||||
n = -1;
|
||||
if (selection == n) return;
|
||||
selection = n;
|
||||
paintNow();
|
||||
}
|
||||
|
||||
wxString DropDown::GetValue() const
|
||||
{
|
||||
return selection >= 0 ? texts[selection] : wxString();
|
||||
}
|
||||
|
||||
void DropDown::SetValue(const wxString &value)
|
||||
{
|
||||
auto i = std::find(texts.begin(), texts.end(), value);
|
||||
selection = i == texts.end() ? -1 : std::distance(texts.begin(), i);
|
||||
}
|
||||
|
||||
void DropDown::SetCornerRadius(double radius)
|
||||
{
|
||||
this->radius = radius;
|
||||
paintNow();
|
||||
}
|
||||
|
||||
void DropDown::SetBorderColor(StateColor const &color)
|
||||
{
|
||||
border_color = color;
|
||||
state_handler.update_binds();
|
||||
paintNow();
|
||||
}
|
||||
|
||||
void DropDown::SetSelectorBorderColor(StateColor const &color)
|
||||
{
|
||||
selector_border_color = color;
|
||||
state_handler.update_binds();
|
||||
paintNow();
|
||||
}
|
||||
|
||||
void DropDown::SetTextColor(StateColor const &color)
|
||||
{
|
||||
text_color = color;
|
||||
state_handler.update_binds();
|
||||
paintNow();
|
||||
}
|
||||
|
||||
void DropDown::SetSelectorBackgroundColor(StateColor const &color)
|
||||
{
|
||||
selector_background_color = color;
|
||||
state_handler.update_binds();
|
||||
paintNow();
|
||||
}
|
||||
|
||||
void DropDown::SetUseContentWidth(bool use)
|
||||
{
|
||||
if (use_content_width == use)
|
||||
return;
|
||||
use_content_width = use;
|
||||
need_sync = true;
|
||||
messureSize();
|
||||
}
|
||||
|
||||
void DropDown::SetAlignIcon(bool align) { align_icon = align; }
|
||||
|
||||
void DropDown::Rescale()
|
||||
{
|
||||
need_sync = true;
|
||||
}
|
||||
|
||||
bool DropDown::HasDismissLongTime()
|
||||
{
|
||||
auto now = boost::posix_time::microsec_clock::universal_time();
|
||||
return !IsShown() &&
|
||||
(now - dismissTime).total_milliseconds() >= 20;
|
||||
}
|
||||
|
||||
void DropDown::paintEvent(wxPaintEvent& evt)
|
||||
{
|
||||
// depending on your system you may need to look at double-buffered dcs
|
||||
wxBufferedPaintDC dc(this);
|
||||
render(dc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Alternatively, you can use a clientDC to paint on the panel
|
||||
* at any time. Using this generally does not free you from
|
||||
* catching paint events, since it is possible that e.g. the window
|
||||
* manager throws away your drawing when the window comes to the
|
||||
* background, and expects you will redraw it when the window comes
|
||||
* back (by sending a paint event).
|
||||
*/
|
||||
void DropDown::paintNow()
|
||||
{
|
||||
// depending on your system you may need to look at double-buffered dcs
|
||||
//wxClientDC dc(this);
|
||||
//render(dc);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
static wxSize GetBmpSize(wxBitmap & bmp)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
return bmp.GetScaledSize();
|
||||
#else
|
||||
return bmp.GetSize();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 DropDown::render(wxDC &dc)
|
||||
{
|
||||
if (texts.size() == 0) return;
|
||||
int states = state_handler.states();
|
||||
dc.SetPen(wxPen(border_color.colorForStates(states)));
|
||||
dc.SetBrush(wxBrush(StateColor::darkModeColorFor(GetBackgroundColour())));
|
||||
// if (GetWindowStyle() & wxBORDER_NONE)
|
||||
// dc.SetPen(wxNullPen);
|
||||
|
||||
// draw background
|
||||
wxSize size = GetSize();
|
||||
if (radius == 0)
|
||||
dc.DrawRectangle(0, 0, size.x, size.y);
|
||||
else
|
||||
dc.DrawRoundedRectangle(0, 0, size.x, size.y, radius);
|
||||
|
||||
// draw hover rectangle
|
||||
wxRect rcContent = {{0, offset.y}, rowSize};
|
||||
if (hover_item >= 0 && (states & StateColor::Hovered)) {
|
||||
rcContent.y += rowSize.y * hover_item;
|
||||
if (rcContent.GetBottom() > 0 && rcContent.y < size.y) {
|
||||
if (selection == hover_item)
|
||||
dc.SetBrush(wxBrush(selector_background_color.colorForStates(states | StateColor::Checked)));
|
||||
dc.SetPen(wxPen(selector_border_color.colorForStates(states)));
|
||||
rcContent.Deflate(4, 1);
|
||||
dc.DrawRectangle(rcContent);
|
||||
rcContent.Inflate(4, 1);
|
||||
}
|
||||
rcContent.y = offset.y;
|
||||
}
|
||||
// draw checked rectangle
|
||||
if (selection >= 0 && (selection != hover_item || (states & StateColor::Hovered) == 0)) {
|
||||
rcContent.y += rowSize.y * selection;
|
||||
if (rcContent.GetBottom() > 0 && rcContent.y < size.y) {
|
||||
dc.SetBrush(wxBrush(selector_background_color.colorForStates(states | StateColor::Checked)));
|
||||
dc.SetPen(wxPen(selector_background_color.colorForStates(states)));
|
||||
rcContent.Deflate(4, 1);
|
||||
dc.DrawRectangle(rcContent);
|
||||
rcContent.Inflate(4, 1);
|
||||
}
|
||||
rcContent.y = offset.y;
|
||||
}
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
{
|
||||
wxSize offset = (rowSize - textSize) / 2;
|
||||
rcContent.Deflate(0, offset.y);
|
||||
}
|
||||
|
||||
// draw position bar
|
||||
if (rowSize.y * texts.size() > size.y) {
|
||||
int height = rowSize.y * texts.size();
|
||||
wxRect rect = {size.x - 6, -offset.y * size.y / height, 4,
|
||||
size.y * size.y / height};
|
||||
dc.SetPen(wxPen(border_color.defaultColor()));
|
||||
dc.SetBrush(wxBrush(*wxLIGHT_GREY));
|
||||
dc.DrawRoundedRectangle(rect, 2);
|
||||
rcContent.width -= 6;
|
||||
}
|
||||
|
||||
// draw check icon
|
||||
rcContent.x += 5;
|
||||
rcContent.width -= 5;
|
||||
if (check_bitmap.get_bitmap().IsOk()) {
|
||||
auto szBmp = check_bitmap.GetSize();
|
||||
if (selection >= 0) {
|
||||
wxPoint pt = rcContent.GetLeftTop();
|
||||
pt.y += (rcContent.height - szBmp.y) / 2;
|
||||
pt.y += rowSize.y * selection;
|
||||
if (pt.y + szBmp.y > 0 && pt.y < size.y)
|
||||
dc.DrawBitmap(check_bitmap.get_bitmap(), pt);
|
||||
}
|
||||
rcContent.x += szBmp.x + 5;
|
||||
rcContent.width -= szBmp.x + 5;
|
||||
}
|
||||
// draw texts & icons
|
||||
dc.SetTextForeground(text_color.colorForStates(states));
|
||||
for (int i = 0; i < texts.size(); ++i) {
|
||||
if (rcContent.GetBottom() < 0) {
|
||||
rcContent.y += rowSize.y;
|
||||
continue;
|
||||
}
|
||||
if (rcContent.y > size.y) break;
|
||||
wxPoint pt = rcContent.GetLeftTop();
|
||||
auto & icon = icons[i];
|
||||
auto size2 = GetBmpSize(icon);
|
||||
if (iconSize.x > 0) {
|
||||
if (icon.IsOk()) {
|
||||
pt.y += (rcContent.height - size2.y) / 2;
|
||||
dc.DrawBitmap(icon, pt);
|
||||
}
|
||||
pt.x += iconSize.x + 5;
|
||||
pt.y = rcContent.y;
|
||||
} else if (icon.IsOk()) {
|
||||
pt.y += (rcContent.height - size2.y) / 2;
|
||||
dc.DrawBitmap(icon, pt);
|
||||
pt.x += size2.x + 5;
|
||||
pt.y = rcContent.y;
|
||||
}
|
||||
auto text = texts[i];
|
||||
if (!text_off && !text.IsEmpty()) {
|
||||
wxSize tSize = dc.GetMultiLineTextExtent(text);
|
||||
if (pt.x + tSize.x > rcContent.GetRight()) {
|
||||
text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END,
|
||||
rcContent.GetRight() - pt.x);
|
||||
}
|
||||
pt.y += (rcContent.height - textSize.y) / 2;
|
||||
dc.SetFont(GetFont());
|
||||
dc.DrawText(text, pt);
|
||||
}
|
||||
rcContent.y += rowSize.y;
|
||||
}
|
||||
}
|
||||
|
||||
void DropDown::messureSize()
|
||||
{
|
||||
if (!need_sync) return;
|
||||
textSize = wxSize();
|
||||
iconSize = wxSize();
|
||||
wxClientDC dc(GetParent() ? GetParent() : this);
|
||||
for (size_t i = 0; i < texts.size(); ++i) {
|
||||
wxSize size1 = text_off ? wxSize() : dc.GetMultiLineTextExtent(texts[i]);
|
||||
if (icons[i].IsOk()) {
|
||||
wxSize size2 = GetBmpSize(icons[i]);
|
||||
if (size2.x > iconSize.x) iconSize = size2;
|
||||
if (!align_icon) {
|
||||
size1.x += size2.x + (text_off ? 0 : 5);
|
||||
}
|
||||
}
|
||||
if (size1.x > textSize.x) textSize = size1;
|
||||
}
|
||||
if (!align_icon) iconSize.x = 0;
|
||||
wxSize szContent = textSize;
|
||||
szContent.x += 10;
|
||||
if (check_bitmap.get_bitmap().IsOk()) {
|
||||
auto szBmp = check_bitmap.GetSize();
|
||||
szContent.x += szBmp.x + 5;
|
||||
}
|
||||
if (iconSize.x > 0) szContent.x += iconSize.x + (text_off ? 0 : 5);
|
||||
if (iconSize.y > szContent.y) szContent.y = iconSize.y;
|
||||
szContent.y += 10;
|
||||
if (texts.size() > 15) szContent.x += 6;
|
||||
if (GetParent()) {
|
||||
auto x = GetParent()->GetSize().x;
|
||||
if (!use_content_width || x > szContent.x)
|
||||
szContent.x = x;
|
||||
}
|
||||
rowSize = szContent;
|
||||
szContent.y *= std::min((size_t)15, texts.size());
|
||||
szContent.y += texts.size() > 15 ? rowSize.y / 2 : 0;
|
||||
wxWindow::SetSize(szContent);
|
||||
#ifdef __WXGTK__
|
||||
// Gtk has a wrapper window for popup widget
|
||||
gtk_window_resize (GTK_WINDOW (m_widget), szContent.x, szContent.y);
|
||||
#endif
|
||||
need_sync = false;
|
||||
}
|
||||
|
||||
void DropDown::autoPosition()
|
||||
{
|
||||
messureSize();
|
||||
wxPoint pos = GetParent()->ClientToScreen(wxPoint(0, -6));
|
||||
wxPoint old = GetPosition();
|
||||
wxSize size = GetSize();
|
||||
Position(pos, {0, GetParent()->GetSize().y + 12});
|
||||
if (old != GetPosition()) {
|
||||
size = rowSize;
|
||||
size.y *= std::min((size_t)15, texts.size());
|
||||
size.y += texts.size() > 15 ? rowSize.y / 2 : 0;
|
||||
if (size != GetSize()) {
|
||||
wxWindow::SetSize(size);
|
||||
offset = wxPoint();
|
||||
Position(pos, {0, GetParent()->GetSize().y + 12});
|
||||
}
|
||||
}
|
||||
if (GetPosition().y > pos.y) {
|
||||
// may exceed
|
||||
auto drect = wxDisplay(GetParent()).GetGeometry();
|
||||
if (GetPosition().y + size.y + 10 > drect.GetBottom()) {
|
||||
if (use_content_width && texts.size() <= 15) size.x += 6;
|
||||
size.y = drect.GetBottom() - GetPosition().y - 10;
|
||||
wxWindow::SetSize(size);
|
||||
if (selection >= 0) {
|
||||
if (offset.y + rowSize.y * (selection + 1) > size.y)
|
||||
offset.y = size.y - rowSize.y * (selection + 1);
|
||||
else if (offset.y + rowSize.y * selection < 0)
|
||||
offset.y = -rowSize.y * selection;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DropDown::mouseDown(wxMouseEvent& event)
|
||||
{
|
||||
// Receivce unexcepted LEFT_DOWN on Mac after OnDismiss
|
||||
if (!IsShown())
|
||||
return;
|
||||
// force calc hover item again
|
||||
mouseMove(event);
|
||||
pressedDown = true;
|
||||
CaptureMouse();
|
||||
dragStart = event.GetPosition();
|
||||
}
|
||||
|
||||
void DropDown::mouseReleased(wxMouseEvent& event)
|
||||
{
|
||||
if (pressedDown) {
|
||||
dragStart = wxPoint();
|
||||
pressedDown = false;
|
||||
if (HasCapture())
|
||||
ReleaseMouse();
|
||||
if (hover_item >= 0) { // not moved
|
||||
sendDropDownEvent();
|
||||
DismissAndNotify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DropDown::mouseCaptureLost(wxMouseCaptureLostEvent &event)
|
||||
{
|
||||
wxMouseEvent evt;
|
||||
mouseReleased(evt);
|
||||
}
|
||||
|
||||
void DropDown::mouseMove(wxMouseEvent &event)
|
||||
{
|
||||
wxPoint pt = event.GetPosition();
|
||||
if (pressedDown) {
|
||||
wxPoint pt2 = offset + pt - dragStart;
|
||||
wxSize size = GetSize();
|
||||
dragStart = pt;
|
||||
if (pt2.y > 0)
|
||||
pt2.y = 0;
|
||||
else if (pt2.y + rowSize.y * int(texts.size()) < size.y)
|
||||
pt2.y = size.y - rowSize.y * int(texts.size());
|
||||
if (pt2.y != offset.y) {
|
||||
offset = pt2;
|
||||
hover_item = -1; // moved
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!pressedDown || hover_item >= 0) {
|
||||
int hover = (pt.y - offset.y) / rowSize.y;
|
||||
if (hover >= (int) texts.size()) hover = -1;
|
||||
if (hover == hover_item) return;
|
||||
hover_item = hover;
|
||||
if (hover >= 0)
|
||||
SetToolTip(texts[hover]);
|
||||
}
|
||||
paintNow();
|
||||
}
|
||||
|
||||
void DropDown::mouseWheelMoved(wxMouseEvent &event)
|
||||
{
|
||||
auto delta = event.GetWheelRotation();
|
||||
wxSize size = GetSize();
|
||||
wxPoint pt2 = offset + wxPoint{0, delta};
|
||||
if (pt2.y > 0)
|
||||
pt2.y = 0;
|
||||
else if (pt2.y + rowSize.y * int(texts.size()) < size.y)
|
||||
pt2.y = size.y - rowSize.y * int(texts.size());
|
||||
if (pt2.y != offset.y) {
|
||||
offset = pt2;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
int hover = (event.GetPosition().y - offset.y) / rowSize.y;
|
||||
if (hover >= (int) texts.size()) hover = -1;
|
||||
if (hover != hover_item) {
|
||||
hover_item = hover;
|
||||
if (hover >= 0) SetToolTip(texts[hover]);
|
||||
}
|
||||
paintNow();
|
||||
}
|
||||
|
||||
// currently unused events
|
||||
void DropDown::sendDropDownEvent()
|
||||
{
|
||||
selection = hover_item;
|
||||
wxCommandEvent event(wxEVT_COMBOBOX, GetId());
|
||||
event.SetEventObject(this);
|
||||
event.SetInt(selection);
|
||||
event.SetString(GetValue());
|
||||
GetEventHandler()->ProcessEvent(event);
|
||||
}
|
||||
|
||||
void DropDown::OnDismiss()
|
||||
{
|
||||
dismissTime = boost::posix_time::microsec_clock::universal_time();
|
||||
hover_item = -1;
|
||||
wxCommandEvent e(EVT_DISMISS);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
}
|
||||
112
src/slic3r/GUI/Widgets/DropDown.hpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#ifndef slic3r_GUI_DropDown_hpp_
|
||||
#define slic3r_GUI_DropDown_hpp_
|
||||
|
||||
#include <wx/stattext.h>
|
||||
#include "../wxExtensions.hpp"
|
||||
#include "StateHandler.hpp"
|
||||
#include "PopupWindow.hpp"
|
||||
|
||||
#define DD_NO_CHECK_ICON 0x0001
|
||||
#define DD_NO_TEXT 0x0002
|
||||
#define DD_STYLE_MASK 0x0003
|
||||
|
||||
wxDECLARE_EVENT(EVT_DISMISS, wxCommandEvent);
|
||||
|
||||
class DropDown : public PopupWindow
|
||||
{
|
||||
std::vector<wxString> & texts;
|
||||
std::vector<wxBitmap> & icons;
|
||||
bool need_sync = false;
|
||||
int selection = -1;
|
||||
int hover_item = -1;
|
||||
|
||||
double radius = 0;
|
||||
bool use_content_width = false;
|
||||
bool align_icon = false;
|
||||
bool text_off = false;
|
||||
|
||||
wxSize textSize;
|
||||
wxSize iconSize;
|
||||
wxSize rowSize;
|
||||
|
||||
StateHandler state_handler;
|
||||
StateColor text_color;
|
||||
StateColor border_color;
|
||||
StateColor selector_border_color;
|
||||
StateColor selector_background_color;
|
||||
ScalableBitmap check_bitmap;
|
||||
|
||||
bool pressedDown = false;
|
||||
boost::posix_time::ptime dismissTime;
|
||||
wxPoint offset; // x not used
|
||||
wxPoint dragStart;
|
||||
|
||||
public:
|
||||
DropDown(std::vector<wxString> &texts,
|
||||
std::vector<wxBitmap> &icons);
|
||||
|
||||
DropDown(wxWindow * parent,
|
||||
std::vector<wxString> &texts,
|
||||
std::vector<wxBitmap> &icons,
|
||||
long style = 0);
|
||||
|
||||
void Create(wxWindow * parent,
|
||||
long style = 0);
|
||||
|
||||
public:
|
||||
void Invalidate(bool clear = false);
|
||||
|
||||
int GetSelection() const { return selection; }
|
||||
|
||||
void SetSelection(int n);
|
||||
|
||||
wxString GetValue() const;
|
||||
void SetValue(const wxString &value);
|
||||
|
||||
public:
|
||||
void SetCornerRadius(double radius);
|
||||
|
||||
void SetBorderColor(StateColor const & color);
|
||||
|
||||
void SetSelectorBorderColor(StateColor const & color);
|
||||
|
||||
void SetTextColor(StateColor const &color);
|
||||
|
||||
void SetSelectorBackgroundColor(StateColor const &color);
|
||||
|
||||
void SetUseContentWidth(bool use);
|
||||
|
||||
void SetAlignIcon(bool align);
|
||||
|
||||
public:
|
||||
void Rescale();
|
||||
|
||||
bool HasDismissLongTime();
|
||||
|
||||
protected:
|
||||
void OnDismiss() override;
|
||||
|
||||
private:
|
||||
void paintEvent(wxPaintEvent& evt);
|
||||
void paintNow();
|
||||
|
||||
void render(wxDC& dc);
|
||||
|
||||
friend class ComboBox;
|
||||
void messureSize();
|
||||
void autoPosition();
|
||||
|
||||
// some useful events
|
||||
void mouseDown(wxMouseEvent& event);
|
||||
void mouseReleased(wxMouseEvent &event);
|
||||
void mouseCaptureLost(wxMouseCaptureLostEvent &event);
|
||||
void mouseMove(wxMouseEvent &event);
|
||||
void mouseWheelMoved(wxMouseEvent &event);
|
||||
|
||||
void sendDropDownEvent();
|
||||
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_DropDown_hpp_
|
||||
37
src/slic3r/GUI/Widgets/PopupWindow.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "PopupWindow.hpp"
|
||||
|
||||
static wxWindow *GetTopParent(wxWindow *pWindow)
|
||||
{
|
||||
wxWindow *pWin = pWindow;
|
||||
while (pWin->GetParent()) {
|
||||
pWin = pWin->GetParent();
|
||||
if (auto top = dynamic_cast<wxNonOwnedWindow*>(pWin))
|
||||
return top;
|
||||
}
|
||||
return pWin;
|
||||
}
|
||||
|
||||
bool PopupWindow::Create(wxWindow *parent, int style)
|
||||
{
|
||||
if (!wxPopupTransientWindow::Create(parent, style))
|
||||
return false;
|
||||
#ifdef __WXGTK__
|
||||
GetTopParent(parent)->Bind(wxEVT_ACTIVATE, &PopupWindow::topWindowActiavate, this);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
PopupWindow::~PopupWindow()
|
||||
{
|
||||
#ifdef __WXGTK__
|
||||
GetTopParent(this)->Unbind(wxEVT_ACTIVATE, &PopupWindow::topWindowActiavate, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __WXGTK__
|
||||
void PopupWindow::topWindowActiavate(wxActivateEvent &event)
|
||||
{
|
||||
event.Skip();
|
||||
if (!event.GetActive() && IsShown()) DismissAndNotify();
|
||||
}
|
||||
#endif
|
||||
24
src/slic3r/GUI/Widgets/PopupWindow.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef slic3r_GUI_PopupWindow_hpp_
|
||||
#define slic3r_GUI_PopupWindow_hpp_
|
||||
|
||||
#include <wx/popupwin.h>
|
||||
|
||||
class PopupWindow : public wxPopupTransientWindow
|
||||
{
|
||||
public:
|
||||
PopupWindow() {}
|
||||
|
||||
~PopupWindow();
|
||||
|
||||
PopupWindow(wxWindow *parent, int style = wxBORDER_NONE)
|
||||
{ Create(parent, style); }
|
||||
|
||||
bool Create(wxWindow *parent, int flags = wxBORDER_NONE);
|
||||
|
||||
private:
|
||||
#ifdef __WXGTK__
|
||||
void topWindowActiavate(wxActivateEvent &event);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_PopupWindow_hpp_
|
||||
42
src/slic3r/GUI/Widgets/RadioBox.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "RadioBox.hpp"
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
RadioBox::RadioBox(wxWindow *parent)
|
||||
: wxBitmapToggleButton(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE), m_on(this, "radio_on", 18), m_off(this, "radio_off", 18)
|
||||
{
|
||||
// SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
|
||||
if (parent) SetBackgroundColour(parent->GetBackgroundColour());
|
||||
// Bind(wxEVT_TOGGLEBUTTON, [this](auto& e) { update(); e.Skip(); });
|
||||
SetSize(m_on.GetSize());
|
||||
SetMinSize(m_on.GetSize());
|
||||
update();
|
||||
}
|
||||
|
||||
void RadioBox::SetValue(bool value)
|
||||
{
|
||||
wxBitmapToggleButton::SetValue(value);
|
||||
update();
|
||||
}
|
||||
|
||||
bool RadioBox::GetValue()
|
||||
{
|
||||
return wxBitmapToggleButton::GetValue();
|
||||
}
|
||||
|
||||
|
||||
void RadioBox::Rescale()
|
||||
{
|
||||
m_on.msw_rescale();
|
||||
m_off.msw_rescale();
|
||||
SetSize(m_on.GetSize());
|
||||
update();
|
||||
}
|
||||
|
||||
void RadioBox::update() { SetBitmap((GetValue() ? m_on : m_off).bmp()); }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
39
src/slic3r/GUI/Widgets/RadioBox.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef slic3r_GUI_RADIOBOX_hpp_
|
||||
#define slic3r_GUI_RADIOBOX_hpp_
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
|
||||
#include <wx/tglbtn.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
class RadioBox : public wxBitmapToggleButton
|
||||
{
|
||||
public:
|
||||
RadioBox(wxWindow *parent);
|
||||
|
||||
public:
|
||||
void SetValue(bool value) override;
|
||||
bool GetValue();
|
||||
void Rescale();
|
||||
bool Disable() {
|
||||
return wxBitmapToggleButton::Disable();
|
||||
}
|
||||
bool Enable() {
|
||||
return wxBitmapToggleButton::Enable();
|
||||
}
|
||||
|
||||
private:
|
||||
void update();
|
||||
|
||||
private:
|
||||
ScalableBitmap m_on;
|
||||
ScalableBitmap m_off;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
|
||||
|
||||
#endif // !slic3r_GUI_CheckBox_hpp_
|
||||
35
src/slic3r/GUI/Widgets/RoundedRectangle.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "RoundedRectangle.hpp"
|
||||
#include "../wxExtensions.hpp"
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
BEGIN_EVENT_TABLE(RoundedRectangle, wxPanel)
|
||||
EVT_PAINT(RoundedRectangle::OnPaint)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
RoundedRectangle::RoundedRectangle(wxWindow *parent, wxColour col, wxPoint pos, wxSize size, double radius, int type)
|
||||
: wxWindow(parent, wxID_ANY, pos, size, wxBORDER_NONE)
|
||||
{
|
||||
SetBackgroundColour(wxColour(255,255,255));
|
||||
m_type = type;
|
||||
m_color = col;
|
||||
m_radius = radius;
|
||||
}
|
||||
|
||||
void RoundedRectangle::OnPaint(wxPaintEvent &evt)
|
||||
{
|
||||
//draw RoundedRectangle
|
||||
if (m_type == 0) {
|
||||
wxPaintDC dc(this);
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
dc.SetBrush(wxBrush(m_color));
|
||||
dc.DrawRoundedRectangle(0, 0, GetSize().GetWidth(), GetSize().GetHeight(), m_radius);
|
||||
}
|
||||
|
||||
//draw RoundedRectangle only board
|
||||
if (m_type == 1) {
|
||||
wxPaintDC dc(this);
|
||||
dc.SetPen(m_color);
|
||||
dc.SetBrush(wxBrush(*wxTRANSPARENT_BRUSH));
|
||||
dc.DrawRoundedRectangle(0, 0, GetSize().GetWidth(), GetSize().GetHeight(), m_radius);
|
||||
}
|
||||
}
|
||||
21
src/slic3r/GUI/Widgets/RoundedRectangle.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef slic3r_GUI_ROUNDEDRECTANGLE_hpp_
|
||||
#define slic3r_GUI_ROUNDEDRECTANGLE_hpp_
|
||||
|
||||
#include "../wxExtensions.hpp"
|
||||
|
||||
class RoundedRectangle : public wxWindow
|
||||
{
|
||||
public:
|
||||
RoundedRectangle(wxWindow *parent, wxColour col, wxPoint pos, wxSize size, double radius, int type = 0);
|
||||
~RoundedRectangle(){};
|
||||
|
||||
private:
|
||||
double m_radius;
|
||||
int m_type;
|
||||
wxColour m_color;
|
||||
|
||||
public:
|
||||
void OnPaint(wxPaintEvent &evt);
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
#endif // !slic3r_GUI_RoundedRectangle_hpp_
|
||||
10
src/slic3r/GUI/Widgets/TextCtrl.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifdef __WXMSW__
|
||||
class TextCtrl : public wxTextCtrl
|
||||
{
|
||||
public:
|
||||
using wxTextCtrl::wxTextCtrl;
|
||||
WXHBRUSH DoMSWControlColor(WXHDC pDC, wxColour colBg, WXHWND hWnd) { return wxTextCtrl::DoMSWControlColor(pDC, wxColour(), hWnd); }
|
||||
};
|
||||
#else
|
||||
typedef wxTextCtrl TextCtrl;
|
||||
#endif
|
||||
240
src/slic3r/GUI/Widgets/TextInput.cpp
Normal file
@@ -0,0 +1,240 @@
|
||||
#include "TextInput.hpp"
|
||||
#include "Label.hpp"
|
||||
#include "TextCtrl.h"
|
||||
#include "slic3r/GUI/Widgets/Label.hpp"
|
||||
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
BEGIN_EVENT_TABLE(TextInput, wxPanel)
|
||||
|
||||
EVT_PAINT(TextInput::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().
|
||||
*/
|
||||
|
||||
TextInput::TextInput()
|
||||
: label_color(std::make_pair(0x909090, (int) StateColor::Disabled),
|
||||
std::make_pair(0x6B6B6B, (int) StateColor::Normal))
|
||||
, text_color(std::make_pair(0x909090, (int) StateColor::Disabled),
|
||||
std::make_pair(0x262E30, (int) StateColor::Normal))
|
||||
{
|
||||
radius = 0;
|
||||
border_width = 1;
|
||||
border_color = StateColor(std::make_pair(0xDBDBDB, (int) StateColor::Disabled), std::make_pair(0x009688, (int) StateColor::Hovered),
|
||||
std::make_pair(0xDBDBDB, (int) StateColor::Normal));
|
||||
background_color = StateColor(std::make_pair(0xF0F0F1, (int) StateColor::Disabled), std::make_pair(*wxWHITE, (int) StateColor::Normal));
|
||||
SetFont(Label::Body_12);
|
||||
}
|
||||
|
||||
TextInput::TextInput(wxWindow * parent,
|
||||
wxString text,
|
||||
wxString label,
|
||||
wxString icon,
|
||||
const wxPoint &pos,
|
||||
const wxSize & size,
|
||||
long style)
|
||||
: TextInput()
|
||||
{
|
||||
Create(parent, text, label, icon, pos, size, style);
|
||||
}
|
||||
|
||||
void TextInput::Create(wxWindow * parent,
|
||||
wxString text,
|
||||
wxString label,
|
||||
wxString icon,
|
||||
const wxPoint &pos,
|
||||
const wxSize & size,
|
||||
long style)
|
||||
{
|
||||
text_ctrl = nullptr;
|
||||
StaticBox::Create(parent, wxID_ANY, pos, size, style);
|
||||
wxWindow::SetLabel(label);
|
||||
style &= ~wxRIGHT;
|
||||
state_handler.attach({&label_color, & text_color});
|
||||
state_handler.update_binds();
|
||||
text_ctrl = new TextCtrl(this, wxID_ANY, text, {4, 4}, wxDefaultSize, style | wxBORDER_NONE | wxTE_PROCESS_ENTER);
|
||||
text_ctrl->SetFont(Label::Body_14);
|
||||
text_ctrl->SetInitialSize(text_ctrl->GetBestSize());
|
||||
text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states()));
|
||||
text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states()));
|
||||
state_handler.attach_child(text_ctrl);
|
||||
text_ctrl->Bind(wxEVT_KILL_FOCUS, [this](auto &e) {
|
||||
OnEdit();
|
||||
e.SetId(GetId());
|
||||
ProcessEventLocally(e);
|
||||
e.Skip();
|
||||
});
|
||||
text_ctrl->Bind(wxEVT_TEXT_ENTER, [this](auto &e) {
|
||||
OnEdit();
|
||||
e.SetId(GetId());
|
||||
ProcessEventLocally(e);
|
||||
});
|
||||
text_ctrl->Bind(wxEVT_RIGHT_DOWN, [this](auto &e) {}); // disable context menu
|
||||
if (!icon.IsEmpty()) {
|
||||
this->icon = ScalableBitmap(this, icon.ToStdString(), 16);
|
||||
}
|
||||
messureSize();
|
||||
}
|
||||
|
||||
void TextInput::SetCornerRadius(double radius)
|
||||
{
|
||||
this->radius = radius;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void TextInput::SetLabel(const wxString& label)
|
||||
{
|
||||
wxWindow::SetLabel(label);
|
||||
messureSize();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void TextInput::SetIcon(const wxBitmap &icon)
|
||||
{
|
||||
this->icon.get_bitmap() = icon;
|
||||
Rescale();
|
||||
}
|
||||
|
||||
void TextInput::SetLabelColor(StateColor const &color)
|
||||
{
|
||||
label_color = color;
|
||||
state_handler.update_binds();
|
||||
}
|
||||
|
||||
void TextInput::SetTextColor(StateColor const& color)
|
||||
{
|
||||
text_color= color;
|
||||
state_handler.update_binds();
|
||||
}
|
||||
|
||||
void TextInput::Rescale()
|
||||
{
|
||||
if (!this->icon.name().empty())
|
||||
this->icon.msw_rescale();
|
||||
messureSize();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
bool TextInput::Enable(bool enable)
|
||||
{
|
||||
bool result = text_ctrl->Enable(enable) && wxWindow::Enable(enable);
|
||||
if (result) {
|
||||
wxCommandEvent e(EVT_ENABLE_CHANGED);
|
||||
e.SetEventObject(this);
|
||||
GetEventHandler()->ProcessEvent(e);
|
||||
text_ctrl->SetBackgroundColour(background_color.colorForStates(state_handler.states()));
|
||||
text_ctrl->SetForegroundColour(text_color.colorForStates(state_handler.states()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void TextInput::SetMinSize(const wxSize& size)
|
||||
{
|
||||
wxSize size2 = size;
|
||||
if (size2.y < 0) {
|
||||
#ifdef __WXMAC__
|
||||
if (GetPeer()) // peer is not ready in Create on mac
|
||||
#endif
|
||||
size2.y = GetSize().y;
|
||||
}
|
||||
wxWindow::SetMinSize(size2);
|
||||
}
|
||||
|
||||
void TextInput::DoSetSize(int x, int y, int width, int height, int sizeFlags)
|
||||
{
|
||||
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
|
||||
if (sizeFlags & wxSIZE_USE_EXISTING) return;
|
||||
wxSize size = GetSize();
|
||||
wxPoint textPos = {5, 0};
|
||||
if (this->icon.get_bitmap().IsOk()) {
|
||||
wxSize szIcon = this->icon.GetSize();
|
||||
textPos.x += szIcon.x;
|
||||
}
|
||||
bool align_right = GetWindowStyle() & wxRIGHT;
|
||||
if (align_right)
|
||||
textPos.x += labelSize.x;
|
||||
if (text_ctrl) {
|
||||
wxSize textSize = text_ctrl->GetSize();
|
||||
textSize.x = size.x - textPos.x - labelSize.x - 10;
|
||||
text_ctrl->SetSize(textSize);
|
||||
text_ctrl->SetPosition({textPos.x, (size.y - textSize.y) / 2});
|
||||
}
|
||||
}
|
||||
|
||||
void TextInput::DoSetToolTipText(wxString const &tip)
|
||||
{
|
||||
wxWindow::DoSetToolTipText(tip);
|
||||
text_ctrl->SetToolTip(tip);
|
||||
}
|
||||
|
||||
void TextInput::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 TextInput::render(wxDC& dc)
|
||||
{
|
||||
StaticBox::render(dc);
|
||||
int states = state_handler.states();
|
||||
wxSize size = GetSize();
|
||||
bool align_right = GetWindowStyle() & wxRIGHT;
|
||||
// start draw
|
||||
wxPoint pt = {5, 0};
|
||||
if (icon.get_bitmap().IsOk()) {
|
||||
wxSize szIcon = icon.GetSize();
|
||||
pt.y = (size.y - szIcon.y) / 2;
|
||||
dc.DrawBitmap(icon.get_bitmap(), pt);
|
||||
pt.x += szIcon.x + 0;
|
||||
}
|
||||
auto text = wxWindow::GetLabel();
|
||||
if (!text.IsEmpty()) {
|
||||
wxSize textSize = text_ctrl->GetSize();
|
||||
if (align_right) {
|
||||
if (pt.x + labelSize.x > size.x)
|
||||
text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END, size.x - pt.x);
|
||||
pt.y = (size.y - labelSize.y) / 2;
|
||||
} else {
|
||||
pt.x += textSize.x;
|
||||
pt.y = (size.y + textSize.y) / 2 - labelSize.y;
|
||||
}
|
||||
dc.SetTextForeground(label_color.colorForStates(states));
|
||||
if(align_right)
|
||||
dc.SetFont(GetFont());
|
||||
else
|
||||
dc.SetFont(Label::Body_12);
|
||||
dc.DrawText(text, pt);
|
||||
}
|
||||
}
|
||||
|
||||
void TextInput::messureSize()
|
||||
{
|
||||
wxSize size = GetSize();
|
||||
wxClientDC dc(this);
|
||||
bool align_right = GetWindowStyle() & wxRIGHT;
|
||||
if (align_right)
|
||||
dc.SetFont(GetFont());
|
||||
else
|
||||
dc.SetFont(Label::Body_12);
|
||||
labelSize = dc.GetTextExtent(wxWindow::GetLabel());
|
||||
wxSize textSize = text_ctrl->GetSize();
|
||||
int h = textSize.y + 8;
|
||||
if (size.y < h) {
|
||||
size.y = h;
|
||||
}
|
||||
wxSize minSize = size;
|
||||
minSize.x = GetMinWidth();
|
||||
SetMinSize(minSize);
|
||||
SetSize(size);
|
||||
}
|
||||
77
src/slic3r/GUI/Widgets/TextInput.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef slic3r_GUI_TextInput_hpp_
|
||||
#define slic3r_GUI_TextInput_hpp_
|
||||
|
||||
#include <wx/textctrl.h>
|
||||
#include "StaticBox.hpp"
|
||||
|
||||
class TextInput : public wxNavigationEnabled<StaticBox>
|
||||
{
|
||||
|
||||
wxSize labelSize;
|
||||
ScalableBitmap icon;
|
||||
StateColor label_color;
|
||||
StateColor text_color;
|
||||
wxTextCtrl * text_ctrl;
|
||||
|
||||
static const int TextInputWidth = 200;
|
||||
static const int TextInputHeight = 50;
|
||||
|
||||
public:
|
||||
TextInput();
|
||||
|
||||
TextInput(wxWindow * parent,
|
||||
wxString text,
|
||||
wxString label = "",
|
||||
wxString icon = "",
|
||||
const wxPoint &pos = wxDefaultPosition,
|
||||
const wxSize & size = wxDefaultSize,
|
||||
long style = 0);
|
||||
|
||||
public:
|
||||
void Create(wxWindow * parent,
|
||||
wxString text,
|
||||
wxString label = "",
|
||||
wxString icon = "",
|
||||
const wxPoint &pos = wxDefaultPosition,
|
||||
const wxSize & size = wxDefaultSize,
|
||||
long style = 0);
|
||||
|
||||
void SetCornerRadius(double radius);
|
||||
|
||||
void SetLabel(const wxString& label);
|
||||
|
||||
void SetIcon(const wxBitmap &icon);
|
||||
|
||||
void SetLabelColor(StateColor const &color);
|
||||
|
||||
void SetTextColor(StateColor const &color);
|
||||
|
||||
virtual void Rescale();
|
||||
|
||||
virtual bool Enable(bool enable = true) override;
|
||||
|
||||
virtual void SetMinSize(const wxSize& size) override;
|
||||
|
||||
wxTextCtrl *GetTextCtrl() { return text_ctrl; }
|
||||
|
||||
wxTextCtrl const *GetTextCtrl() const { return text_ctrl; }
|
||||
|
||||
protected:
|
||||
virtual void OnEdit() {}
|
||||
|
||||
virtual void DoSetSize(
|
||||
int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO);
|
||||
|
||||
void DoSetToolTipText(wxString const &tip) override;
|
||||
|
||||
private:
|
||||
void paintEvent(wxPaintEvent& evt);
|
||||
|
||||
void render(wxDC& dc);
|
||||
|
||||
void messureSize();
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
#endif // !slic3r_GUI_TextInput_hpp_
|
||||
242
src/slic3r/GUI/calib_dlg.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
#include "calib_dlg.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include <wx/dcgraph.h>
|
||||
#include "MainFrame.hpp"
|
||||
#include <string>
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
wxBoxSizer *create_item_checkbox(wxString title, wxWindow *parent, bool *value, CheckBoxInWT *&checkbox)
|
||||
{
|
||||
wxBoxSizer* m_sizer_checkbox = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
m_sizer_checkbox->Add(0, 0, 0, wxEXPAND | wxLEFT, 5);
|
||||
|
||||
checkbox = new ::CheckBoxInWT(parent);
|
||||
m_sizer_checkbox->Add(checkbox, 0, wxALIGN_CENTER, 0);
|
||||
m_sizer_checkbox->Add(0, 0, 0, wxEXPAND | wxLEFT, 8);
|
||||
|
||||
auto checkbox_title = new wxStaticText(parent, wxID_ANY, title, wxDefaultPosition, wxSize(-1, -1), 0);
|
||||
checkbox_title->SetForegroundColour(wxColour(144, 144, 144));
|
||||
checkbox_title->SetFont(::Label::Body_13);
|
||||
checkbox_title->Wrap(-1);
|
||||
m_sizer_checkbox->Add(checkbox_title, 0, wxALIGN_CENTER | wxALL, 3);
|
||||
|
||||
checkbox->SetValue(true);
|
||||
|
||||
checkbox->Bind(wxEVT_TOGGLEBUTTON, [parent, checkbox, value](wxCommandEvent& e) {
|
||||
(*value) = (*value) ? false : true;
|
||||
e.Skip();
|
||||
});
|
||||
|
||||
return m_sizer_checkbox;
|
||||
}
|
||||
|
||||
PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
|
||||
: DPIDialog(parent, id, _L("PA Calibration"), wxDefaultPosition, parent->FromDIP(wxSize(-1, 280)), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), m_plater(plater)
|
||||
{
|
||||
wxBoxSizer* v_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
SetSizer(v_sizer);
|
||||
wxBoxSizer* choice_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
wxString m_rbExtruderTypeChoices[] = { _L("DDE"), _L("Bowden") };
|
||||
int m_rbExtruderTypeNChoices = sizeof(m_rbExtruderTypeChoices) / sizeof(wxString);
|
||||
m_rbExtruderType = new wxRadioBox(this, wxID_ANY, _L("Extruder type"), wxDefaultPosition, wxDefaultSize, m_rbExtruderTypeNChoices, m_rbExtruderTypeChoices, 2, wxRA_SPECIFY_COLS);
|
||||
m_rbExtruderType->SetSelection(0);
|
||||
choice_sizer->Add(m_rbExtruderType, 0, wxALL, 5);
|
||||
choice_sizer->Add(FromDIP(5), 0, 0, wxEXPAND, 5);
|
||||
wxString m_rbMethodChoices[] = { _L("PA Tower"), _L("PA Line"), _L("PA Pattern") };
|
||||
int m_rbMethodNChoices = sizeof(m_rbMethodChoices) / sizeof(wxString);
|
||||
m_rbMethod = new wxRadioBox(this, wxID_ANY, _L("Method"), wxDefaultPosition, wxDefaultSize, m_rbMethodNChoices, m_rbMethodChoices, 2, wxRA_SPECIFY_COLS);
|
||||
m_rbMethod->SetSelection(0);
|
||||
choice_sizer->Add(m_rbMethod, 0, wxALL, 5);
|
||||
|
||||
v_sizer->Add(choice_sizer);
|
||||
|
||||
// Settings
|
||||
//
|
||||
wxString start_pa_str = _L("Start PA: ");
|
||||
wxString end_pa_str = _L("End PA: ");
|
||||
wxString PA_step_str = _L("PA step: ");
|
||||
auto text_size = wxWindow::GetTextExtent(start_pa_str);
|
||||
text_size.IncTo(wxWindow::GetTextExtent(end_pa_str));
|
||||
text_size.IncTo(wxWindow::GetTextExtent(PA_step_str));
|
||||
text_size.x = text_size.x * 1.5;
|
||||
wxStaticBoxSizer* settings_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _L("Settings"));
|
||||
|
||||
auto st_size = FromDIP(wxSize(text_size.x, -1));
|
||||
auto ti_size = FromDIP(wxSize(90, -1));
|
||||
// start PA
|
||||
auto start_PA_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto start_pa_text = new wxStaticText(this, wxID_ANY, start_pa_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
|
||||
m_tiStartPA = new TextInput(this, "", "", "", wxDefaultPosition, ti_size, wxTE_CENTRE | wxTE_PROCESS_ENTER);
|
||||
m_tiStartPA->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||
|
||||
start_PA_sizer->Add(start_pa_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
start_PA_sizer->Add(m_tiStartPA, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
settings_sizer->Add(start_PA_sizer);
|
||||
|
||||
// end PA
|
||||
auto end_PA_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto end_pa_text = new wxStaticText(this, wxID_ANY, end_pa_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
|
||||
m_tiEndPA = new TextInput(this, "", "", "", wxDefaultPosition, ti_size, wxTE_CENTRE | wxTE_PROCESS_ENTER);
|
||||
m_tiStartPA->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||
end_PA_sizer->Add(end_pa_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
end_PA_sizer->Add(m_tiEndPA, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
settings_sizer->Add(end_PA_sizer);
|
||||
|
||||
// PA step
|
||||
auto PA_step_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto PA_step_text = new wxStaticText(this, wxID_ANY, PA_step_str, wxDefaultPosition, st_size, wxALIGN_LEFT);
|
||||
m_tiPAStep = new TextInput(this, "", "", "", wxDefaultPosition, ti_size, wxTE_CENTRE | wxTE_PROCESS_ENTER);
|
||||
m_tiStartPA->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||
PA_step_sizer->Add(PA_step_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
PA_step_sizer->Add(m_tiPAStep, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
settings_sizer->Add(PA_step_sizer);
|
||||
|
||||
settings_sizer->Add(create_item_checkbox(_L("Print numbers"), this, &m_params.print_numbers, m_cbPrintNum));
|
||||
m_cbPrintNum->SetValue(false);
|
||||
|
||||
v_sizer->Add(settings_sizer);
|
||||
v_sizer->Add(0, FromDIP(10), 0, wxEXPAND, 5);
|
||||
m_btnStart = new Button(this, _L("OK"));
|
||||
StateColor btn_bg_green(std::pair<wxColour, int>(wxColour(0, 137, 123), StateColor::Pressed),
|
||||
std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
|
||||
std::pair<wxColour, int>(wxColour(0, 150, 136), StateColor::Normal));
|
||||
|
||||
m_btnStart->SetBackgroundColor(btn_bg_green);
|
||||
m_btnStart->SetBorderColor(wxColour(0, 150, 136));
|
||||
m_btnStart->SetTextColor(wxColour("#FFFFFE"));
|
||||
m_btnStart->SetSize(wxSize(FromDIP(48), FromDIP(24)));
|
||||
m_btnStart->SetMinSize(wxSize(FromDIP(48), FromDIP(24)));
|
||||
m_btnStart->SetCornerRadius(FromDIP(3));
|
||||
m_btnStart->Bind(wxEVT_BUTTON, &PA_Calibration_Dlg::on_start, this);
|
||||
v_sizer->Add(m_btnStart, 0, wxALL | wxALIGN_RIGHT, FromDIP(5));
|
||||
|
||||
PA_Calibration_Dlg::reset_params();
|
||||
|
||||
// Connect Events
|
||||
m_rbExtruderType->Connect(wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler(PA_Calibration_Dlg::on_extruder_type_changed), NULL, this);
|
||||
m_rbMethod->Connect(wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler(PA_Calibration_Dlg::on_method_changed), NULL, this);
|
||||
this->Connect(wxEVT_SHOW, wxShowEventHandler(PA_Calibration_Dlg::on_show));
|
||||
//wxGetApp().UpdateDlgDarkUI(this);
|
||||
|
||||
Layout();
|
||||
Fit();
|
||||
}
|
||||
|
||||
PA_Calibration_Dlg::~PA_Calibration_Dlg() {
|
||||
// Disconnect Events
|
||||
m_rbExtruderType->Disconnect(wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler(PA_Calibration_Dlg::on_extruder_type_changed), NULL, this);
|
||||
m_rbMethod->Disconnect(wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler(PA_Calibration_Dlg::on_method_changed), NULL, this);
|
||||
m_btnStart->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PA_Calibration_Dlg::on_start), NULL, this);
|
||||
}
|
||||
|
||||
void PA_Calibration_Dlg::reset_params() {
|
||||
bool isDDE = m_rbExtruderType->GetSelection() == 0 ? true : false;
|
||||
int method = m_rbMethod->GetSelection();
|
||||
|
||||
m_tiStartPA->GetTextCtrl()->SetValue(wxString::FromDouble(0.0));
|
||||
|
||||
switch (method) {
|
||||
case 1:
|
||||
m_params.mode = CalibMode::Calib_PA_Line;
|
||||
m_tiEndPA->GetTextCtrl()->SetValue(wxString::FromDouble(0.1));
|
||||
m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.002));
|
||||
m_cbPrintNum->SetValue(true);
|
||||
m_cbPrintNum->Enable(true);
|
||||
break;
|
||||
case 2:
|
||||
m_params.mode = CalibMode::Calib_PA_Pattern;
|
||||
m_tiEndPA->GetTextCtrl()->SetValue(wxString::FromDouble(0.08));
|
||||
m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.005));
|
||||
m_cbPrintNum->SetValue(true);
|
||||
m_cbPrintNum->Enable(false);
|
||||
break;
|
||||
default:
|
||||
m_params.mode = CalibMode::Calib_PA_Tower;
|
||||
m_tiEndPA->GetTextCtrl()->SetValue(wxString::FromDouble(0.1));
|
||||
m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.002));
|
||||
m_cbPrintNum->SetValue(false);
|
||||
m_cbPrintNum->Enable(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isDDE) {
|
||||
m_tiEndPA->GetTextCtrl()->SetValue(wxString::FromDouble(1.0));
|
||||
|
||||
if (m_params.mode == CalibMode::Calib_PA_Pattern) {
|
||||
m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.05));
|
||||
} else {
|
||||
m_tiPAStep->GetTextCtrl()->SetValue(wxString::FromDouble(0.02));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PA_Calibration_Dlg::on_start(wxCommandEvent& event) {
|
||||
bool read_double = false;
|
||||
read_double = m_tiStartPA->GetTextCtrl()->GetValue().ToDouble(&m_params.start);
|
||||
read_double = read_double && m_tiEndPA->GetTextCtrl()->GetValue().ToDouble(&m_params.end);
|
||||
read_double = read_double && m_tiPAStep->GetTextCtrl()->GetValue().ToDouble(&m_params.step);
|
||||
if (!read_double || m_params.start < 0 || m_params.step < EPSILON || m_params.end < m_params.start + m_params.step) {
|
||||
MessageDialog msg_dlg(nullptr, _L("Please input valid values:\nStart PA: >= 0.0\nEnd PA: > Start PA\nPA step: >= 0.001)"), wxEmptyString, wxICON_WARNING | wxOK);
|
||||
msg_dlg.ShowModal();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_rbMethod->GetSelection()) {
|
||||
case 1:
|
||||
m_params.mode = CalibMode::Calib_PA_Line;
|
||||
break;
|
||||
case 2:
|
||||
m_params.mode = CalibMode::Calib_PA_Pattern;
|
||||
break;
|
||||
default:
|
||||
m_params.mode = CalibMode::Calib_PA_Tower;
|
||||
}
|
||||
|
||||
m_params.print_numbers = m_cbPrintNum->GetValue();
|
||||
|
||||
m_plater->calib_pa(m_params);
|
||||
EndModal(wxID_OK);
|
||||
|
||||
}
|
||||
void PA_Calibration_Dlg::on_extruder_type_changed(wxCommandEvent& event) {
|
||||
PA_Calibration_Dlg::reset_params();
|
||||
event.Skip();
|
||||
}
|
||||
void PA_Calibration_Dlg::on_method_changed(wxCommandEvent& event) {
|
||||
PA_Calibration_Dlg::reset_params();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void PA_Calibration_Dlg::on_dpi_changed(const wxRect& suggested_rect) {
|
||||
this->Refresh();
|
||||
Fit();
|
||||
}
|
||||
|
||||
void PA_Calibration_Dlg::on_show(wxShowEvent& event) {
|
||||
PA_Calibration_Dlg::reset_params();
|
||||
}
|
||||
|
||||
// Temp Calib dlg
|
||||
//
|
||||
enum FILAMENT_TYPE : int
|
||||
{
|
||||
tPLA = 0,
|
||||
tABS_ASA,
|
||||
tPETG,
|
||||
tTPU,
|
||||
tPA_CF,
|
||||
tPET_CF,
|
||||
tCustom
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
52
src/slic3r/GUI/calib_dlg.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef slic3r_calib_dlg_hpp_
|
||||
#define slic3r_calib_dlg_hpp_
|
||||
|
||||
#include "wxExtensions.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "Widgets/Button.hpp"
|
||||
#include "Widgets/Label.hpp"
|
||||
#include "Widgets/RadioBox.hpp"
|
||||
#include "Widgets/RoundedRectangle.hpp"
|
||||
#include "Widgets/CheckBoxInWT.hpp"
|
||||
#include "Widgets/ComboBox.hpp"
|
||||
#include "Widgets/TextInput.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "wx/hyperlink.h"
|
||||
#include <wx/radiobox.h>
|
||||
#include "libslic3r/calib.hpp"
|
||||
#include "Plater.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
class PA_Calibration_Dlg : public DPIDialog
|
||||
{
|
||||
public:
|
||||
PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater* plater);
|
||||
~PA_Calibration_Dlg();
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
void on_show(wxShowEvent& event);
|
||||
protected:
|
||||
void reset_params();
|
||||
virtual void on_start(wxCommandEvent& event);
|
||||
virtual void on_extruder_type_changed(wxCommandEvent& event);
|
||||
virtual void on_method_changed(wxCommandEvent& event);
|
||||
|
||||
protected:
|
||||
bool m_bDDE;
|
||||
Calib_Params m_params;
|
||||
|
||||
|
||||
wxRadioBox* m_rbExtruderType;
|
||||
wxRadioBox* m_rbMethod;
|
||||
TextInput* m_tiStartPA;
|
||||
TextInput* m_tiEndPA;
|
||||
TextInput* m_tiPAStep;
|
||||
CheckBoxInWT *m_cbPrintNum;
|
||||
Button* m_btnStart;
|
||||
|
||||
Plater* m_plater;
|
||||
};
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
#endif
|
||||
@@ -795,6 +795,56 @@ void ScalableBitmap::sys_color_changed()
|
||||
m_bmp = *get_bmp_bundle(m_icon_name, m_px_cnt);
|
||||
}
|
||||
|
||||
//B34
|
||||
// win is used to get a correct em_unit value
|
||||
// It's important for bitmaps of dialogs.
|
||||
// if win == nullptr, em_unit value of MainFrame will be used
|
||||
wxBitmap create_scaled_bitmap(const std::string &bmp_name_in,
|
||||
wxWindow * win /* = nullptr*/,
|
||||
const int px_cnt /* = 16*/,
|
||||
const bool grayscale /* = false*/,
|
||||
const std::string &new_color /* = std::string()*/, // color witch will used instead of orange
|
||||
const bool menu_bitmap /* = false*/,
|
||||
const bool resize /* = false*/)
|
||||
{
|
||||
static Slic3r::GUI::BitmapCache cache;
|
||||
|
||||
unsigned int width = 0;
|
||||
unsigned int height = (unsigned int) (win->FromDIP(px_cnt) + 0.5f);
|
||||
|
||||
std::string bmp_name = bmp_name_in;
|
||||
boost::replace_last(bmp_name, ".png", "");
|
||||
|
||||
bool dark_mode =
|
||||
#ifdef _WIN32
|
||||
menu_bitmap ? Slic3r::GUI::check_dark_mode() :
|
||||
#endif
|
||||
Slic3r::GUI::wxGetApp().dark_mode();
|
||||
|
||||
// Try loading an SVG first, then PNG if SVG is not found:
|
||||
wxBitmap *bmp = cache.load_svg(bmp_name, width, height, grayscale, dark_mode, new_color);
|
||||
if (bmp == nullptr) {
|
||||
bmp = cache.load_png(bmp_name, width, height, grayscale);
|
||||
}
|
||||
|
||||
if (bmp == nullptr) {
|
||||
// Neither SVG nor PNG has been found, raise error
|
||||
throw Slic3r::RuntimeError("Could not load bitmap: " + bmp_name);
|
||||
}
|
||||
|
||||
return *bmp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//B34
|
||||
void ScalableBitmap::msw_rescale()
|
||||
{
|
||||
|
||||
m_bmp = create_scaled_bitmap(m_icon_name, m_parent, m_px_cnt, m_grayscale, std::string(), false, m_resize);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// QIDIButton
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -158,6 +158,9 @@ public:
|
||||
return m_bmp.GetDefaultSize();
|
||||
#endif
|
||||
}
|
||||
//B34
|
||||
void msw_rescale();
|
||||
|
||||
int GetWidth() const { return GetSize().GetWidth(); }
|
||||
int GetHeight() const { return GetSize().GetHeight(); }
|
||||
|
||||
@@ -167,6 +170,9 @@ private:
|
||||
wxBitmap m_bitmap = wxBitmap();
|
||||
std::string m_icon_name = "";
|
||||
int m_px_cnt {16};
|
||||
//B34
|
||||
bool m_grayscale{false};
|
||||
bool m_resize{false};
|
||||
};
|
||||
|
||||
|
||||
|
||||