mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-12-25 09:08:38 -07:00
ENH: new wiping dialog
1.Enhance performance and ui display jira: None Signed-off-by: xun.zhang <xun.zhang@bambulab.com> Change-Id: If1cde4d1a17437ee5485dd51adff4c3444774ffd (cherry picked from commit 9c28c320d680d69b16d4895fda1bdcab9ad5b18d)
This commit is contained in:
parent
6895cbcc58
commit
5c406ef00a
5 changed files with 881 additions and 778 deletions
645
resources/web/flush/WipingDialog.html
Normal file
645
resources/web/flush/WipingDialog.html
Normal file
|
|
@ -0,0 +1,645 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
background: #f5f5f5;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
padding-bottom: 10px;
|
||||
border: 1px solid #ccc;
|
||||
max-width:fit-content(1000px);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.tip-panel {
|
||||
background: #eeeeee;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
max-width: 100%;
|
||||
max-height: 500px;
|
||||
overflow: auto;
|
||||
border: 1px solid #ccc;
|
||||
position: relative;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid #ccc;
|
||||
text-align: center;
|
||||
padding: 2px;
|
||||
position: relative;
|
||||
width: 40px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
background: #eee;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
tbody th {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
background: #eee;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(even) {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(odd) {
|
||||
background: #eeeeee;
|
||||
}
|
||||
|
||||
tbody td:first-child,
|
||||
thead th:first-child {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: #eee;
|
||||
z-index: 11;
|
||||
}
|
||||
|
||||
.icon-button {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid #999;
|
||||
text-align: center;
|
||||
line-height: 15px;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
input[type="number"].table-input {
|
||||
width: 30px;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
-moz-appearance: textfield;
|
||||
appearance: textfield;
|
||||
border: none;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
input[type="number"].table-input::-webkit-inner-spin-button,
|
||||
input[type="number"].table-input::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.warning-text {
|
||||
color: red;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.normal-text {
|
||||
color: black;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.icon-gap {
|
||||
width: 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 6px 9px;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.btn-ok {
|
||||
color: #fff;
|
||||
background-color: #21a452;
|
||||
}
|
||||
.btn-ok:hover {
|
||||
background-color: #3dcb73;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
color: black;
|
||||
background-color: white;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.btn-cancel:hover {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
select {
|
||||
padding: 6px 9px;
|
||||
border: 1px solid #dbdbdb;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
appearance: auto;
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
select option {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
select:hover,
|
||||
select:focus {
|
||||
outline: none;
|
||||
border-color: #00ae42;
|
||||
background-color: #edfaf2;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
/* 暗色模式样式 */
|
||||
body.dark-mode {
|
||||
background-color: #2d2d31;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
body.dark-mode .container {
|
||||
background: inherit;
|
||||
border-color: #2d2d31;
|
||||
}
|
||||
|
||||
body.dark-mode .tip-panel {
|
||||
background: #4c4c55;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
body.dark-mode .scroll-container {
|
||||
border-color: #4c4c55;
|
||||
}
|
||||
|
||||
body.dark-mode table {
|
||||
background: inherit;
|
||||
border-color: #4c4c55;
|
||||
}
|
||||
|
||||
body.dark-mode th, body.dark-mode td {
|
||||
background: inherit;
|
||||
border-color: #555;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
body.dark-mode thead th{
|
||||
position: sticky;
|
||||
z-index: 10
|
||||
}
|
||||
|
||||
body.dark-mode tbody th{
|
||||
position: sticky;
|
||||
z-index: 9
|
||||
}
|
||||
|
||||
body.dark-mode tbody tr:nth-child(even) {
|
||||
background: #2d2d31;
|
||||
}
|
||||
|
||||
body.dark-mode tbody tr:nth-child(odd) {
|
||||
background: #4c4c55;
|
||||
}
|
||||
|
||||
body.dark-mode tbody td:first-child,
|
||||
body.dark-mode thead th:first-child {
|
||||
position: sticky;
|
||||
z-index: 11;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-ok {
|
||||
background-color: #3a8f44;
|
||||
}
|
||||
|
||||
body.dark-mode .btn-dark {
|
||||
background-color: #34495e;
|
||||
}
|
||||
|
||||
body.dark-mode select {
|
||||
background-color: #2d2d31;
|
||||
color: white;
|
||||
border-color: #4c4c55;
|
||||
}
|
||||
|
||||
body.dark-mode .warning-text {
|
||||
color: #f44336;
|
||||
}
|
||||
|
||||
body.dark-mode .normal-text {
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
body.dark-mode .icon-button {
|
||||
background-color: #4c4c55;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="tip-panel" id="auto_flush_tip">
|
||||
Studio would re-calculate your flushing volumes every time the filament
|
||||
color changed or filaments changed. You could disable the auto-calculate
|
||||
in Bambu Studio > Preferences.
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 10px; ">
|
||||
<button
|
||||
class="btn btn-ok"
|
||||
onclick="calcFlushingVolumes()"
|
||||
id="calc_btn"
|
||||
>
|
||||
Re-Calculate
|
||||
</button>
|
||||
<select
|
||||
id="extruders"
|
||||
onchange="handleExtruderSelect(document.getElementById('extruders').value)"
|
||||
>
|
||||
<option value="left" id="extruder_label_0">Left Nozzle</option>
|
||||
<option value="right" id="extruder_label_1">Right Nozzle</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="scroll-container">
|
||||
<table id="flushTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 10px;">
|
||||
<div id="volume_desp_panel" class="normal-text">
|
||||
Flushing volume (mm³) for each filament pair.
|
||||
</div>
|
||||
<div
|
||||
id="volume_range_panel"
|
||||
class="normal-text"
|
||||
style="margin-top: 5px;"
|
||||
>
|
||||
Suggestion: Flushing Volume in range [50, 999]
|
||||
</div>
|
||||
<div style="margin-top: 8px;">
|
||||
<label
|
||||
for="multiplierInput"
|
||||
id="multiplier_label"
|
||||
style="font-size: 12px;"
|
||||
>Multiplier</label
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
step="0.1"
|
||||
id="multiplierInput"
|
||||
style="width:70px;"
|
||||
value="1.00"
|
||||
oninput="onMultiplierChange()"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="margin-top: 5px; margin-bottom: 5px; color: #666; font-size: 12px;"
|
||||
id="multiplier_range_panel"
|
||||
>
|
||||
The multiplier should be in range [0.50, 3.00].
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-container" style="padding: 0px; margin: 0px;">
|
||||
<button class="btn btn-ok" id="ok_btn" style="width: 60px; height: 30px; font-size: 12px; text-align: center;" onclick="storeData()">
|
||||
Save
|
||||
</button>
|
||||
<button class="btn btn-cancel" id="cancel_btn" style="width: 60px; height: 30px; font-size: 12px; text-align: center;" onclick="quit()">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let m_number_of_filaments // 材料数量
|
||||
let m_number_of_extruders // 喷嘴数量
|
||||
let m_colours // 颜色
|
||||
let m_display_matrix // 显示的矩阵
|
||||
let m_raw_matrix // 原始数据
|
||||
let m_flush_multipiers // 冲刷系数
|
||||
let m_cell_inputs = []; //显示的内容
|
||||
let m_curr_extruder_id = 0
|
||||
let m_min_flush_volumes = []
|
||||
let m_max_flush_volumes = []
|
||||
let m_min_flush_multiplier = 0.50
|
||||
let m_max_flush_multiplier = 3
|
||||
|
||||
function storeData() {
|
||||
var data = JSON.stringify({
|
||||
msg: 'storeData',
|
||||
number_of_extruders: m_number_of_extruders,
|
||||
raw_matrix: m_raw_matrix,
|
||||
flush_multiplier: m_flush_multipiers
|
||||
})
|
||||
window.wipingDialog.postMessage(data);
|
||||
}
|
||||
|
||||
function quit() {
|
||||
var data = JSON.stringify({
|
||||
msg: 'quit'
|
||||
})
|
||||
window.wipingDialog.postMessage(data);
|
||||
}
|
||||
|
||||
function calcFlushingVolumes() {
|
||||
var data = JSON.stringify({
|
||||
msg: 'updateMatrix',
|
||||
extruder_id: m_curr_extruder_id
|
||||
})
|
||||
window.wipingDialog.postMessage(data);
|
||||
}
|
||||
|
||||
function updateTable(dataMatrix, extruder_id) {
|
||||
for (let i = 0; i < m_number_of_filaments; i++) {
|
||||
for (let j = 0; j < m_number_of_filaments; j++) {
|
||||
var newValue
|
||||
var index = m_number_of_filaments * i + j
|
||||
newValue = (i == j ? 0 : rawToDislay(dataMatrix[index] ,m_flush_multipiers[extruder_id]))
|
||||
newValue = limitDisplayVal(newValue,extruder_id)
|
||||
m_cell_inputs[i][j].value = newValue;
|
||||
m_display_matrix[index] = newValue;
|
||||
m_raw_matrix[extruder_id][index] = dataMatrix[index]
|
||||
}
|
||||
}
|
||||
updateWarningTexts();
|
||||
}
|
||||
|
||||
// const virtual_data = {
|
||||
// filament_colors: [
|
||||
// '#123456', '#7890AB', '#CDEF01', '#F1A2B3', '#4D8B72', '#D9E1F2', '#B76C8C', '#A9C3D3',
|
||||
// '#FF5733', '#33FF57', '#5733FF', '#FF33FF', '#FFFF33', '#33FFFF', '#FF5733', '#3333FF'
|
||||
// ],
|
||||
// extruder_num: 2,
|
||||
// flush_volume_matrixs: [
|
||||
// Array.from({ length: 256 }, () => Math.floor(Math.random() * 1000)),
|
||||
// Array.from({ length: 256 }, () => Math.floor(Math.random() * 1000))
|
||||
// ],
|
||||
// flush_multiplier:[1,1]
|
||||
// }
|
||||
window.addEventListener("DOMContentLoaded",function(){
|
||||
var data = JSON.stringify({
|
||||
msg: 'init',
|
||||
})
|
||||
window.wipingDialog.postMessage(data);
|
||||
});
|
||||
|
||||
function buildText(data) {
|
||||
document.getElementById('volume_desp_panel').innerText = data.volume_desp_panel
|
||||
document.getElementById('volume_range_panel').innerText = data.volume_range_panel
|
||||
document.getElementById('multiplier_range_panel').innerText = data.multiplier_range_panel
|
||||
document.getElementById('auto_flush_tip').innerText = data.auto_flush_tip
|
||||
document.getElementById('calc_btn').innerText = data.calc_btn_panel
|
||||
document.getElementById('extruder_label_0').innerText = data.extruder_label_0
|
||||
document.getElementById('extruder_label_1').innerText = data.extruder_label_1
|
||||
document.getElementById('multiplier_label').innerText = data.multiplier_label
|
||||
document.getElementById('ok_btn').innerText = data.ok_btn_label
|
||||
document.getElementById('cancel_btn').innerText = data.cancel_btn_label
|
||||
updateVolumeRange(m_min_flush_volumes[m_curr_extruder_id],m_max_flush_volumes[m_curr_extruder_id])
|
||||
updateMultiplierRange(m_min_flush_multiplier,m_max_flush_multiplier)
|
||||
}
|
||||
|
||||
// 计算亮度
|
||||
function getLuminance(color) {
|
||||
const hex = color.replace(/^#/, '');
|
||||
const r = parseInt(hex.slice(0, 2), 16);
|
||||
const g = parseInt(hex.slice(2, 4), 16);
|
||||
const b = parseInt(hex.slice(4, 6), 16);
|
||||
return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
||||
}
|
||||
|
||||
|
||||
function updateVolumeRange(min_volume,max_volume){
|
||||
const panel = document.getElementById('volume_range_panel');
|
||||
panel.innerText = panel.innerText.replace(/\[.*\]/, `[${min_volume}, ${max_volume}]`);
|
||||
}
|
||||
|
||||
function updateMultiplierRange(min_multiplier,max_multiplier){
|
||||
const panel = document.getElementById('multiplier_range_panel');
|
||||
panel.innerText = panel.innerText.replace(/\[.*\]/, `[${min_multiplier}, ${max_multiplier}]`);
|
||||
}
|
||||
|
||||
function updateFlushMultiplier(extruder_id){
|
||||
document.getElementById("multiplierInput").value = m_flush_multipiers[extruder_id]
|
||||
}
|
||||
|
||||
function rawToDislay(val, ratio){
|
||||
return Math.round(val * ratio)
|
||||
}
|
||||
|
||||
function displayToRaw(val, ratio){
|
||||
if(ratio==0)
|
||||
return 0
|
||||
else
|
||||
return Math.round(val / ratio)
|
||||
}
|
||||
|
||||
function limitDisplayVal(val,extruder_id){
|
||||
if (isNaN(val))
|
||||
return 0
|
||||
if (val < 0)
|
||||
return 0
|
||||
if (val > m_max_flush_volumes[extruder_id])
|
||||
return m_max_flush_volumes[extruder_id];
|
||||
return val
|
||||
}
|
||||
|
||||
function buildTable(data) {
|
||||
m_colours = data.filament_colors
|
||||
m_number_of_extruders = data.extruder_num
|
||||
m_number_of_filaments = data.filament_colors.length
|
||||
m_display_matrix = data.flush_volume_matrixs[0].slice();
|
||||
m_raw_matrix = data.flush_volume_matrixs.map(function(arr) {
|
||||
return arr.slice();
|
||||
});
|
||||
m_flush_multipiers = data.flush_multiplier.slice()
|
||||
m_max_flush_volumes = data.max_flush_volumes
|
||||
m_min_flush_volumes = data.min_flush_volumes
|
||||
m_min_flush_multiplier = data.min_flush_multiplier
|
||||
m_max_flush_multiplier = data.max_flush_multiplier
|
||||
|
||||
if(data.is_dark_mode == true)
|
||||
document.body.classList.add('dark-mode');
|
||||
|
||||
updateFlushMultiplier(m_curr_extruder_id)
|
||||
|
||||
const selectElement = document.getElementById('extruders');
|
||||
if (m_number_of_extruders > 1) {
|
||||
selectElement.style.display = 'inline-block';
|
||||
} else {
|
||||
selectElement.style.display = 'none';
|
||||
}
|
||||
|
||||
var thead = document.querySelector("#flushTable thead tr");
|
||||
var tbody = document.querySelector("#flushTable tbody");
|
||||
thead.innerHTML = "";
|
||||
tbody.innerHTML = "";
|
||||
|
||||
for (let j = 0; j < m_number_of_filaments; j++) {
|
||||
if (j == 0) {
|
||||
var tag = document.createElement("th")
|
||||
tag.innerHTML = "<div style='font-size:12px'>from/to</div>"
|
||||
thead.appendChild(tag)
|
||||
}
|
||||
let th = document.createElement("th");
|
||||
const luminance = getLuminance(m_colours[j]);
|
||||
const textColor = luminance > 0.5 ? "black" : "white";
|
||||
th.innerHTML = `<div class="icon-button" style="font-size:10px;background:${m_colours[j]}; color:${textColor};">${j + 1}</div>`;
|
||||
thead.appendChild(th);
|
||||
}
|
||||
|
||||
for (let i = 0; i < m_number_of_filaments; i++) {
|
||||
let tr = document.createElement("tr");
|
||||
|
||||
let rowHeader = document.createElement("th");
|
||||
const luminance = getLuminance(m_colours[i]);
|
||||
const textColor = luminance > 0.5 ? "black" : "white";
|
||||
rowHeader.innerHTML = `<div class="icon-button" style="font-size:10px; background:${m_colours[i]};color:${textColor};">${i + 1}</div>`;
|
||||
tr.appendChild(rowHeader);
|
||||
|
||||
m_cell_inputs[i] = [];
|
||||
|
||||
for (let j = 0; j < m_number_of_filaments; j++) {
|
||||
let td = document.createElement("td");
|
||||
td.style.overflow = "hidden";
|
||||
td.style.textOverflow = "ellipsis";
|
||||
let displayVal = rawToDislay(m_raw_matrix[m_curr_extruder_id][m_number_of_filaments * i + j], m_flush_multipiers[m_curr_extruder_id])
|
||||
displayVal = limitDisplayVal(displayVal, m_curr_extruder_id)
|
||||
m_display_matrix[m_number_of_filaments*i + j] = displayVal
|
||||
let readonly = (i === j);
|
||||
let input = document.createElement("input");
|
||||
input.className = "table-input"
|
||||
input.type = "number";
|
||||
input.value = readonly ? 0 : displayVal;
|
||||
if (readonly) {
|
||||
input.readOnly = true;
|
||||
}
|
||||
input.addEventListener("input", (e) => onCellInput(i, j, e));
|
||||
|
||||
m_cell_inputs[i][j] = input;
|
||||
|
||||
td.appendChild(input);
|
||||
tr.appendChild(td);
|
||||
}
|
||||
|
||||
tbody.appendChild(tr);
|
||||
}
|
||||
updateWarningTexts();
|
||||
}
|
||||
|
||||
function onCellInput(i, j, event) {
|
||||
const input = event.target;
|
||||
let val = parseInt(input.value, 10);
|
||||
val = limitDisplayVal(val, m_curr_extruder_id);
|
||||
input.value = val;
|
||||
|
||||
if (i !== j) {
|
||||
var index = m_number_of_filaments*i+j
|
||||
m_raw_matrix[m_curr_extruder_id][index] = displayToRaw(val, m_flush_multipiers[m_curr_extruder_id])
|
||||
m_display_matrix[index] = val;
|
||||
}
|
||||
updateWarningTexts();
|
||||
}
|
||||
|
||||
function handleExtruderSelect(extruder) {
|
||||
m_curr_extruder_id = extruder == 'left' ? 0 : 1
|
||||
updateTable(m_raw_matrix[m_curr_extruder_id], m_curr_extruder_id)
|
||||
updateVolumeRange(m_min_flush_volumes[m_curr_extruder_id],m_max_flush_volumes[m_curr_extruder_id])
|
||||
updateFlushMultiplier(m_min_flush_multiplier[m_curr_extruder_id],m_max_flush_multiplier[m_curr_extruder_id])
|
||||
updateFlushMultiplier(m_curr_extruder_id)
|
||||
}
|
||||
|
||||
function onMultiplierChange() {
|
||||
let val = parseFloat(document.getElementById("multiplierInput").value);
|
||||
if (isNaN(val)) val = 1.0;
|
||||
if(val<m_min_flush_multiplier){
|
||||
val = m_min_flush_multiplier
|
||||
document.getElementById("multiplierInput").value = m_min_flush_multiplier;
|
||||
}
|
||||
else if(val>m_max_flush_multiplier){
|
||||
val = m_max_flush_multiplier
|
||||
document.getElementById("multiplierInput").value = m_max_flush_multiplier;
|
||||
}
|
||||
m_flush_multipiers[m_curr_extruder_id] = val;
|
||||
for (let i = 0; i < m_number_of_filaments; i++) {
|
||||
for (let j = 0; j < m_number_of_filaments; j++) {
|
||||
if (i === j) continue;
|
||||
var index = i * m_number_of_filaments + j;
|
||||
let displayVal = rawToDislay(m_raw_matrix[m_curr_extruder_id][index] ,m_flush_multipiers[m_curr_extruder_id])
|
||||
displayVal = limitDisplayVal(displayVal, m_curr_extruder_id)
|
||||
m_cell_inputs[i][j].value = displayVal;
|
||||
m_display_matrix[index] = displayVal;
|
||||
}
|
||||
}
|
||||
updateWarningTexts();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function updateWarningTexts() {
|
||||
let hasException = false;
|
||||
for (let i = 0; i < m_number_of_filaments; i++) {
|
||||
for (let j = 0; j < m_number_of_filaments; j++) {
|
||||
if (i === j) continue;
|
||||
const input = m_cell_inputs[i][j];
|
||||
let val = parseInt(input.value, 10);
|
||||
if (isNaN(val)) val = 0;
|
||||
|
||||
if (val < m_min_flush_volumes[m_curr_extruder_id] || val > m_max_flush_volumes[m_curr_extruder_id]) {
|
||||
input.style.color = "red";
|
||||
hasException = true;
|
||||
} else {
|
||||
input.style.color = "black";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rangeLabel = document.getElementById("volume_range_panel");
|
||||
if (hasException) {
|
||||
rangeLabel.classList.remove("normal-text");
|
||||
rangeLabel.classList.add("warning-text");
|
||||
} else {
|
||||
rangeLabel.classList.remove("warning-text");
|
||||
rangeLabel.classList.add("normal-text");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1719,22 +1719,13 @@ Sidebar::Sidebar(Plater *parent)
|
|||
extra_flush_volumes[nozzle_id] = get_min_flush_volumes(full_config, nozzle_id);
|
||||
}
|
||||
|
||||
std::vector<float> flush_multiplier;
|
||||
ConfigOptionFloats *flush_multi_opt = project_config.option<ConfigOptionFloats>("flush_multiplier");
|
||||
if (flush_multi_opt)
|
||||
flush_multiplier = cast<float>(flush_multi_opt->values);
|
||||
|
||||
flush_multiplier.resize(nozzle_nums, 1.0f);
|
||||
|
||||
WipingDialog dlg(parent, cast<float>(init_matrix), cast<float>(init_extruders), extruder_colours, extra_flush_volumes, flush_multiplier, nozzle_nums);
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
std::vector<float> matrix = dlg.get_matrix();
|
||||
std::vector<float> extruders = dlg.get_extruders();
|
||||
std::vector<float> flush_multipliers = dlg.get_flush_multiplier_vector();
|
||||
WipingDialog dlg(static_cast<wxWindow *>(wxGetApp().mainframe),extra_flush_volumes);
|
||||
dlg.ShowModal();
|
||||
if (dlg.GetSubmitFlag()) {
|
||||
auto matrix = dlg.GetFlattenMatrix();
|
||||
auto flush_multipliers = dlg.GetMultipliers();
|
||||
(project_config.option<ConfigOptionFloats>("flush_volumes_matrix"))->values = std::vector<double>(matrix.begin(), matrix.end());
|
||||
(project_config.option<ConfigOptionFloats>("flush_volumes_vector"))->values = std::vector<double>(extruders.begin(), extruders.end());
|
||||
(project_config.option<ConfigOptionFloats>("flush_multiplier"))->values = std::vector<double>(flush_multipliers.begin(), flush_multipliers.end());
|
||||
|
||||
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
|
||||
|
||||
wxGetApp().plater()->update_project_dirty_from_presets();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||||
#include "WipeTowerDialog.hpp"
|
||||
|
||||
#include "Search.hpp"
|
||||
#include "OG_CustomCtrl.hpp"
|
||||
|
|
@ -49,6 +48,7 @@
|
|||
#include "Search.hpp"
|
||||
#include "BedShapeDialog.hpp"
|
||||
#include "libslic3r/GCode/Thumbnails.hpp"
|
||||
#include "WipeTowerDialog.hpp"
|
||||
|
||||
#include "BedShapeDialog.hpp"
|
||||
// #include "BonjourDialog.hpp"
|
||||
|
|
|
|||
|
|
@ -1,19 +1,15 @@
|
|||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <wx/sizer.h>
|
||||
#include "libslic3r/FlushVolCalc.hpp"
|
||||
#include "WipeTowerDialog.hpp"
|
||||
#include "BitmapCache.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "format.hpp"
|
||||
#include "libslic3r/Color.hpp"
|
||||
#include "Widgets/Button.hpp"
|
||||
#include "Widgets/StaticLine.hpp"
|
||||
#include "Widgets/DialogButtons.hpp"
|
||||
#include "slic3r/Utils/ColorSpaceConvert.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "Widgets/Label.hpp"
|
||||
|
||||
|
|
@ -21,28 +17,6 @@ using namespace Slic3r;
|
|||
using namespace Slic3r::GUI;
|
||||
|
||||
int scale(const int val) { return val * Slic3r::GUI::wxGetApp().em_unit() / 10; }
|
||||
int ITEM_WIDTH() { return scale(30); }
|
||||
static const wxColour g_text_color = wxColour(107, 107, 107, 255);
|
||||
|
||||
#undef ICON_SIZE
|
||||
#define ICON_SIZE wxSize(FromDIP(16), FromDIP(16))
|
||||
#define TABLE_BORDER FromDIP(28)
|
||||
#define HEADER_VERT_PADDING FromDIP(12)
|
||||
#define HEADER_BEG_PADDING FromDIP(30)
|
||||
#define ICON_GAP FromDIP(44)
|
||||
#define HEADER_END_PADDING FromDIP(24)
|
||||
#define ROW_VERT_PADDING FromDIP(6)
|
||||
#define ROW_BEG_PADDING FromDIP(20)
|
||||
#define EDIT_BOXES_GAP FromDIP(30)
|
||||
#define ROW_END_PADDING FromDIP(21)
|
||||
#define BTN_SIZE wxSize(FromDIP(58), FromDIP(24))
|
||||
#define BTN_GAP FromDIP(20)
|
||||
#define TEXT_BEG_PADDING FromDIP(30)
|
||||
#define MAX_FLUSH_VALUE 2147483520
|
||||
#define MIN_WIPING_DIALOG_WIDTH FromDIP(300)
|
||||
#define TIP_MESSAGES_PADDING FromDIP(8)
|
||||
|
||||
|
||||
|
||||
static void update_ui(wxWindow* window)
|
||||
{
|
||||
|
|
@ -220,530 +194,212 @@ std::string RammingPanel::get_parameters()
|
|||
return stream.str();
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define style wxSP_ARROW_KEYS | wxBORDER_SIMPLE
|
||||
#else
|
||||
#define style wxSP_ARROW_KEYS
|
||||
#endif
|
||||
|
||||
static const float g_min_flush_multiplier = 0.f;
|
||||
static const float g_max_flush_multiplier = 3.f;
|
||||
|
||||
wxBoxSizer* WipingDialog::create_btn_sizer(long flags)
|
||||
{
|
||||
auto btn_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
btn_sizer->AddStretchSpacer();
|
||||
|
||||
if (flags & wxRESET) {
|
||||
Button *calc_btn = new Button(this, _L("Auto-Calc"));
|
||||
calc_btn->SetStyle(ButtonStyle::Confirm, ButtonType::Choice);
|
||||
calc_btn->SetFocus();
|
||||
calc_btn->SetId(wxID_RESET);
|
||||
btn_sizer->Add(calc_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(ButtonProps::ChoiceButtonGap()));
|
||||
m_button_list[wxRESET] = calc_btn;
|
||||
static std::vector<float> MatrixFlatten(const WipingDialog::VolumeMatrix& matrix) {
|
||||
std::vector<float> vec;
|
||||
for (auto row_elems : matrix) {
|
||||
for (auto elem : row_elems)
|
||||
vec.emplace_back(elem);
|
||||
}
|
||||
if (flags & wxOK) {
|
||||
Button* ok_btn = new Button(this, _L("OK"));
|
||||
ok_btn->SetStyle(ButtonStyle::Confirm, ButtonType::Choice);
|
||||
ok_btn->SetFocus();
|
||||
ok_btn->SetId(wxID_OK);
|
||||
btn_sizer->Add(ok_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(ButtonProps::ChoiceButtonGap()));
|
||||
m_button_list[wxOK] = ok_btn;
|
||||
}
|
||||
if (flags & wxCANCEL) {
|
||||
Button* cancel_btn = new Button(this, _L("Cancel"));
|
||||
cancel_btn->SetStyle(ButtonStyle::Regular, ButtonType::Choice);
|
||||
cancel_btn->SetId(wxID_CANCEL);
|
||||
btn_sizer->Add(cancel_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(ButtonProps::ChoiceButtonGap()));
|
||||
m_button_list[wxCANCEL] = cancel_btn;
|
||||
}
|
||||
|
||||
return btn_sizer;
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
wxBoxSizer* WipingPanel::create_calc_btn_sizer(wxWindow* parent) {
|
||||
auto btn_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxString WipingDialog::BuildTableObjStr()
|
||||
{
|
||||
auto full_config = wxGetApp().preset_bundle->full_config();
|
||||
auto filament_colors = full_config.option<ConfigOptionStrings>("filament_colour")->values;
|
||||
auto flush_multiplier = full_config.option<ConfigOptionFloats>("flush_multiplier")->values;
|
||||
int nozzle_num = full_config.option<ConfigOptionFloatsNullable>("nozzle_diameter")->values.size();
|
||||
auto raw_matrix_data = full_config.option<ConfigOptionFloats>("flush_volumes_matrix")->values;
|
||||
std::vector<std::vector<double>> flush_matrixs;
|
||||
for (int idx = 0; idx < nozzle_num; ++idx) {
|
||||
flush_matrixs.emplace_back(get_flush_volumes_matrix(raw_matrix_data, idx, nozzle_num));
|
||||
}
|
||||
flush_multiplier.resize(nozzle_num, 1);
|
||||
|
||||
Button* calc_btn = new Button(parent, _L("Re-calculate"));
|
||||
calc_btn->SetStyle(ButtonStyle::Confirm, ButtonType::Window);
|
||||
calc_btn->SetFocus();
|
||||
btn_sizer->Add(calc_btn, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(ButtonProps::WindowButtonGap()));
|
||||
calc_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { calc_flushing_volumes(); });
|
||||
m_raw_matrixs = flush_matrixs;
|
||||
m_flush_multipliers = flush_multiplier;
|
||||
|
||||
if (m_nozzle_nums == 2) {
|
||||
ComboBox *extruder_combo = new ComboBox(parent, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(130), FromDIP(24)), 0, nullptr, wxCB_READONLY);
|
||||
extruder_combo->AppendString(_L("Left extruder"));
|
||||
extruder_combo->AppendString(_L("Right extruder"));
|
||||
extruder_combo->SetSelection(0);
|
||||
extruder_combo->Bind(wxEVT_COMBOBOX, &WipingPanel::on_select_extruder, this);
|
||||
btn_sizer->Add(extruder_combo);
|
||||
json obj;
|
||||
obj["flush_multiplier"] = flush_multiplier;
|
||||
obj["extruder_num"] = nozzle_num;
|
||||
obj["filament_colors"] = filament_colors;
|
||||
obj["flush_volume_matrixs"] = json::array();
|
||||
obj["min_flush_volumes"] = json::array();
|
||||
obj["max_flush_volumes"] = json::array();
|
||||
obj["min_flush_multiplier"] = g_min_flush_multiplier;
|
||||
obj["max_flush_multiplier"] = g_max_flush_multiplier;
|
||||
obj["is_dark_mode"] = wxGetApp().dark_mode();
|
||||
|
||||
for (const auto& vec : flush_matrixs) {
|
||||
obj["flush_volume_matrixs"].push_back(vec);
|
||||
}
|
||||
|
||||
return btn_sizer;
|
||||
for (int idx = 0; idx < nozzle_num; ++idx) {
|
||||
obj["min_flush_volumes"].push_back(*min_element(m_extra_flush_volume[idx].begin(), m_extra_flush_volume[idx].end()));
|
||||
obj["max_flush_volumes"].push_back(m_max_flush_volume);
|
||||
}
|
||||
|
||||
auto obj_str = obj.dump();
|
||||
return obj_str;
|
||||
}
|
||||
void WipingDialog::on_dpi_changed(const wxRect &suggested_rect)
|
||||
|
||||
wxString WipingDialog::BuildTextObjStr()
|
||||
{
|
||||
for (auto button_item : m_button_list)
|
||||
{
|
||||
if (button_item.first == wxRESET)
|
||||
{
|
||||
button_item.second->Rescale();
|
||||
}
|
||||
wxString auto_flush_tip = _L("Studio would re-calculate your flushing volumes everytime the filaments color changed or filaments changed. You could disable the auto-calculate in Bambu Studio > Preferences");
|
||||
wxString volume_desp_panel = _L("Flushing volume (mm³) for each filament pair.");
|
||||
wxString volume_range_panel = wxString::Format(_L("Suggestion: Flushing Volume in range [%d, %d]"), 0, 700);
|
||||
wxString multiplier_range_panel = wxString::Format(_L("The multiplier should be in range [%.2f, %.2f]."), 0, 3);
|
||||
wxString calc_btn_panel = _L("Re-calculate");
|
||||
wxString extruder_label_0 = _L("Left extruder");
|
||||
wxString extruder_label_1 = _L("Right extruder");
|
||||
wxString multiplier_label = _L("Multiplier");
|
||||
wxString ok_btn_label = _L("OK");
|
||||
wxString cancel_btn_label = _L("Cancel");
|
||||
|
||||
wxString text_obj = "{";
|
||||
text_obj += wxString::Format("\"volume_desp_panel\":\"%s\",", volume_desp_panel);
|
||||
text_obj += wxString::Format("\"volume_range_panel\":\"%s\",", volume_range_panel);
|
||||
text_obj += wxString::Format("\"multiplier_range_panel\":\"%s\",", multiplier_range_panel);
|
||||
text_obj += wxString::Format("\"calc_btn_panel\":\"%s\",", calc_btn_panel);
|
||||
text_obj += wxString::Format("\"extruder_label_0\":\"%s\",", extruder_label_0);
|
||||
text_obj += wxString::Format("\"extruder_label_1\":\"%s\",", extruder_label_1);
|
||||
text_obj += wxString::Format("\"multiplier_label\":\"%s\",", multiplier_label);
|
||||
text_obj += wxString::Format("\"ok_btn_label\":\"%s\",", ok_btn_label);
|
||||
text_obj += wxString::Format("\"cancel_btn_label\":\"%s\",", cancel_btn_label);
|
||||
text_obj += wxString::Format("\"auto_flush_tip\":\"%s\"", auto_flush_tip);
|
||||
text_obj += "}";
|
||||
return text_obj;
|
||||
}
|
||||
|
||||
WipingDialog::WipingDialog(wxWindow* parent, const std::vector<std::vector<int>>& extra_flush_volume,const int max_flush_volume) :
|
||||
wxDialog(parent, wxID_ANY, _(L("Flushing volumes for filament change")),
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
wxDEFAULT_DIALOG_STYLE ),
|
||||
m_extra_flush_volume(extra_flush_volume),
|
||||
m_max_flush_volume(max_flush_volume)
|
||||
{
|
||||
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
this->SetSizer(main_sizer);
|
||||
|
||||
auto filament_count= wxGetApp().preset_bundle->project_config.option<ConfigOptionStrings>("filament_colour")->values.size();
|
||||
wxSize extra_size = { FromDIP(100),FromDIP(235) };
|
||||
if (filament_count <= 2)
|
||||
extra_size.y += FromDIP(16) * 3 + FromDIP(32);
|
||||
else if (filament_count == 3)
|
||||
extra_size.y += FromDIP(16) * 3;
|
||||
else if (4 <= filament_count && filament_count <= 8)
|
||||
extra_size.y += FromDIP(16) * 2;
|
||||
else
|
||||
extra_size.y += FromDIP(16);
|
||||
|
||||
wxSize max_scroll_size = { FromDIP(1000),FromDIP(500) };
|
||||
wxSize estimate_size = { (int)(filament_count + 1) * FromDIP(60),(int)(filament_count + 1) * FromDIP(30)+FromDIP(2)};
|
||||
wxSize scroll_size ={ std::min(max_scroll_size.x,estimate_size.x),std::min(max_scroll_size.y,estimate_size.y) };
|
||||
|
||||
wxSize appied_size = scroll_size + extra_size;
|
||||
m_webview = wxWebView::New(this, wxID_ANY,
|
||||
wxEmptyString,
|
||||
wxDefaultPosition,
|
||||
appied_size,
|
||||
wxWebViewBackendDefault,
|
||||
wxNO_BORDER);
|
||||
|
||||
m_webview->AddScriptMessageHandler("wipingDialog");
|
||||
main_sizer->Add(m_webview, 1);
|
||||
|
||||
fs::path filepath = fs::path(resources_dir()) / "web/flush/WipingDialog.html";
|
||||
wxString filepath_str = wxString::FromUTF8(filepath.string());
|
||||
wxFileName fn(filepath_str);
|
||||
if(fn.FileExists()) {
|
||||
wxString url = "file:///" + fn.GetFullPath();
|
||||
m_webview->LoadURL(url);
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< "WipingDialog.html not exist";
|
||||
}
|
||||
m_panel_wiping->msw_rescale();
|
||||
this->Refresh();
|
||||
};
|
||||
|
||||
// Parent dialog for purging volume adjustments - it fathers WipingPanel widget (that contains all controls) and a button to toggle simple/advanced mode:
|
||||
WipingDialog::WipingDialog(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, const std::vector<std::string>& extruder_colours,
|
||||
const std::vector<std::vector<int>>&extra_flush_volume, const std::vector<float>& flush_multiplier, size_t nozzle_nums)
|
||||
: GUI::DPIDialog(parent ? parent : static_cast<wxWindow *>(wxGetApp().mainframe),
|
||||
wxID_ANY,
|
||||
_(L("Flushing volumes for filament change")),
|
||||
wxDefaultPosition,
|
||||
wxDefaultSize,
|
||||
wxDEFAULT_DIALOG_STYLE /* | wxRESIZE_BORDER*/)
|
||||
{
|
||||
auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1));
|
||||
m_line_top->SetBackgroundColour(wxColour(166, 169, 170));
|
||||
|
||||
this->SetBackgroundColour(*wxWHITE);
|
||||
this->SetMinSize(wxSize(MIN_WIPING_DIALOG_WIDTH, -1));
|
||||
|
||||
|
||||
m_panel_wiping = new WipingPanel(this, matrix, extruders, 0, extruder_colours, nullptr, extra_flush_volume, flush_multiplier, nozzle_nums);
|
||||
|
||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->Add(m_line_top, 0, wxEXPAND, 0);
|
||||
|
||||
// set min sizer width according to extruders count
|
||||
auto sizer_width = (int)((sqrt(matrix.size()) + 2.8)*ITEM_WIDTH());
|
||||
sizer_width = sizer_width > MIN_WIPING_DIALOG_WIDTH ? sizer_width : MIN_WIPING_DIALOG_WIDTH;
|
||||
main_sizer->SetMinSize(wxSize(sizer_width, -1));
|
||||
main_sizer->Add(m_panel_wiping, 1, wxEXPAND | wxALL, 0);
|
||||
|
||||
auto dlg_btns = new DialogButtons(this, {"OK", "Cancel"});
|
||||
main_sizer->Add(dlg_btns, 0, wxEXPAND);
|
||||
SetSizer(main_sizer);
|
||||
main_sizer->SetSizeHints(this);
|
||||
|
||||
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { // if OK button is clicked..
|
||||
m_output_matrix = m_panel_wiping->read_matrix_values(); // ..query wiping panel and save returned values
|
||||
m_output_extruders = m_panel_wiping->read_extruders_values(); // so they can be recovered later by calling get_...()
|
||||
EndModal(wxID_OK);
|
||||
}, wxID_OK);
|
||||
|
||||
dlg_btns->GetCANCEL()->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { EndModal(wxCANCEL); });
|
||||
|
||||
/*
|
||||
if (this->FindWindowById(wxID_RESET, this)) {
|
||||
this->FindWindowById(wxID_RESET, this)->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { m_panel_wiping->calc_flushing_volumes(); });
|
||||
}
|
||||
*/
|
||||
|
||||
this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { EndModal(wxCANCEL); });
|
||||
this->Bind(wxEVT_CHAR_HOOK, [this](wxKeyEvent& e) {
|
||||
if (e.GetKeyCode() == WXK_ESCAPE) {
|
||||
if (this->IsModal())
|
||||
this->EndModal(wxID_CANCEL);
|
||||
else
|
||||
this->Close();
|
||||
}
|
||||
else
|
||||
e.Skip();
|
||||
});
|
||||
|
||||
main_sizer->Fit(this);
|
||||
CenterOnParent();
|
||||
wxGetApp().UpdateDlgDarkUI(this);
|
||||
}
|
||||
|
||||
void WipingPanel::create_panels(wxWindow* parent, const int num) {
|
||||
for (size_t i = 0; i < num; i++)
|
||||
{
|
||||
wxPanel* panel = new wxPanel(parent);
|
||||
panel->SetBackgroundColour(i % 2 == 0 ? *wxWHITE : wxColour(238, 238, 238));
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
panel->SetSizer(sizer);
|
||||
//m_webview->Bind(wxEVT_WEBVIEW_NAVIGATED, [this](auto& evt) {
|
||||
// auto table_obj_str = BuildTableObjStr();
|
||||
// auto text_obj_str = BuildTextObjStr();
|
||||
// CallAfter([table_obj_str, text_obj_str, this] {
|
||||
// wxString script = wxString::Format("buildTable(%s);buildText(%s)", table_obj_str, text_obj_str);
|
||||
// m_webview->RunScript(script);
|
||||
// });
|
||||
// });
|
||||
|
||||
wxButton* icon = new wxButton(panel, wxID_ANY, {}, wxDefaultPosition, ICON_SIZE, wxBORDER_NONE | wxBU_AUTODRAW);
|
||||
icon->SetBitmap(*get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(i + 1), FromDIP(16), FromDIP(16)));
|
||||
icon->SetCanFocus(false);
|
||||
icon_list2.push_back(icon);
|
||||
|
||||
sizer->AddSpacer(ROW_BEG_PADDING);
|
||||
sizer->Add(icon, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, ROW_VERT_PADDING);
|
||||
|
||||
for (int j = 0; j < num; ++j) {
|
||||
edit_boxes[j][i]->Reparent(panel);
|
||||
edit_boxes[j][i]->SetBackgroundColour(panel->GetBackgroundColour());
|
||||
edit_boxes[j][i]->SetFont(::Label::Body_13);
|
||||
sizer->AddSpacer(EDIT_BOXES_GAP);
|
||||
sizer->Add(edit_boxes[j][i], 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||
}
|
||||
sizer->AddSpacer(ROW_END_PADDING);
|
||||
|
||||
m_sizer_advanced->Add(panel, 0, wxRIGHT | wxLEFT | wxEXPAND, TABLE_BORDER);
|
||||
panel->Layout();
|
||||
}
|
||||
}
|
||||
|
||||
// This panel contains all control widgets for both simple and advanced mode (these reside in separate sizers)
|
||||
WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders,
|
||||
size_t cur_extruder_id,
|
||||
const std::vector<std::string>& extruder_colours, Button* calc_button,
|
||||
const std::vector<std::vector<int>>& extra_flush_volume, const std::vector<float>& flush_multiplier, size_t nozzle_nums)
|
||||
: wxPanel(parent,wxID_ANY, wxDefaultPosition, wxDefaultSize/*,wxBORDER_RAISED*/)
|
||||
, m_flush_multiplier(flush_multiplier)
|
||||
, m_matrix(matrix)
|
||||
, m_cur_extruder_id(cur_extruder_id)
|
||||
, m_min_flush_volume(extra_flush_volume)
|
||||
, m_max_flush_volume(Slic3r::g_max_flush_volume)
|
||||
, m_nozzle_nums(nozzle_nums)
|
||||
{
|
||||
m_number_of_extruders = (unsigned int)extruder_colours.size();
|
||||
|
||||
generate_display_matrix();
|
||||
|
||||
for (const std::string& color : extruder_colours) {
|
||||
Slic3r::ColorRGB rgb;
|
||||
Slic3r::decode_color(color, rgb);
|
||||
m_colours.push_back(wxColor(rgb.r_uchar(), rgb.g_uchar(), rgb.b_uchar()));
|
||||
}
|
||||
auto sizer_width = (int)((sqrt(m_display_matrix.size())) * ITEM_WIDTH() + (sqrt(m_display_matrix.size()) + 1) * HEADER_BEG_PADDING);
|
||||
sizer_width = sizer_width > MIN_WIPING_DIALOG_WIDTH ? sizer_width : MIN_WIPING_DIALOG_WIDTH;
|
||||
// Create two switched panels with their own sizers
|
||||
m_sizer_simple = new wxBoxSizer(wxVERTICAL);
|
||||
m_sizer_advanced = new wxBoxSizer(wxVERTICAL);
|
||||
m_page_simple = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
m_page_advanced = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
m_page_simple->SetSizer(m_sizer_simple);
|
||||
m_page_advanced->SetSizer(m_sizer_advanced);
|
||||
m_page_advanced->SetBackgroundColour(*wxWHITE);
|
||||
|
||||
update_ui(m_page_simple);
|
||||
update_ui(m_page_advanced);
|
||||
|
||||
auto gridsizer_simple = new wxGridSizer(3, 5, 10);
|
||||
m_gridsizer_advanced = new wxGridSizer(m_number_of_extruders + 1, 5, 1);
|
||||
|
||||
// First create controls for advanced mode and assign them to m_page_advanced:
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i) {
|
||||
edit_boxes.push_back(std::vector<wxTextCtrl*>(0));
|
||||
|
||||
for (unsigned int j = 0; j < m_number_of_extruders; ++j) {
|
||||
#ifdef _WIN32
|
||||
wxTextCtrl* text = new wxTextCtrl(m_page_advanced, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(ITEM_WIDTH(), -1), wxTE_CENTER | wxBORDER_NONE | wxTE_PROCESS_ENTER);
|
||||
update_ui(text);
|
||||
edit_boxes.back().push_back(text);
|
||||
#else
|
||||
edit_boxes.back().push_back(new wxTextCtrl(m_page_advanced, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(ITEM_WIDTH(), -1)));
|
||||
#endif
|
||||
if (i == j) {
|
||||
edit_boxes[i][j]->SetValue(wxString("0"));
|
||||
edit_boxes[i][j]->SetEditable(false);
|
||||
edit_boxes[i][j]->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent&) {});
|
||||
edit_boxes[i][j]->Bind(wxEVT_SET_FOCUS, [this](wxFocusEvent&) {});
|
||||
}
|
||||
else {
|
||||
edit_boxes[i][j]->SetValue(wxString("") << int(m_display_matrix[m_number_of_extruders * j + i] * m_flush_multiplier[m_cur_extruder_id]));
|
||||
|
||||
edit_boxes[i][j]->Bind(wxEVT_TEXT, [this, i, j](wxCommandEvent& e) {
|
||||
wxString str = edit_boxes[i][j]->GetValue();
|
||||
int value = wxAtoi(str);
|
||||
if (value > MAX_FLUSH_VALUE) {
|
||||
str = wxString::Format(("%d"), MAX_FLUSH_VALUE);
|
||||
edit_boxes[i][j]->SetValue(str);
|
||||
}
|
||||
else if (value < 0) {
|
||||
edit_boxes[i][j]->SetValue(wxString("0"));
|
||||
}
|
||||
m_webview->Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, [this](wxWebViewEvent& evt) {
|
||||
std::string message = evt.GetString().ToStdString();
|
||||
try {
|
||||
json j = json::parse(message);
|
||||
if (j["msg"].get<std::string>() == "init") {
|
||||
auto table_obj_str = BuildTableObjStr();
|
||||
auto text_obj_str = BuildTextObjStr();
|
||||
CallAfter([table_obj_str, text_obj_str, this] {
|
||||
wxString script = wxString::Format("buildTable(%s);buildText(%s)", table_obj_str, text_obj_str);
|
||||
m_webview->RunScript(script);
|
||||
});
|
||||
|
||||
auto on_apply_text_modify = [this, i, j](wxEvent &e) {
|
||||
wxString str = edit_boxes[i][j]->GetValue();
|
||||
int value = wxAtoi(str);
|
||||
m_display_matrix[m_number_of_extruders * j + i] = value / get_flush_multiplier();
|
||||
this->update_warning_texts();
|
||||
e.Skip();
|
||||
};
|
||||
|
||||
edit_boxes[i][j]->Bind(wxEVT_TEXT_ENTER, on_apply_text_modify);
|
||||
edit_boxes[i][j]->Bind(wxEVT_KILL_FOCUS, on_apply_text_modify);
|
||||
}
|
||||
else if (j["msg"].get<std::string>() == "updateMatrix") {
|
||||
int extruder_id = j["extruder_id"].get<int>();
|
||||
auto new_matrix = CalcFlushingVolumes(extruder_id);
|
||||
json obj;
|
||||
obj["flush_volume_matrix"] = MatrixFlatten(new_matrix);
|
||||
obj["extruder_id"] = extruder_id;
|
||||
CallAfter([obj, this] {
|
||||
std::string flush_volume_matrix_str = obj["flush_volume_matrix"].dump();
|
||||
std::string extruder_id_str = std::to_string(obj["extruder_id"].get<int>());
|
||||
wxString script = wxString::Format("updateTable(%s,%s)", flush_volume_matrix_str, extruder_id_str);
|
||||
m_webview->RunScript(script);
|
||||
});
|
||||
}
|
||||
else if (j["msg"].get<std::string>() == "storeData") {
|
||||
int extruder_num = j["number_of_extruders"].get<int>();
|
||||
std::vector<std::vector<double>> store_matrixs;
|
||||
for (auto iter = j["raw_matrix"].begin(); iter != j["raw_matrix"].end(); ++iter) {
|
||||
store_matrixs.emplace_back((*iter).get<std::vector<double>>());
|
||||
}
|
||||
std::vector<double>store_multipliers = j["flush_multiplier"].get<std::vector<double>>();
|
||||
this->StoreFlushData(extruder_num, store_matrixs, store_multipliers);
|
||||
m_submit_flag = true;
|
||||
this->Close();
|
||||
}
|
||||
else if (j["msg"].get<std::string>() == "quit") {
|
||||
this->Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
|
||||
// BBS
|
||||
m_sizer_advanced->AddSpacer(FromDIP(10));
|
||||
auto tip_message_panel = new wxPanel(m_page_advanced, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
tip_message_panel->SetBackgroundColour(wxColour(238, 238, 238));
|
||||
auto message_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
tip_message_panel->SetSizer(message_sizer);
|
||||
{
|
||||
wxString message = _L("Orca would re-calculate your flushing volumes every time the filaments color changed. You could disable the auto-calculate in Orca Slicer > Preferences");
|
||||
m_tip_message_label = new Label(tip_message_panel, wxEmptyString);
|
||||
wxClientDC dc(tip_message_panel);
|
||||
wxString multiline_message;
|
||||
m_tip_message_label->split_lines(dc, sizer_width, message, multiline_message);
|
||||
m_tip_message_label->SetLabel(multiline_message);
|
||||
m_tip_message_label->SetFont(Label::Body_13);
|
||||
message_sizer->Add(m_tip_message_label, 0, wxEXPAND | wxALL, TIP_MESSAGES_PADDING);
|
||||
}
|
||||
m_sizer_advanced->Add(tip_message_panel, 0, wxEXPAND | wxRIGHT | wxLEFT, TABLE_BORDER);
|
||||
bool is_show = wxGetApp().app_config->get("auto_calculate_flush") != "disabled";
|
||||
tip_message_panel->Show(is_show);
|
||||
m_sizer_advanced->AddSpacer(FromDIP(10));
|
||||
auto calc_btn_sizer = create_calc_btn_sizer(m_page_advanced);
|
||||
m_sizer_advanced->Add(calc_btn_sizer, 0, wxEXPAND | wxLEFT, FromDIP(30));
|
||||
|
||||
//m_sizer_advanced->AddSpacer(FromDIP(10));
|
||||
m_sizer_advanced->AddSpacer(FromDIP(5));
|
||||
header_line_panel = new wxPanel(m_page_advanced, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
header_line_panel->SetBackgroundColour(wxColour(238, 238, 238));
|
||||
auto header_line_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
header_line_panel->SetSizer(header_line_sizer);
|
||||
|
||||
header_line_sizer->AddSpacer(HEADER_BEG_PADDING);
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i) {
|
||||
wxButton* icon = new wxButton(header_line_panel, wxID_ANY, {}, wxDefaultPosition, ICON_SIZE, wxBORDER_NONE | wxBU_AUTODRAW);
|
||||
icon->SetBitmap(*get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(i + 1), FromDIP(16), FromDIP(16)));
|
||||
icon->SetCanFocus(false);
|
||||
icon_list1.push_back(icon);
|
||||
|
||||
header_line_sizer->AddSpacer(ICON_GAP);
|
||||
header_line_sizer->Add(icon, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, HEADER_VERT_PADDING);
|
||||
}
|
||||
header_line_sizer->AddSpacer(HEADER_END_PADDING);
|
||||
|
||||
m_sizer_advanced->Add(header_line_panel, 0, wxEXPAND | wxRIGHT | wxLEFT, TABLE_BORDER);
|
||||
|
||||
create_panels(m_page_advanced, m_number_of_extruders);
|
||||
|
||||
//m_sizer_advanced->AddSpacer(BTN_SIZE.y);
|
||||
|
||||
// BBS: for tunning flush volumes
|
||||
{
|
||||
auto multi_desc_label = new wxStaticText(m_page_advanced, wxID_ANY, _(L("Flushing volume (mm³) for each filament pair.")), wxDefaultPosition, wxDefaultSize, 0);
|
||||
multi_desc_label->SetForegroundColour(g_text_color);
|
||||
m_sizer_advanced->Add(multi_desc_label, 0, wxEXPAND | wxLEFT, TEXT_BEG_PADDING);
|
||||
|
||||
wxString min_flush_str = wxString::Format(_L("Suggestion: Flushing Volume in range [%d, %d]"),*std::min_element(m_min_flush_volume[m_cur_extruder_id].begin(), m_min_flush_volume[m_cur_extruder_id].end()), m_max_flush_volume);
|
||||
m_min_flush_label = new wxStaticText(m_page_advanced, wxID_ANY, min_flush_str, wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_min_flush_label->SetForegroundColour(g_text_color);
|
||||
m_sizer_advanced->Add(m_min_flush_label, 0, wxEXPAND | wxLEFT, TEXT_BEG_PADDING);
|
||||
|
||||
auto on_apply_text_modify = [this](wxEvent& e) {
|
||||
wxString str = m_flush_multiplier_ebox->GetValue();
|
||||
float multiplier = wxAtof(str);
|
||||
if (multiplier < g_min_flush_multiplier || multiplier > g_max_flush_multiplier) {
|
||||
str = wxString::Format(("%.2f"), multiplier < g_min_flush_multiplier ? g_min_flush_multiplier : g_max_flush_multiplier);
|
||||
m_flush_multiplier_ebox->SetValue(str);
|
||||
m_flush_multiplier[m_cur_extruder_id] = wxAtof(m_flush_multiplier_ebox->GetValue());
|
||||
MessageDialog dlg(nullptr,
|
||||
wxString::Format(_L("The multiplier should be in range [%.2f, %.2f]."), g_min_flush_multiplier, g_max_flush_multiplier),
|
||||
_L("Warning"), wxICON_WARNING | wxOK);
|
||||
dlg.ShowModal();
|
||||
}
|
||||
else {
|
||||
m_flush_multiplier[m_cur_extruder_id] = multiplier;
|
||||
}
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i) {
|
||||
for (unsigned int j = 0; j < m_number_of_extruders; ++j) {
|
||||
edit_boxes[i][j]->SetValue(to_string(int(m_display_matrix[m_number_of_extruders * j + i] * multiplier)));
|
||||
}
|
||||
}
|
||||
|
||||
this->update_warning_texts();
|
||||
e.Skip();
|
||||
};
|
||||
|
||||
m_sizer_advanced->AddSpacer(10);
|
||||
|
||||
wxBoxSizer* param_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxStaticText* flush_multiplier_title = new wxStaticText(m_page_advanced, wxID_ANY, _L("Multiplier"));
|
||||
param_sizer->Add(flush_multiplier_title, 0, wxALIGN_CENTER | wxALL, 0);
|
||||
param_sizer->AddSpacer(FromDIP(5));
|
||||
m_flush_multiplier_ebox = new wxTextCtrl(m_page_advanced, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(50), -1), wxTE_PROCESS_ENTER);
|
||||
m_flush_multiplier_ebox->SetValue(wxString::Format(("%.2f"), m_flush_multiplier[m_cur_extruder_id]));
|
||||
m_flush_multiplier_ebox->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
|
||||
param_sizer->Add(m_flush_multiplier_ebox, 0, wxALIGN_CENTER | wxALL, 0);
|
||||
param_sizer->AddStretchSpacer(1);
|
||||
m_sizer_advanced->Add(param_sizer, 0, wxEXPAND | wxLEFT, TEXT_BEG_PADDING);
|
||||
|
||||
m_flush_multiplier_ebox->Bind(wxEVT_TEXT_ENTER, on_apply_text_modify);
|
||||
m_flush_multiplier_ebox->Bind(wxEVT_KILL_FOCUS, on_apply_text_modify);
|
||||
m_flush_multiplier_ebox->Bind(wxEVT_COMMAND_TEXT_UPDATED, [this](wxCommandEvent&) {
|
||||
wxString str = m_flush_multiplier_ebox->GetValue();
|
||||
float multiplier = wxAtof(str);
|
||||
if (multiplier < g_min_flush_multiplier || multiplier > g_max_flush_multiplier) {
|
||||
str = wxString::Format(("%.2f"), multiplier < g_min_flush_multiplier ? g_min_flush_multiplier : g_max_flush_multiplier);
|
||||
m_flush_multiplier_ebox->SetValue(str);
|
||||
m_flush_multiplier[m_cur_extruder_id] = wxAtof(m_flush_multiplier_ebox->GetValue());
|
||||
}
|
||||
else {
|
||||
m_flush_multiplier[m_cur_extruder_id] = multiplier;
|
||||
}
|
||||
m_flush_multiplier_ebox->SetInsertionPointEnd();
|
||||
}
|
||||
});
|
||||
}
|
||||
this->update_warning_texts();
|
||||
|
||||
m_page_advanced->Hide();
|
||||
|
||||
// Now the same for simple mode:
|
||||
gridsizer_simple->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString("")), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
gridsizer_simple->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString(_(L("unloaded")))), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
gridsizer_simple->Add(new wxStaticText(m_page_simple,wxID_ANY,wxString(_(L("loaded")))), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
auto add_spin_ctrl = [this](std::vector<wxSpinCtrl*>& vec, float initial)
|
||||
{
|
||||
wxSpinCtrl* spin_ctrl = new wxSpinCtrl(m_page_simple, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(ITEM_WIDTH(), -1), style | wxALIGN_RIGHT, 0, 300, (int)initial);
|
||||
update_ui(spin_ctrl);
|
||||
vec.push_back(spin_ctrl);
|
||||
|
||||
#ifdef __WXOSX__
|
||||
// On OSX / Cocoa, wxSpinCtrl::GetValue() doesn't return the new value
|
||||
// when it was changed from the text control, so the on_change callback
|
||||
// gets the old one, and on_kill_focus resets the control to the old value.
|
||||
// As a workaround, we get the new value from $event->GetString and store
|
||||
// here temporarily so that we can return it from get_value()
|
||||
spin_ctrl->Bind(wxEVT_TEXT, ([spin_ctrl](wxCommandEvent e)
|
||||
{
|
||||
long value;
|
||||
const bool parsed = e.GetString().ToLong(&value);
|
||||
int tmp_value = parsed && value >= INT_MIN && value <= INT_MAX ? (int)value : INT_MIN;
|
||||
|
||||
// Forcibly set the input value for SpinControl, since the value
|
||||
// inserted from the keyboard or clipboard is not updated under OSX
|
||||
if (tmp_value != INT_MIN) {
|
||||
spin_ctrl->SetValue(tmp_value);
|
||||
|
||||
// But in SetValue() is executed m_text_ctrl->SelectAll(), so
|
||||
// discard this selection and set insertion point to the end of string
|
||||
spin_ctrl->GetText()->SetInsertionPointEnd();
|
||||
}
|
||||
}), spin_ctrl->GetId());
|
||||
#endif
|
||||
};
|
||||
|
||||
for (unsigned int i=0;i<m_number_of_extruders;++i) {
|
||||
add_spin_ctrl(m_old, extruders[2 * i]);
|
||||
add_spin_ctrl(m_new, extruders[2 * i+1]);
|
||||
|
||||
auto hsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxWindow* w = new wxWindow(m_page_simple, wxID_ANY, wxDefaultPosition, ICON_SIZE, wxBORDER_SIMPLE);
|
||||
w->SetCanFocus(false);
|
||||
w->SetBackgroundColour(m_colours[i]);
|
||||
hsizer->Add(w, wxALIGN_CENTER_VERTICAL);
|
||||
hsizer->AddSpacer(10);
|
||||
hsizer->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString(_(L("Filament #"))) << i + 1 << ": "), 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
gridsizer_simple->Add(hsizer, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL);
|
||||
gridsizer_simple->Add(m_old.back(),0);
|
||||
gridsizer_simple->Add(m_new.back(),0);
|
||||
}
|
||||
|
||||
m_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_sizer->Add(m_page_simple, 0, wxEXPAND, 0);
|
||||
m_sizer->Add(m_page_advanced, 0, wxEXPAND, 0);
|
||||
|
||||
m_sizer->SetSizeHints(this);
|
||||
SetSizer(m_sizer);
|
||||
this->Layout();
|
||||
|
||||
toggle_advanced(); // to show/hide what is appropriate
|
||||
|
||||
header_line_panel->Bind(wxEVT_PAINT, [this](wxPaintEvent&) {
|
||||
wxPaintDC dc(header_line_panel);
|
||||
wxString from_text = _L("From");
|
||||
wxString to_text = _L("To");
|
||||
wxSize from_text_size = dc.GetTextExtent(from_text);
|
||||
wxSize to_text_size = dc.GetTextExtent(to_text);
|
||||
|
||||
int base_y = (header_line_panel->GetSize().y - from_text_size.y - to_text_size.y) / 2;
|
||||
int vol_width = ROW_BEG_PADDING + EDIT_BOXES_GAP / 2 + ICON_SIZE.x;
|
||||
int base_x = (vol_width - from_text_size.x - to_text_size.x) / 2;
|
||||
|
||||
// draw from text
|
||||
int x = base_x;
|
||||
int y = base_y + to_text_size.y;
|
||||
dc.DrawText(from_text, x, y);
|
||||
|
||||
// draw to text
|
||||
x = base_x + from_text_size.x;
|
||||
y = base_y;
|
||||
dc.DrawText(to_text, x, y);
|
||||
|
||||
// draw a line
|
||||
int p1_x = base_x + from_text_size.x - to_text_size.y;
|
||||
int p1_y = base_y;
|
||||
int p2_x = base_x + from_text_size.x + from_text_size.y;
|
||||
int p2_y = base_y + from_text_size.y + to_text_size.y;
|
||||
dc.SetPen(wxPen(wxColour(172, 172, 172, 1)));
|
||||
dc.DrawLine(p1_x, p1_y, p2_x, p2_y);
|
||||
});
|
||||
}
|
||||
|
||||
int WipingPanel::calc_flushing_volume(const wxColour& from_, const wxColour& to_ ,int min_flush_volume)
|
||||
{
|
||||
Slic3r::FlushVolCalculator calculator(min_flush_volume, m_max_flush_volume);
|
||||
|
||||
return calculator.calc_flush_vol(from_.Alpha(), from_.Red(), from_.Green(), from_.Blue(), to_.Alpha(), to_.Red(), to_.Green(), to_.Blue());
|
||||
int WipingDialog::CalcFlushingVolume(const wxColour& from, const wxColour& to, int min_flush_volume)
|
||||
{
|
||||
Slic3r::FlushVolCalculator calculator(min_flush_volume, Slic3r::g_max_flush_volume);
|
||||
return calculator.calc_flush_vol(from.Alpha(), from.Red(), from.Green(), from.Blue(), to.Alpha(), to.Red(), to.Green(), to.Blue());
|
||||
}
|
||||
|
||||
void WipingPanel::update_warning_texts()
|
||||
WipingDialog::VolumeMatrix WipingDialog::CalcFlushingVolumes(int extruder_id)
|
||||
{
|
||||
static const wxColour g_warning_color = *wxRED;
|
||||
static const wxColour g_normal_color = *wxBLACK;
|
||||
auto& preset_bundle = wxGetApp().preset_bundle;
|
||||
auto full_config = preset_bundle->full_config();
|
||||
auto& ams_multi_color_filament = preset_bundle->ams_multi_color_filment;
|
||||
|
||||
wxString multi_str = m_flush_multiplier_ebox->GetValue();
|
||||
float multiplier = wxAtof(multi_str);
|
||||
|
||||
bool has_exception_flush = false;
|
||||
for (int i = 0; i < edit_boxes.size(); i++) {
|
||||
auto& box_vec = edit_boxes[i];
|
||||
for (int j = 0; j < box_vec.size(); j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
|
||||
auto text_box = box_vec[j];
|
||||
wxString str = text_box->GetValue();
|
||||
int actual_volume = wxAtoi(str);
|
||||
if (actual_volume < m_min_flush_volume[m_cur_extruder_id][i] || actual_volume > m_max_flush_volume) {
|
||||
if (text_box->GetForegroundColour() != g_warning_color) {
|
||||
text_box->SetForegroundColour(g_warning_color);
|
||||
text_box->Refresh();
|
||||
}
|
||||
has_exception_flush = true;
|
||||
}
|
||||
else {
|
||||
if (text_box->GetForegroundColour() != g_normal_color) {
|
||||
text_box->SetForegroundColour(StateColor::darkModeColorFor(g_normal_color));
|
||||
text_box->Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_exception_flush && m_min_flush_label->GetForegroundColour() != g_warning_color) {
|
||||
m_min_flush_label->SetForegroundColour(g_warning_color);
|
||||
m_min_flush_label->Refresh();
|
||||
}
|
||||
else if (!has_exception_flush && m_min_flush_label->GetForegroundColour() != g_text_color) {
|
||||
m_min_flush_label->SetForegroundColour(g_text_color);
|
||||
m_min_flush_label->Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void WipingPanel::calc_flushing_volumes()
|
||||
{
|
||||
auto& ams_multi_color_filament = wxGetApp().preset_bundle->ams_multi_color_filment;
|
||||
std::vector<std::string> filament_color_strs = full_config.option<ConfigOptionStrings>("filament_colour")->values;
|
||||
std::vector<std::vector<wxColour>> multi_colors;
|
||||
std::vector<wxColour> filament_colors;
|
||||
for (auto color_str : filament_color_strs)
|
||||
filament_colors.emplace_back(color_str);
|
||||
|
||||
// Support for multi-color filament
|
||||
for (int i = 0; i < m_colours.size(); ++i) {
|
||||
for (int i = 0; i < filament_colors.size(); ++i) {
|
||||
std::vector<wxColour> single_filament;
|
||||
if (i < ams_multi_color_filament.size()) {
|
||||
if (!ams_multi_color_filament[i].empty()) {
|
||||
|
|
@ -755,169 +411,64 @@ void WipingPanel::calc_flushing_volumes()
|
|||
continue;
|
||||
}
|
||||
}
|
||||
single_filament.push_back(wxColour(m_colours[i]));
|
||||
single_filament.push_back(wxColour(filament_colors[i]));
|
||||
multi_colors.push_back(single_filament);
|
||||
}
|
||||
|
||||
VolumeMatrix matrix;
|
||||
|
||||
for (int from_idx = 0; from_idx < multi_colors.size(); ++from_idx) {
|
||||
bool is_from_support = is_support_filament(from_idx);
|
||||
matrix.emplace_back();
|
||||
for (int to_idx = 0; to_idx < multi_colors.size(); ++to_idx) {
|
||||
bool is_to_support = is_support_filament(to_idx);
|
||||
if (from_idx == to_idx) {
|
||||
edit_boxes[to_idx][from_idx]->SetValue(std::to_string(0));
|
||||
matrix.back().emplace_back(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_to_support = is_support_filament(to_idx);
|
||||
|
||||
int flushing_volume = 0;
|
||||
if (is_to_support) {
|
||||
flushing_volume = Slic3r::g_flush_volume_to_support;
|
||||
}
|
||||
else {
|
||||
int flushing_volume = 0;
|
||||
if (is_to_support) {
|
||||
flushing_volume = Slic3r::g_flush_volume_to_support;
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < multi_colors[from_idx].size(); ++i) {
|
||||
const wxColour& from = multi_colors[from_idx][i];
|
||||
for (int j = 0; j < multi_colors[to_idx].size(); ++j) {
|
||||
const wxColour& to = multi_colors[to_idx][j];
|
||||
int volume = calc_flushing_volume(from, to, m_min_flush_volume[m_cur_extruder_id][from_idx]);
|
||||
flushing_volume = std::max(flushing_volume, volume);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_from_support) {
|
||||
flushing_volume = std::max(Slic3r::g_min_flush_volume_from_support, flushing_volume);
|
||||
for (int i = 0; i < multi_colors[from_idx].size(); ++i) {
|
||||
const wxColour& from = multi_colors[from_idx][i];
|
||||
for (int j = 0; j < multi_colors[to_idx].size(); ++j) {
|
||||
const wxColour& to = multi_colors[to_idx][j];
|
||||
int volume = CalcFlushingVolume(from, to, m_extra_flush_volume[extruder_id][from_idx]);
|
||||
flushing_volume = std::max(flushing_volume, volume);
|
||||
}
|
||||
}
|
||||
|
||||
m_display_matrix[m_number_of_extruders * from_idx + to_idx] = flushing_volume;
|
||||
flushing_volume = int(flushing_volume * get_flush_multiplier());
|
||||
edit_boxes[to_idx][from_idx]->SetValue(std::to_string(flushing_volume));
|
||||
if (is_from_support) {
|
||||
flushing_volume = std::max(Slic3r::g_min_flush_volume_from_support, flushing_volume);
|
||||
}
|
||||
}
|
||||
matrix.back().emplace_back(flushing_volume);
|
||||
}
|
||||
}
|
||||
|
||||
this->update_warning_texts();
|
||||
return matrix;
|
||||
}
|
||||
|
||||
void WipingPanel::msw_rescale()
|
||||
void WipingDialog::StoreFlushData(int extruder_num, const std::vector<std::vector<double>>& flush_volume_vecs, const std::vector<double>&flush_multipliers)
|
||||
{
|
||||
for (unsigned int i = 0; i < icon_list1.size(); ++i) {
|
||||
auto bitmap = *get_extruder_color_icon(m_colours[i].GetAsString(wxC2S_HTML_SYNTAX).ToStdString(), std::to_string(i + 1), FromDIP(16), FromDIP(16));
|
||||
icon_list1[i]->SetBitmap(bitmap);
|
||||
icon_list2[i]->SetBitmap(bitmap);
|
||||
}
|
||||
m_flush_multipliers = flush_multipliers;
|
||||
m_raw_matrixs = flush_volume_vecs;
|
||||
}
|
||||
|
||||
// Reads values from the (advanced) wiping matrix:
|
||||
std::vector<float> WipingPanel::read_matrix_values() {
|
||||
if (!m_advanced)
|
||||
fill_in_matrix();
|
||||
std::vector<float> output;
|
||||
for (unsigned int i=0;i<m_number_of_extruders;++i) {
|
||||
for (unsigned int j=0;j<m_number_of_extruders;++j) {
|
||||
double val = 0.;
|
||||
float flush_multipler = get_flush_multiplier();
|
||||
if (flush_multipler == 0) {
|
||||
output.push_back(0.);
|
||||
}
|
||||
else {
|
||||
edit_boxes[j][i]->GetValue().ToDouble(&val);
|
||||
output.push_back((float) val / get_flush_multiplier());
|
||||
}
|
||||
}
|
||||
}
|
||||
m_display_matrix = output;
|
||||
back_matrix();
|
||||
return m_matrix;
|
||||
}
|
||||
|
||||
// Reads values from simple mode to save them for next time:
|
||||
std::vector<float> WipingPanel::read_extruders_values() {
|
||||
std::vector<float> output;
|
||||
for (unsigned int i=0;i<m_number_of_extruders;++i) {
|
||||
output.push_back(m_old[i]->GetValue());
|
||||
output.push_back(m_new[i]->GetValue());
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// This updates the "advanced" matrix based on values from "simple" mode
|
||||
void WipingPanel::fill_in_matrix() {
|
||||
for (unsigned i=0;i<m_number_of_extruders;++i) {
|
||||
for (unsigned j=0;j<m_number_of_extruders;++j) {
|
||||
if (i==j) continue;
|
||||
edit_boxes[j][i]->SetValue(wxString("")<< (m_old[i]->GetValue() + m_new[j]->GetValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WipingPanel::generate_display_matrix()
|
||||
std::vector<double> WipingDialog::GetFlattenMatrix()const
|
||||
{
|
||||
m_display_matrix = get_flush_volumes_matrix(m_matrix, m_cur_extruder_id, m_nozzle_nums);
|
||||
std::vector<double> ret;
|
||||
for (auto& matrix : m_raw_matrixs) {
|
||||
ret.insert(ret.end(), matrix.begin(), matrix.end());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void WipingPanel::back_matrix()
|
||||
|
||||
std::vector<double> WipingDialog::GetMultipliers()const
|
||||
{
|
||||
set_flush_volumes_matrix(m_matrix, m_display_matrix, m_cur_extruder_id, m_nozzle_nums);
|
||||
}
|
||||
|
||||
void WipingPanel::update_table()
|
||||
{
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i) {
|
||||
for (unsigned int j = 0; j < m_number_of_extruders; ++j) {
|
||||
if (i == j) {
|
||||
edit_boxes[i][j]->SetValue(wxString("0"));
|
||||
edit_boxes[i][j]->SetEditable(false);
|
||||
} else {
|
||||
edit_boxes[i][j]->SetValue(wxString("") << int(m_display_matrix[m_number_of_extruders * j + i] * m_flush_multiplier[m_cur_extruder_id]));
|
||||
}
|
||||
}
|
||||
}
|
||||
wxString str = wxString::Format(("%.2f"), m_flush_multiplier[m_cur_extruder_id]);
|
||||
m_flush_multiplier_ebox->SetValue(str);
|
||||
update_warning_texts();
|
||||
}
|
||||
|
||||
void WipingPanel::on_select_extruder(wxCommandEvent &evt)
|
||||
{
|
||||
ComboBox *comboBox = dynamic_cast<ComboBox *>(evt.GetEventObject());
|
||||
if (comboBox) {
|
||||
int selection = comboBox->GetSelection();
|
||||
if (m_cur_extruder_id != selection) {
|
||||
read_matrix_values();
|
||||
m_cur_extruder_id = selection;
|
||||
generate_display_matrix();
|
||||
update_table();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function to check if simple and advanced settings are matching
|
||||
bool WipingPanel::advanced_matches_simple() {
|
||||
for (unsigned i=0;i<m_number_of_extruders;++i) {
|
||||
for (unsigned j=0;j<m_number_of_extruders;++j) {
|
||||
if (i==j) continue;
|
||||
if (edit_boxes[j][i]->GetValue() != (wxString("")<< (m_old[i]->GetValue() + m_new[j]->GetValue())))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Switches the dialog from simple to advanced mode and vice versa
|
||||
void WipingPanel::toggle_advanced(bool user_action) {
|
||||
if (user_action)
|
||||
m_advanced = !m_advanced; // user demands a change -> toggle
|
||||
else {
|
||||
// BBS: show advanced mode by default
|
||||
//m_advanced = !advanced_matches_simple(); // if called from constructor, show what is appropriate
|
||||
m_advanced = true;
|
||||
}
|
||||
|
||||
(m_advanced ? m_page_advanced : m_page_simple)->Show();
|
||||
(!m_advanced ? m_page_advanced : m_page_simple)->Hide();
|
||||
|
||||
if (m_advanced)
|
||||
if (user_action) fill_in_matrix(); // otherwise keep values loaded from config
|
||||
|
||||
m_sizer->Layout();
|
||||
Refresh();
|
||||
return m_flush_multipliers;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,11 @@
|
|||
#ifndef _WIPE_TOWER_DIALOG_H_
|
||||
#define _WIPE_TOWER_DIALOG_H_
|
||||
|
||||
#include "GUI_Utils.hpp"
|
||||
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/webview.h>
|
||||
|
||||
#include "Widgets/SpinInput.hpp"
|
||||
|
||||
#include "RammingChart.hpp"
|
||||
class Button;
|
||||
class Label;
|
||||
|
||||
|
||||
class RammingPanel : public wxPanel {
|
||||
|
|
@ -45,106 +36,31 @@ private:
|
|||
std::string m_output_data;
|
||||
};
|
||||
|
||||
class WipingPanel : public wxPanel {
|
||||
public:
|
||||
// BBS
|
||||
WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, size_t cur_extruder_id,
|
||||
const std::vector<std::string>& extruder_colours, Button* calc_button,
|
||||
const std::vector<std::vector<int>>& extra_flush_volume, const std::vector<float>& flush_multiplier, size_t nozzle_nums);
|
||||
std::vector<float> read_matrix_values();
|
||||
std::vector<float> read_extruders_values();
|
||||
void toggle_advanced(bool user_action = false);
|
||||
void create_panels(wxWindow* parent, const int num);
|
||||
void calc_flushing_volumes();
|
||||
void msw_rescale();
|
||||
wxBoxSizer* create_calc_btn_sizer(wxWindow* parent);
|
||||
|
||||
float get_flush_multiplier()
|
||||
{
|
||||
if (m_flush_multiplier_ebox == nullptr)
|
||||
return 1.f;
|
||||
|
||||
return wxAtof(m_flush_multiplier_ebox->GetValue());
|
||||
}
|
||||
|
||||
std::vector<float> get_flush_multiplier_vector() { return m_flush_multiplier; }
|
||||
|
||||
private:
|
||||
void on_select_extruder(wxCommandEvent &evt);
|
||||
void generate_display_matrix(); // generate display_matrix frem matrix
|
||||
void back_matrix();
|
||||
void update_table(); // if matrix is modified update the table
|
||||
void fill_in_matrix();
|
||||
bool advanced_matches_simple();
|
||||
int calc_flushing_volume(const wxColour& from, const wxColour& to,int min_flush_volume);
|
||||
void update_warning_texts();
|
||||
|
||||
std::vector<wxSpinCtrl*> m_old;
|
||||
std::vector<wxSpinCtrl*> m_new;
|
||||
std::vector<std::vector<wxTextCtrl*>> edit_boxes;
|
||||
std::vector<wxColour> m_colours;
|
||||
unsigned int m_number_of_extruders = 0;
|
||||
bool m_advanced = false;
|
||||
wxPanel* m_page_simple = nullptr;
|
||||
wxPanel* m_page_advanced = nullptr;
|
||||
wxPanel* header_line_panel = nullptr;
|
||||
wxBoxSizer* m_sizer = nullptr;
|
||||
wxBoxSizer* m_sizer_simple = nullptr;
|
||||
wxBoxSizer* m_sizer_advanced = nullptr;
|
||||
wxGridSizer* m_gridsizer_advanced = nullptr;
|
||||
wxButton* m_widget_button = nullptr;
|
||||
Label* m_tip_message_label = nullptr;
|
||||
|
||||
std::vector<wxButton *> icon_list1;
|
||||
std::vector<wxButton *> icon_list2;
|
||||
|
||||
const std::vector<std::vector<int>> m_min_flush_volume;
|
||||
const int m_max_flush_volume;
|
||||
|
||||
wxTextCtrl* m_flush_multiplier_ebox = nullptr;
|
||||
wxStaticText* m_min_flush_label = nullptr;
|
||||
|
||||
std::vector<float> m_flush_multiplier;
|
||||
std::vector<float> m_matrix;
|
||||
std::vector<float> m_display_matrix;
|
||||
size_t m_cur_extruder_id;
|
||||
size_t m_nozzle_nums;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class WipingDialog : public Slic3r::GUI::DPIDialog
|
||||
class WipingDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
WipingDialog(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, const std::vector<std::string>& extruder_colours,
|
||||
const std::vector<std::vector<int>>&extra_flush_volume, const std::vector<float>& flush_multiplier, size_t nozzle_nums);
|
||||
std::vector<float> get_matrix() const { return m_output_matrix; }
|
||||
std::vector<float> get_extruders() const { return m_output_extruders; }
|
||||
wxBoxSizer* create_btn_sizer(long flags);
|
||||
using VolumeMatrix = std::vector<std::vector<double>>;
|
||||
|
||||
float get_flush_multiplier()
|
||||
{
|
||||
if (m_panel_wiping == nullptr)
|
||||
return 1.f;
|
||||
|
||||
return m_panel_wiping->get_flush_multiplier();
|
||||
}
|
||||
|
||||
std::vector<float> get_flush_multiplier_vector() const {
|
||||
if (m_panel_wiping == nullptr)
|
||||
return {1.f, 1.f};
|
||||
return m_panel_wiping->get_flush_multiplier_vector();
|
||||
}
|
||||
|
||||
void on_dpi_changed(const wxRect &suggested_rect) override;
|
||||
WipingDialog(wxWindow* parent,const std::vector<std::vector<int>>& extra_flush_volume, const int max_flush_volume = Slic3r::g_max_flush_volume);
|
||||
VolumeMatrix CalcFlushingVolumes(int extruder_id);
|
||||
std::vector<double> GetFlattenMatrix()const;
|
||||
std::vector<double> GetMultipliers()const;
|
||||
bool GetSubmitFlag() const { return m_submit_flag; }
|
||||
|
||||
private:
|
||||
WipingPanel* m_panel_wiping = nullptr;
|
||||
std::vector<float> m_output_matrix;
|
||||
std::vector<float> m_output_extruders;
|
||||
std::unordered_map<int, Button *> m_button_list;
|
||||
int CalcFlushingVolume(const wxColour& from_, const wxColour& to_, int min_flush_volume);
|
||||
wxString BuildTableObjStr();
|
||||
wxString BuildTextObjStr();
|
||||
void StoreFlushData(int extruder_num, const std::vector<std::vector<double>>& flush_volume_vecs, const std::vector<double>& flush_multipliers);
|
||||
|
||||
wxWebView* m_webview;
|
||||
std::vector<std::vector<int>> m_extra_flush_volume;
|
||||
int m_max_flush_volume;
|
||||
|
||||
VolumeMatrix m_raw_matrixs;
|
||||
std::vector<double> m_flush_multipliers;
|
||||
bool m_submit_flag{ false };
|
||||
};
|
||||
|
||||
#endif // _WIPE_TOWER_DIALOG_H_
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue