mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-18 08:22:06 +00:00
Add timelapse storage location selection
This commit is contained in:
3
resources/images/folder-closed-active.svg
Normal file
3
resources/images/folder-closed-active.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.88802 4.48958C8.16145 4.76302 8.53124 4.91667 8.91927 4.91667H13C13.2292 4.91667 13.4167 5.10417 13.4167 5.33333V6.16667H2.58333V3.66667C2.58333 3.4375 2.77083 3.25 2.99999 3.25H6.47656C6.58593 3.25 6.6927 3.29427 6.77083 3.3724L7.88802 4.48958ZM2.58333 7.41667H13.4167V12C13.4167 12.2292 13.2292 12.4167 13 12.4167H2.99999C2.77083 12.4167 2.58333 12.2292 2.58333 12V7.41667ZM8.77343 3.60677L7.65364 2.48698C7.34114 2.17448 6.91666 2 6.47395 2H2.99999C2.08072 2 1.33333 2.7474 1.33333 3.66667V12C1.33333 12.9193 2.08072 13.6667 2.99999 13.6667H13C13.9193 13.6667 14.6667 12.9193 14.6667 12V5.33333C14.6667 4.41406 13.9193 3.66667 13 3.66667H8.91927C8.86458 3.66667 8.80989 3.64583 8.77083 3.60677H8.77343Z" fill="#009688"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 839 B |
3
resources/images/folder-closed-hover.svg
Normal file
3
resources/images/folder-closed-hover.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.88802 4.48958C8.16145 4.76302 8.53124 4.91667 8.91927 4.91667H13C13.2292 4.91667 13.4167 5.10417 13.4167 5.33333V6.16667H2.58333V3.66667C2.58333 3.4375 2.77083 3.25 2.99999 3.25H6.47656C6.58593 3.25 6.6927 3.29427 6.77083 3.3724L7.88802 4.48958ZM2.58333 7.41667H13.4167V12C13.4167 12.2292 13.2292 12.4167 13 12.4167H2.99999C2.77083 12.4167 2.58333 12.2292 2.58333 12V7.41667ZM8.77343 3.60677L7.65364 2.48698C7.34114 2.17448 6.91666 2 6.47395 2H2.99999C2.08072 2 1.33333 2.7474 1.33333 3.66667V12C1.33333 12.9193 2.08072 13.6667 2.99999 13.6667H13C13.9193 13.6667 14.6667 12.9193 14.6667 12V5.33333C14.6667 4.41406 13.9193 3.66667 13 3.66667H8.91927C8.86458 3.66667 8.80989 3.64583 8.77083 3.60677H8.77343Z" fill="#6B6B6B"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 839 B |
3
resources/images/folder-closed.svg
Normal file
3
resources/images/folder-closed.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.88802 4.48958C8.16145 4.76302 8.53124 4.91667 8.91927 4.91667H13C13.2292 4.91667 13.4167 5.10417 13.4167 5.33333V6.16667H2.58333V3.66667C2.58333 3.4375 2.77083 3.25 2.99999 3.25H6.47656C6.58593 3.25 6.6927 3.29427 6.77083 3.3724L7.88802 4.48958ZM2.58333 7.41667H13.4167V12C13.4167 12.2292 13.2292 12.4167 13 12.4167H2.99999C2.77083 12.4167 2.58333 12.2292 2.58333 12V7.41667ZM8.77343 3.60677L7.65364 2.48698C7.34114 2.17448 6.91666 2 6.47395 2H2.99999C2.08072 2 1.33333 2.7474 1.33333 3.66667V12C1.33333 12.9193 2.08072 13.6667 2.99999 13.6667H13C13.9193 13.6667 14.6667 12.9193 14.6667 12V5.33333C14.6667 4.41406 13.9193 3.66667 13 3.66667H8.91927C8.86458 3.66667 8.80989 3.64583 8.77083 3.60677H8.77343Z" fill="#262E30"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 839 B |
@@ -262,6 +262,7 @@ void PrintJob::process(Ctl &ctl)
|
||||
params.task_vibration_cali = this->task_vibration_cali;
|
||||
params.task_layer_inspect = this->task_layer_inspect;
|
||||
params.task_record_timelapse= this->task_record_timelapse;
|
||||
params.task_timelapse_use_internal = this->task_timelapse_use_internal;
|
||||
params.nozzle_mapping = this->task_nozzle_mapping;
|
||||
params.ams_mapping = this->task_ams_mapping;
|
||||
params.ams_mapping2 = this->task_ams_mapping2;
|
||||
|
||||
@@ -80,6 +80,7 @@ public:
|
||||
bool task_flow_cali;
|
||||
bool task_vibration_cali;
|
||||
bool task_record_timelapse;
|
||||
bool task_timelapse_use_internal { false };
|
||||
bool task_layer_inspect;
|
||||
bool cloud_print_only { false };
|
||||
bool has_sdcard { false };
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "Widgets/StaticBox.hpp"
|
||||
#include "Widgets/CheckBox.hpp"
|
||||
#include "Widgets/Label.hpp"
|
||||
#include "Widgets/RadioBox.hpp"
|
||||
#include "ConnectPrinter.hpp"
|
||||
#include "Jobs/BoostThreadWorker.hpp"
|
||||
#include "Jobs/PlaterWorker.hpp"
|
||||
@@ -544,6 +545,29 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater)
|
||||
|
||||
auto option_timelapse = new PrintOption(m_options_other, _L("Timelapse"), wxEmptyString, ops_no_auto, "timelapse");
|
||||
|
||||
// timelapse storage location folder button (shown only when is_support_internal_timelapse)
|
||||
m_timelapse_folder_btn = new ScalableButton(m_options_other, wxID_ANY, "folder-closed", wxEmptyString,
|
||||
wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true);
|
||||
m_timelapse_folder_btn->SetBackgroundColour(*wxWHITE);
|
||||
m_timelapse_folder_btn->SetToolTip(_L("Select timelapse storage location"));
|
||||
m_timelapse_folder_btn->Hide();
|
||||
m_timelapse_folder_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
|
||||
show_timelapse_folder_popup();
|
||||
});
|
||||
m_timelapse_folder_btn->Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent& e) {
|
||||
// hover: only switch if popup is not open (popup open = active state)
|
||||
if (!m_timelapse_storage_popup || !m_timelapse_storage_popup->IsShown())
|
||||
m_timelapse_folder_btn->SetBitmap(create_scaled_bitmap("folder-closed-hover", m_timelapse_folder_btn, 16));
|
||||
e.Skip();
|
||||
});
|
||||
m_timelapse_folder_btn->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) {
|
||||
// restore normal (popup open state is handled separately)
|
||||
if (!m_timelapse_storage_popup || !m_timelapse_storage_popup->IsShown())
|
||||
update_timelapse_folder_btn_icon();
|
||||
e.Skip();
|
||||
});
|
||||
option_timelapse->insert_extra_widget(m_timelapse_folder_btn);
|
||||
|
||||
auto option_auto_bed_level = new PrintOption(
|
||||
m_options_other, _L("Auto Bed Leveling"),
|
||||
_L("This checks the flatness of heatbed. Leveling makes extruded height uniform.\n*Automatic mode: Run a leveling check(about 10 seconds). Skip if surface is fine."),
|
||||
@@ -2657,6 +2681,16 @@ void SelectMachineDialog::update_option_opts(MachineObject *obj)
|
||||
|
||||
/*timelapse*/
|
||||
m_checkbox_list["timelapse"]->Show();
|
||||
if (obj->is_support_internal_timelapse) {
|
||||
m_timelapse_folder_btn->Show();
|
||||
if (m_timelapse_storage.empty()) {
|
||||
m_timelapse_storage = "internal";
|
||||
}
|
||||
update_timelapse_folder_btn_icon();
|
||||
} else {
|
||||
m_timelapse_folder_btn->Hide();
|
||||
m_timelapse_storage.clear();
|
||||
}
|
||||
|
||||
/*bed_leveling*/
|
||||
if (obj->is_support_bed_leveling == 2) {
|
||||
@@ -2792,6 +2826,99 @@ void SelectMachineDialog::Enable_Auto_Refill(bool enable)
|
||||
m_ams_backup_tip->Refresh();
|
||||
}
|
||||
|
||||
void SelectMachineDialog::update_timelapse_folder_btn_icon()
|
||||
{
|
||||
if (!m_timelapse_folder_btn) return;
|
||||
// always restore to normal (grey) - active state is managed by popup open/close
|
||||
m_timelapse_folder_btn->SetBitmap(create_scaled_bitmap("folder-closed", m_timelapse_folder_btn, 16));
|
||||
m_timelapse_folder_btn->Refresh();
|
||||
}
|
||||
|
||||
void SelectMachineDialog::show_timelapse_folder_popup()
|
||||
{
|
||||
if (m_timelapse_storage_popup && m_timelapse_storage_popup->IsShown()) {
|
||||
m_timelapse_storage_popup->Dismiss();
|
||||
return;
|
||||
}
|
||||
|
||||
// build popup with rounded corners + light border
|
||||
m_timelapse_storage_popup = new PopupWindow(this, wxBORDER_NONE);
|
||||
m_timelapse_storage_popup->SetBackgroundColour(wxColour(0xF0, 0xF0, 0xF0));
|
||||
m_timelapse_storage_popup->Bind(wxEVT_PAINT, [this](wxPaintEvent&) {
|
||||
wxPaintDC dc(m_timelapse_storage_popup);
|
||||
auto size = m_timelapse_storage_popup->GetSize();
|
||||
dc.SetPen(wxPen(wxColour(0xCE, 0xCE, 0xCE)));
|
||||
dc.SetBrush(wxBrush(wxColour(0xF0, 0xF0, 0xF0)));
|
||||
dc.DrawRoundedRectangle(0, 0, size.x, size.y, FromDIP(8));
|
||||
});
|
||||
|
||||
auto* panel = new wxPanel(m_timelapse_storage_popup, wxID_ANY);
|
||||
panel->SetBackgroundColour(wxColour(0xF0, 0xF0, 0xF0));
|
||||
|
||||
// horizontal layout: [ Internal] [External]
|
||||
auto* sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
DeviceManager* dev_popup = wxGetApp().getDeviceManager();
|
||||
MachineObject* obj_popup = dev_popup ? dev_popup->get_selected_machine() : nullptr;
|
||||
bool has_sdcard = obj_popup && obj_popup->GetStorage()->get_sdcard_state() == DevStorage::SdcardState::HAS_SDCARD_NORMAL;
|
||||
// if external was previously selected but sdcard is now absent, fall back to internal
|
||||
if (!has_sdcard && m_timelapse_storage == "external")
|
||||
m_timelapse_storage = "internal";
|
||||
|
||||
// Reuse the themed RadioBox widget (radio_on / radio_off bitmaps) instead of the
|
||||
// native wxRadioButton: the selected state shows a clear filled dot with good
|
||||
// contrast on every platform, matching the storage selector in SendToPrinter.
|
||||
auto make_item = [&](const wxString& label, const std::string& val, bool enabled) {
|
||||
auto* radio = new RadioBox(panel);
|
||||
radio->SetValue(m_timelapse_storage == val);
|
||||
if (enabled) radio->Enable(); else radio->Disable();
|
||||
|
||||
auto* text = new Label(panel, Label::Body_14, label);
|
||||
text->SetForegroundColour(enabled ? wxColour(0x5C, 0x5C, 0x5C) : wxColour(0xAC, 0xAC, 0xAC));
|
||||
|
||||
if (enabled) {
|
||||
auto on_select = [this, val](wxMouseEvent&) {
|
||||
m_timelapse_storage = val;
|
||||
update_timelapse_folder_btn_icon();
|
||||
if (m_timelapse_storage_popup) m_timelapse_storage_popup->Dismiss();
|
||||
};
|
||||
radio->Bind(wxEVT_LEFT_DOWN, on_select);
|
||||
text->Bind(wxEVT_LEFT_DOWN, on_select);
|
||||
}
|
||||
|
||||
sizer->Add(radio, 0, wxALIGN_CENTER_VERTICAL);
|
||||
sizer->Add(text, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(6));
|
||||
};
|
||||
|
||||
make_item(_L("Internal"), "internal", true);
|
||||
sizer->AddSpacer(FromDIP(16));
|
||||
make_item(_L("External"), "external", has_sdcard);
|
||||
|
||||
panel->SetSizer(sizer);
|
||||
panel->Fit();
|
||||
|
||||
auto* outer = new wxBoxSizer(wxVERTICAL);
|
||||
outer->Add(panel, 0, wxALL, FromDIP(10));
|
||||
m_timelapse_storage_popup->SetSizer(outer);
|
||||
m_timelapse_storage_popup->Fit();
|
||||
|
||||
// restore normal icon when popup is dismissed
|
||||
m_timelapse_storage_popup->Bind(wxEVT_SHOW, [this](wxShowEvent& e) {
|
||||
if (!e.IsShown())
|
||||
update_timelapse_folder_btn_icon();
|
||||
e.Skip();
|
||||
});
|
||||
|
||||
wxPoint pos = m_timelapse_folder_btn->ClientToScreen(wxPoint(0, m_timelapse_folder_btn->GetSize().GetHeight()));
|
||||
m_timelapse_storage_popup->Position(pos, wxSize(0, 0));
|
||||
|
||||
// switch to active icon before showing popup
|
||||
m_timelapse_folder_btn->SetBitmap(create_scaled_bitmap("folder-closed-active", m_timelapse_folder_btn, 16));
|
||||
m_timelapse_folder_btn->Refresh();
|
||||
|
||||
m_timelapse_storage_popup->Popup();
|
||||
}
|
||||
|
||||
void SelectMachineDialog::on_send_print()
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "print_job: on_ok to send";
|
||||
@@ -2965,6 +3092,10 @@ void SelectMachineDialog::on_send_print()
|
||||
pa_manual_mode = (m_checkbox_list["pa_value"]->getValue() == "on") ? 0 : 1;
|
||||
}
|
||||
|
||||
if (timelapse_option && obj_->is_support_internal_timelapse && !m_timelapse_storage.empty()) {
|
||||
m_print_job->task_timelapse_use_internal = (m_timelapse_storage == "internal");
|
||||
}
|
||||
|
||||
m_print_job->set_print_config(
|
||||
MachineBedTypeString[0],
|
||||
(m_checkbox_list["bed_leveling"]->getValue() == "on"),
|
||||
@@ -5774,6 +5905,18 @@ void PrintOption::msw_rescale()
|
||||
update_title_display();
|
||||
}
|
||||
|
||||
void PrintOption::insert_extra_widget(wxWindow* widget)
|
||||
{
|
||||
// insert after title (index 0), before tips (index 1)
|
||||
// sizer layout: [title][tips][stretch][item]
|
||||
// after insert: [title][widget][tips][stretch][item]
|
||||
wxSizer* sizer = GetSizer();
|
||||
if (!sizer || !widget) return;
|
||||
widget->Reparent(this);
|
||||
sizer->Insert(1, widget, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(4));
|
||||
Layout();
|
||||
}
|
||||
|
||||
PrintOptionItem::PrintOptionItem(wxWindow* parent, std::vector<POItem> ops, std::string param)
|
||||
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
|
||||
{
|
||||
|
||||
@@ -228,6 +228,7 @@ public:
|
||||
void update_options(std::vector<POItem> ops, const wxString &tips);
|
||||
void update_tooltip(const wxString &tips);
|
||||
void update_title_display();
|
||||
void insert_extra_widget(wxWindow* widget);
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
@@ -335,6 +336,11 @@ private:
|
||||
std::string m_required_data_file_name;
|
||||
std::string m_required_data_file_path;
|
||||
|
||||
// timelapse internal storage selection
|
||||
std::string m_timelapse_storage; // "internal" or "external"; empty = unsupported
|
||||
ScalableButton* m_timelapse_folder_btn { nullptr };
|
||||
PopupWindow* m_timelapse_storage_popup { nullptr };
|
||||
|
||||
std::vector<POItem> ops_auto;
|
||||
std::vector<POItem> ops_no_auto;
|
||||
|
||||
@@ -572,6 +578,10 @@ private:
|
||||
void update_option_opts(MachineObject *obj);
|
||||
void update_options_layout();
|
||||
|
||||
/* timelapse storage-location selector */
|
||||
void update_timelapse_folder_btn_icon();
|
||||
void show_timelapse_folder_popup();
|
||||
|
||||
// save and restore from config
|
||||
void load_option_vals(MachineObject* obj);
|
||||
void save_option_vals();
|
||||
|
||||
Reference in New Issue
Block a user