Compare commits

..
Author SHA1 Message Date
Hanif Koh 203f02361e Show "No Available Printers" Instead of an Empty Printer Dropdown
A ComboBox with no items opened a one-row-high popup that DropDown never
paints, leaving a blank strip with stale pixels under the box. Don't open
the list when it is empty, and label the printer box in the print and
send-to-printer dialogs when no printer is available.
2026-10-18 15:01:47 +08:00
6 changed files with 11 additions and 42 deletions

No files matched your search

+2 -5
View File
@@ -350,11 +350,8 @@ identity default and translates nothing. `NetworkAgent` forwards both to the liv
comparison sites below reach them through `wxGetApp().getAgent()` and leave an id untranslated
while no agent is live. Whole documents are Bambu's business alone:
`BBLPrinterAgent::to_orca_payload` and `from_orca_payload` rewrite every string under
`tray_info_idx`, `filament_id`, `filamentId`, `cate` or `fila_id` at any depth; text that does not
parse, or carries none of those keys, comes back unchanged. The last two are the H2C nozzle rack's:
`cate` in the auto nozzle mapping request, `fila_id` in the rack status. A new Bambu message that
carries a filament id under another key needs that key added to `filament_id_keys`, or the id
crosses the boundary untranslated. The map is loaded once, lazily; a missing or malformed
`tray_info_idx`, `filament_id` or `filamentId` at any depth; text that does not parse, or carries
none of those keys, comes back unchanged. The map is loaded once, lazily; a missing or malformed
file degrades to identity with a log line rather than failing.
| Boundary | Where it translates |
+1 -1
View File
@@ -4087,7 +4087,7 @@ void SelectMachineDialog::update_user_printer()
{
m_printer_last_select = "";
update_select_layout(nullptr);
m_printer_box->GetPrinterComboBox()->SetTextLabel("");
m_printer_box->GetPrinterComboBox()->SetValue(_L("No available printers"));
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "for send task, current printer id = " << m_printer_last_select << std::endl;
+1 -1
View File
@@ -1229,7 +1229,7 @@ void SendToPrinterDialog::update_user_printer()
}
else {
m_printer_last_select = "";
m_comboBox_printer->SetTextLabel("");
m_comboBox_printer->SetValue(_L("No available printers"));
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "for send task, current printer id = " << m_printer_last_select << std::endl;
+3 -3
View File
@@ -287,7 +287,7 @@ void ComboBox::DoDeleteOneItem(unsigned int pos)
void ComboBox::ForceDropdownOpen()
{
if (!IsEnabled())
if (!IsEnabled() || items.empty())
return;
if (!drop_down) {
@@ -398,7 +398,7 @@ void ComboBox::mouseDown(wxMouseEvent &event)
SetFocus();
if (drop_down) {
drop.Hide();
} else if (drop.HasDismissLongTime()) {
} else if (!items.empty() && drop.HasDismissLongTime()) { // DropDown paints nothing for an empty list
drop.autoPosition();
drop_down = true;
drop.Popup(&drop);
@@ -426,7 +426,7 @@ void ComboBox::keyDown(wxKeyEvent& event)
case WXK_SPACE:
if (drop_down) {
drop.DismissAndNotify();
} else if (drop.HasDismissLongTime()) {
} else if (!items.empty() && drop.HasDismissLongTime()) {
drop.autoPosition();
drop_down = true;
drop.Popup();
+4 -11
View File
@@ -7,8 +7,6 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/DeviceCore/DevManager.h"
#include <algorithm>
#include <array>
#include <boost/format.hpp>
#include <boost/log/trivial.hpp>
#include <boost/nowide/fstream.hpp>
@@ -18,7 +16,6 @@
#include <cmath>
#include <slic3r/GUI/DeviceManager.hpp>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
using json = nlohmann::json;
@@ -67,16 +64,12 @@ const BambuFilamentIdMap& bambu_filament_id_map()
return map;
}
// Keys whose string value is a filament id. "cate" and "fila_id" are the H2C nozzle rack's: the
// auto nozzle mapping request and the rack status in the push message.
constexpr std::array<std::string_view, 5> filament_id_keys{"tray_info_idx", "filament_id", "filamentId", "cate", "fila_id"};
// Rewrites every string under a filament id key, at any depth, in place.
// Rewrites every string under "tray_info_idx", "filament_id" or "filamentId", at any depth, in place.
void rewrite_filament_ids(json& j, const std::unordered_map<std::string, std::string>& map)
{
if (j.is_object()) {
for (auto& [key, value] : j.items()) {
if (value.is_string() && std::find(filament_id_keys.begin(), filament_id_keys.end(), key) != filament_id_keys.end()) {
if (value.is_string() && (key == "tray_info_idx" || key == "filament_id" || key == "filamentId")) {
auto it = map.find(value.get_ref<const std::string&>());
if (it != map.end())
value = it->second;
@@ -91,8 +84,8 @@ void rewrite_filament_ids(json& j, const std::unordered_map<std::string, std::st
// Text that does not parse as JSON, or that mentions none of the id keys, comes back byte-identical.
std::string rewrite_filament_ids(std::string text, const std::unordered_map<std::string, std::string>& map)
{
if (map.empty() || std::none_of(filament_id_keys.begin(), filament_id_keys.end(),
[&text](std::string_view key) { return text.find(key) != std::string::npos; }))
if (map.empty() || (text.find("tray_info_idx") == std::string::npos && text.find("filament_id") == std::string::npos &&
text.find("filamentId") == std::string::npos))
return text; // nothing to map, skip the parse (moved, not copied)
try {
json j = json::parse(text);
@@ -81,24 +81,3 @@ TEST_CASE("Payload rewrite covers nested trays, calibration lists and mapping in
CHECK(BBLPrinterAgent::from_orca_payload("not json") == "not json");
CHECK(BBLPrinterAgent::from_orca_payload(R"({"print":{"command":"pushall"}})") == R"({"print":{"command":"pushall"}})");
}
TEST_CASE("Payload rewrite covers the nozzle rack status and the auto nozzle mapping request", "[BambuFilamentIds]")
{
const ScopedRepoResourcesDir repo_resources;
const std::string petg_hf = orca_id_of("GFG96");
const std::string rack_status =
R"({"print":{"device":{"nozzle":{"info":[{"id":16,"fila_id":"GFG96","color_m":"FFFFFFFF"},{"id":17,"fila_id":"P22f54c9"}]}}}})";
json inbound = json::parse(BBLPrinterAgent::to_orca_payload(rack_status));
CHECK(inbound["print"]["device"]["nozzle"]["info"][0]["fila_id"] == petg_hf);
CHECK(inbound["print"]["device"]["nozzle"]["info"][1]["fila_id"] == "P22f54c9"); // user id: untouched
const std::string request = R"({"print":{"command":"get_auto_nozzle_mapping","ams_mapping":[65535,65024],)"
R"("fila_info":[{"id":2,"cate":")" + petg_hf + R"(","color":"FFFFFFFF"}],)"
R"("nozzle_info":[{"pos":16,"cate":")" + petg_hf + R"(","color":"FFFFFFFF"},{"pos":1,"cate":""}]}})";
json outbound = json::parse(BBLPrinterAgent::from_orca_payload(request));
CHECK(outbound["print"]["fila_info"][0]["cate"] == "GFG96");
CHECK(outbound["print"]["nozzle_info"][0]["cate"] == "GFG96");
CHECK(outbound["print"]["nozzle_info"][1]["cate"] == ""); // empty nozzle
CHECK(outbound["print"]["ams_mapping"] == json::parse("[65535,65024]"));
}