mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-11 19:17:33 +00:00
Add a OrcaSlicer badge in the thumbnail preview for published 3MF projects. Add a visual indicator in the publish dialog to show that something in the section is toggled
This commit is contained in:
@@ -553,6 +553,7 @@ body
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
width: 184px;
|
width: 184px;
|
||||||
height: 184px;
|
height: 184px;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.FileItem img
|
.FileItem img
|
||||||
@@ -564,6 +565,19 @@ body
|
|||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.FileImg .FileLogoBadge
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
left: 8px;
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
padding: 2px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: rgba(255,255,255,0.85);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
.FileName
|
.FileName
|
||||||
{
|
{
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|||||||
@@ -226,10 +226,11 @@ function ShowRecentFileList( pList )
|
|||||||
//let sShortName=sPath.substring(index+1,sPath.length);
|
//let sShortName=sPath.substring(index+1,sPath.length);
|
||||||
|
|
||||||
let sBadge=sPublished? '<span class="FilePublishedBadge">PUB</span>':'';
|
let sBadge=sPublished? '<span class="FilePublishedBadge">PUB</span>':'';
|
||||||
|
let sLogoBadge=sPublished? '<img class="FileLogoBadge" src="../../images/OrcaSlicer_gradient_circle.svg" alt="" />':'';
|
||||||
|
|
||||||
let TmpHtml='<div class="FileItem" fpath="'+sPath+'" >'+
|
let TmpHtml='<div class="FileItem" fpath="'+sPath+'" >'+
|
||||||
'<a class="FileTip" title="'+sPath+'"></a>'+
|
'<a class="FileTip" title="'+sPath+'"></a>'+
|
||||||
'<div class="FileImg" ><img src="'+sImg+'" onerror="this.onerror=null;this.src=\'img/d.png\';" alt="No Image" /></div>'+
|
'<div class="FileImg" ><img src="'+sImg+'" onerror="this.onerror=null;this.src=\'img/d.png\';" alt="No Image" />'+sLogoBadge+'</div>'+
|
||||||
'<div class="FileNamePack">'+sBadge+'<div class="FileName TextS1">'+sName+'</div></div>'+
|
'<div class="FileNamePack">'+sBadge+'<div class="FileName TextS1">'+sName+'</div></div>'+
|
||||||
'<div class="FileDate">'+sTime+'</div>'+
|
'<div class="FileDate">'+sTime+'</div>'+
|
||||||
'</div>';
|
'</div>';
|
||||||
|
|||||||
@@ -881,6 +881,7 @@ void PublishSettingsDialog::build_option_model()
|
|||||||
m_outer_tabs->SelectItem(0);
|
m_outer_tabs->SelectItem(0);
|
||||||
show_outer_page(0);
|
show_outer_page(0);
|
||||||
}
|
}
|
||||||
|
refresh_tab_indicators();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t PublishSettingsDialog::section_group_for(Section kind)
|
size_t PublishSettingsDialog::section_group_for(Section kind)
|
||||||
@@ -1127,6 +1128,7 @@ void PublishSettingsDialog::add_row_ui(const std::string& key,
|
|||||||
Row& current = m_rows[row_index];
|
Row& current = m_rows[row_index];
|
||||||
current.check = new wxCheckBox(category.scroll, wxID_ANY, label);
|
current.check = new wxCheckBox(category.scroll, wxID_ANY, label);
|
||||||
current.check->SetFont(Label::Body_13);
|
current.check->SetFont(Label::Body_13);
|
||||||
|
current.check->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) { refresh_tab_indicators(); });
|
||||||
auto* row_sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto* row_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
row_sizer->Add(current.check, 0, wxALIGN_CENTER_VERTICAL);
|
row_sizer->Add(current.check, 0, wxALIGN_CENTER_VERTICAL);
|
||||||
// The value is read-only text (incl. the Type row: the published type is the slot's
|
// The value is read-only text (incl. the Type row: the published type is the slot's
|
||||||
@@ -1161,6 +1163,7 @@ void PublishSettingsDialog::on_full_toggle(size_t category_index)
|
|||||||
const bool full = cat.full_check->GetValue();
|
const bool full = cat.full_check->GetValue();
|
||||||
for (size_t r : cat.rows)
|
for (size_t r : cat.rows)
|
||||||
m_rows[r].check->Enable(!full);
|
m_rows[r].check->Enable(!full);
|
||||||
|
refresh_tab_indicators();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PublishSettingsDialog::on_enable_toggle(size_t category_index)
|
void PublishSettingsDialog::on_enable_toggle(size_t category_index)
|
||||||
@@ -1195,6 +1198,7 @@ void PublishSettingsDialog::on_enable_toggle(size_t category_index)
|
|||||||
apply_visibility();
|
apply_visibility();
|
||||||
if (cat.page != nullptr)
|
if (cat.page != nullptr)
|
||||||
cat.page->GetSizer()->Layout();
|
cat.page->GetSizer()->Layout();
|
||||||
|
refresh_tab_indicators();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PublishSettingsDialog::add_mixed_visual(size_t category_index, const MixedVisualSpec& spec)
|
void PublishSettingsDialog::add_mixed_visual(size_t category_index, const MixedVisualSpec& spec)
|
||||||
@@ -1606,6 +1610,7 @@ void PublishSettingsDialog::select_all(bool value)
|
|||||||
if (m_categories[c].section == Section::Material)
|
if (m_categories[c].section == Section::Material)
|
||||||
on_enable_toggle(c);
|
on_enable_toggle(c);
|
||||||
apply_visibility();
|
apply_visibility();
|
||||||
|
refresh_tab_indicators();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PublishSettingsDialog::row_is_visible(const Row& row) const
|
bool PublishSettingsDialog::row_is_visible(const Row& row) const
|
||||||
@@ -1637,6 +1642,7 @@ void PublishSettingsDialog::select_visible(bool value)
|
|||||||
m_filter_ctrl->ChangeValue("");
|
m_filter_ctrl->ChangeValue("");
|
||||||
apply_filter(""); // resync visibility and the All/None bar
|
apply_filter(""); // resync visibility and the All/None bar
|
||||||
}
|
}
|
||||||
|
refresh_tab_indicators();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PublishSettingsDialog::show_menu(wxMouseEvent& evt)
|
void PublishSettingsDialog::show_menu(wxMouseEvent& evt)
|
||||||
@@ -1778,6 +1784,7 @@ void PublishSettingsDialog::apply_selection(const std::vector<std::string>& publ
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply_visibility();
|
apply_visibility();
|
||||||
|
refresh_tab_indicators();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> PublishSettingsDialog::GetPublishedKeys() const
|
std::vector<std::string> PublishSettingsDialog::GetPublishedKeys() const
|
||||||
@@ -1932,6 +1939,38 @@ std::vector<Slic3r::PublishedMaterialEntry> PublishSettingsDialog::GetPublishedM
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PublishSettingsDialog::category_has_selection(const Category& cat) const
|
||||||
|
{
|
||||||
|
// A material slot publishes (or not) as a whole, gated by "Enable".
|
||||||
|
if (cat.section == Section::Material)
|
||||||
|
return cat.enable_check != nullptr && cat.enable_check->GetValue();
|
||||||
|
// Print/Printer categories have no gate: any checked row counts.
|
||||||
|
for (const size_t r : cat.rows)
|
||||||
|
if (m_rows[r].check->GetValue())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PublishSettingsDialog::refresh_tab_indicators()
|
||||||
|
{
|
||||||
|
for (size_t s = 0; s < m_sections.size(); ++s) {
|
||||||
|
SectionGroup& section = m_sections[s];
|
||||||
|
bool any = false;
|
||||||
|
for (size_t i = 0; i < section.categories.size(); ++i) {
|
||||||
|
const bool on = category_has_selection(m_categories[section.categories[i]]);
|
||||||
|
section.tabs->SetItemIndicator(static_cast<unsigned int>(i), on);
|
||||||
|
any = any || on;
|
||||||
|
}
|
||||||
|
if (section.mixed_tabs != nullptr)
|
||||||
|
for (size_t i = 0; i < section.mixed_categories.size(); ++i) {
|
||||||
|
const bool on = category_has_selection(m_categories[section.mixed_categories[i]]);
|
||||||
|
section.mixed_tabs->SetItemIndicator(static_cast<unsigned int>(i), on);
|
||||||
|
any = any || on;
|
||||||
|
}
|
||||||
|
m_outer_tabs->SetItemIndicator(static_cast<unsigned int>(s), any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> PublishSettingsDialog::full_keys_for_slot() const
|
std::vector<std::string> PublishSettingsDialog::full_keys_for_slot() const
|
||||||
{
|
{
|
||||||
// The canonical filament preset keys minus the structural keys the published overlay must
|
// The canonical filament preset keys minus the structural keys the published overlay must
|
||||||
|
|||||||
@@ -213,6 +213,11 @@ private:
|
|||||||
// "Enable" toggled on a material slot: reveals/hides everything below the header and, for a
|
// "Enable" toggled on a material slot: reveals/hides everything below the header and, for a
|
||||||
// mixed slot, auto-selects its component filaments' "Enable" + "Full Publish" toggles.
|
// mixed slot, auto-selects its component filaments' "Enable" + "Full Publish" toggles.
|
||||||
void on_enable_toggle(size_t category_index);
|
void on_enable_toggle(size_t category_index);
|
||||||
|
// Whether a category currently publishes something, driving its tab's indicator dot.
|
||||||
|
// Print/Printer: any row checked. Material: the slot's "Enable" is on.
|
||||||
|
bool category_has_selection(const Category& cat) const;
|
||||||
|
// Recompute the indicator dot on every outer/inner tab from the current selection state.
|
||||||
|
void refresh_tab_indicators();
|
||||||
// Unmet dependencies of enabled mixed-filament slots, one record per (mix, component) pair:
|
// Unmet dependencies of enabled mixed-filament slots, one record per (mix, component) pair:
|
||||||
// "Enable" not checked on the component, or enabled with neither "Full Publish" nor the
|
// "Enable" not checked on the component, or enabled with neither "Full Publish" nor the
|
||||||
// "Type" requirement row checked. Colour is deliberately ignored (the receiver renders the
|
// "Type" requirement row checked. Colour is deliberately ignored (the receiver renders the
|
||||||
|
|||||||
@@ -162,6 +162,15 @@ void Button::SetCenter(bool isCenter)
|
|||||||
{
|
{
|
||||||
this->isCenter = isCenter; }
|
this->isCenter = isCenter; }
|
||||||
|
|
||||||
|
void Button::SetIndicator(bool on)
|
||||||
|
{
|
||||||
|
if (m_show_indicator == on)
|
||||||
|
return;
|
||||||
|
m_show_indicator = on;
|
||||||
|
messureSize();
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
void Button::SetVertical(bool vertical)
|
void Button::SetVertical(bool vertical)
|
||||||
{
|
{
|
||||||
this->vertical = vertical;
|
this->vertical = vertical;
|
||||||
@@ -324,6 +333,13 @@ void Button::render(wxDC& dc)
|
|||||||
szContent.x -= d;
|
szContent.x -= d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (m_show_indicator) {
|
||||||
|
const int dot = FromDIP(6);
|
||||||
|
if (vertical)
|
||||||
|
szContent.y += dot + FromDIP(6);
|
||||||
|
else
|
||||||
|
szContent.x += dot + FromDIP(6);
|
||||||
|
}
|
||||||
// move to center
|
// move to center
|
||||||
wxRect rcContent = { {0, 0}, size };
|
wxRect rcContent = { {0, 0}, size };
|
||||||
if (isCenter) {
|
if (isCenter) {
|
||||||
@@ -364,6 +380,17 @@ void Button::render(wxDC& dc)
|
|||||||
#endif
|
#endif
|
||||||
dc.DrawText(text, pt);
|
dc.DrawText(text, pt);
|
||||||
}
|
}
|
||||||
|
if (m_show_indicator) {
|
||||||
|
const int dot = FromDIP(6); // diameter
|
||||||
|
wxPoint dot_pt;
|
||||||
|
dot_pt.x = pt.x + (text.IsEmpty() ? 0 : textSize.x) + FromDIP(6) + dot / 2;
|
||||||
|
// Centre on the content vertically; a bitmap-only (empty-label) tab has no text row.
|
||||||
|
dot_pt.y = text.IsEmpty() ? rcContent.y + rcContent.height / 2 : pt.y + textSize.y / 2;
|
||||||
|
const wxColour c = StateColor::darkModeColorFor(m_indicator_color);
|
||||||
|
dc.SetBrush(wxBrush(c));
|
||||||
|
dc.SetPen(wxPen(c));
|
||||||
|
dc.DrawCircle(dot_pt, dot / 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Button::messureSize()
|
void Button::messureSize()
|
||||||
@@ -388,6 +415,14 @@ void Button::messureSize()
|
|||||||
if (szIcon.y > szContent.y) szContent.y = szIcon.y;
|
if (szIcon.y > szContent.y) szContent.y = szIcon.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (m_show_indicator) {
|
||||||
|
// Indicator dot sits to the right of the label: its diameter plus the gap from the text.
|
||||||
|
const int dot = FromDIP(6);
|
||||||
|
if (vertical)
|
||||||
|
szContent.y += dot + FromDIP(6);
|
||||||
|
else
|
||||||
|
szContent.x += dot + FromDIP(6);
|
||||||
|
}
|
||||||
wxSize size = szContent + paddingSize * 2;
|
wxSize size = szContent + paddingSize * 2;
|
||||||
if (minSize.GetHeight() > 0)
|
if (minSize.GetHeight() > 0)
|
||||||
size.SetHeight(minSize.GetHeight());
|
size.SetHeight(minSize.GetHeight());
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "../wxExtensions.hpp"
|
#include "../wxExtensions.hpp"
|
||||||
#include "StaticBox.hpp"
|
#include "StaticBox.hpp"
|
||||||
#include <wx/tipwin.h>
|
#include <wx/tipwin.h>
|
||||||
|
#include <wx/colour.h>
|
||||||
|
|
||||||
class ButtonProps
|
class ButtonProps
|
||||||
{
|
{
|
||||||
@@ -44,6 +45,8 @@ class Button : public StaticBox
|
|||||||
bool canFocus = true;
|
bool canFocus = true;
|
||||||
bool isCenter = true;
|
bool isCenter = true;
|
||||||
bool vertical = false;
|
bool vertical = false;
|
||||||
|
bool m_show_indicator = false;
|
||||||
|
wxColour m_indicator_color = wxColour("#009688");
|
||||||
|
|
||||||
static const int buttonWidth = 200;
|
static const int buttonWidth = 200;
|
||||||
static const int buttonHeight = 50;
|
static const int buttonHeight = 50;
|
||||||
@@ -75,6 +78,10 @@ public:
|
|||||||
|
|
||||||
void SetSelected(bool selected = true) { m_selected = selected; }
|
void SetSelected(bool selected = true) { m_selected = selected; }
|
||||||
|
|
||||||
|
// Show a small coloured dot to the right of the label (used by TabCtrl tabs to flag that
|
||||||
|
// the tab's category has a selected/toggled setting).
|
||||||
|
void SetIndicator(bool on);
|
||||||
|
|
||||||
// Only meant to be used by inspector, not public API
|
// Only meant to be used by inspector, not public API
|
||||||
ButtonStyle GetStyle() const { return m_style; }
|
ButtonStyle GetStyle() const { return m_style; }
|
||||||
ButtonType GetType() const { return m_type; }
|
ButtonType GetType() const { return m_type; }
|
||||||
|
|||||||
@@ -171,6 +171,14 @@ void TabCtrl::SetItemBitmap(unsigned int item, const wxBitmap& bitmap)
|
|||||||
relayout();
|
relayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TabCtrl::SetItemIndicator(unsigned int item, bool on)
|
||||||
|
{
|
||||||
|
if (item >= btns.size())
|
||||||
|
return;
|
||||||
|
btns[item]->SetIndicator(on);
|
||||||
|
relayout();
|
||||||
|
}
|
||||||
|
|
||||||
bool TabCtrl::GetItemBold(unsigned int item) const
|
bool TabCtrl::GetItemBold(unsigned int item) const
|
||||||
{
|
{
|
||||||
if (item >= btns.size())
|
if (item >= btns.size())
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ public:
|
|||||||
void SetItemText(unsigned int item, wxString const& value);
|
void SetItemText(unsigned int item, wxString const& value);
|
||||||
void SetItemBitmap(unsigned int item, const wxBitmap& bitmap);
|
void SetItemBitmap(unsigned int item, const wxBitmap& bitmap);
|
||||||
|
|
||||||
|
// Show/hide the small "has selection" dot next to a tab's text.
|
||||||
|
void SetItemIndicator(unsigned int item, bool on);
|
||||||
|
|
||||||
bool GetItemBold(unsigned int item) const;
|
bool GetItemBold(unsigned int item) const;
|
||||||
void SetItemBold(unsigned int item, bool bold);
|
void SetItemBold(unsigned int item, bool bold);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user