Merge branch 'master' of https://github.com/prusa3d/Slic3r into et_canvas_gui_refactoring

This commit is contained in:
Enrico Turri 2019-03-29 12:58:41 +01:00
commit aca78cfba2
11 changed files with 187 additions and 80 deletions

View File

@ -80,9 +80,8 @@ public:
// Provokes static_assert in the right way. // Provokes static_assert in the right way.
template<class T = void> struct VeryFalse { static const bool value = false; }; template<class T = void> struct VeryFalse { static const bool value = false; };
// This has to be explicitly implemented in the gui layer or a default zlib // This can be explicitly implemented in the gui layer or the default Zipper
// based implementation is needed. I don't have time for that and I'm delegating // API in libslic3r with minz.
// the implementation to the gui layer where the gui toolkit can cover this.
template<class Fmt> class LayerWriter { template<class Fmt> class LayerWriter {
public: public:
@ -91,21 +90,28 @@ public:
"No layer writer implementation provided!"); "No layer writer implementation provided!");
} }
// Should create a new file within the zip with the given filename. It
// should also finish any previous entry.
void next_entry(const std::string& /*fname*/) {} void next_entry(const std::string& /*fname*/) {}
// binary entry // Should create a new file within the archive and write the provided data.
void binary_entry(const std::string& /*fname*/, void binary_entry(const std::string& /*fname*/,
const std::uint8_t* buf, size_t len); const std::uint8_t* buf, size_t len);
// Get the name of the archive but only the name part without the path or
// the extension.
std::string get_name() { return ""; } std::string get_name() { return ""; }
// Test whether the object can still be used for writing.
bool is_ok() { return false; } bool is_ok() { return false; }
// Write some data (text) into the current file (entry) within the archive.
template<class T> LayerWriter& operator<<(T&& /*arg*/) { template<class T> LayerWriter& operator<<(T&& /*arg*/) {
return *this; return *this;
} }
void close() {} // Flush the current entry into the archive.
void finalize() {}
}; };
// Implementation for PNG raster output // Implementation for PNG raster output
@ -267,7 +273,7 @@ public:
} }
} }
writer.close(); writer.finalize();
} catch(std::exception& e) { } catch(std::exception& e) {
BOOST_LOG_TRIVIAL(error) << e.what(); BOOST_LOG_TRIVIAL(error) << e.what();
// Rethrow the exception // Rethrow the exception

View File

@ -322,18 +322,18 @@ template<> class LayerWriter<SLAminzZipper> {
Zipper m_zip; Zipper m_zip;
public: public:
inline LayerWriter(const std::string& zipfile_path): m_zip(zipfile_path) {} LayerWriter(const std::string& zipfile_path): m_zip(zipfile_path) {}
inline void next_entry(const std::string& fname) { m_zip.add_entry(fname); } void next_entry(const std::string& fname) { m_zip.add_entry(fname); }
inline void binary_entry(const std::string& fname, void binary_entry(const std::string& fname,
const std::uint8_t* buf, const std::uint8_t* buf,
size_t l) size_t l)
{ {
m_zip.add_entry(fname, buf, l); m_zip.add_entry(fname, buf, l);
} }
inline std::string get_name() const { std::string get_name() const {
return m_zip.get_name(); return m_zip.get_name();
} }
@ -345,7 +345,11 @@ public:
return true; // m_zip blows up if something goes wrong... return true; // m_zip blows up if something goes wrong...
} }
inline void close() { m_zip.close(); } // After finalize, no writing to the archive will have an effect. The only
// valid operation is to dispose the object calling the destructor which
// should close the file. This method can throw and signal potential errors
// when flushing the archive. This is why its present.
void finalize() { m_zip.finalize(); }
}; };
/** /**

View File

@ -111,6 +111,11 @@ public:
{ {
throw std::runtime_error(formatted_errorstr()); throw std::runtime_error(formatted_errorstr());
} }
bool is_alive()
{
return arch.m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
}
}; };
Zipper::Zipper(const std::string &zipfname, e_compression compression) Zipper::Zipper(const std::string &zipfname, e_compression compression)
@ -129,11 +134,19 @@ Zipper::Zipper(const std::string &zipfname, e_compression compression)
Zipper::~Zipper() Zipper::~Zipper()
{ {
try { if(m_impl->is_alive()) {
close(); // Flush the current entry if not finished yet.
} catch(...) { try { finish_entry(); } catch(...) {
BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr(); BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr();
}
if(!mz_zip_writer_finalize_archive(&m_impl->arch))
BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr();
} }
// The file should be closed no matter what...
if(!mz_zip_writer_end(&m_impl->arch))
BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr();
} }
Zipper::Zipper(Zipper &&m): Zipper::Zipper(Zipper &&m):
@ -152,12 +165,16 @@ Zipper &Zipper::operator=(Zipper &&m) {
void Zipper::add_entry(const std::string &name) void Zipper::add_entry(const std::string &name)
{ {
if(!m_impl->is_alive()) return;
finish_entry(); // finish previous business finish_entry(); // finish previous business
m_entry = name; m_entry = name;
} }
void Zipper::add_entry(const std::string &name, const uint8_t *data, size_t l) void Zipper::add_entry(const std::string &name, const uint8_t *data, size_t l)
{ {
if(!m_impl->is_alive()) return;
finish_entry(); finish_entry();
mz_uint cmpr = MZ_NO_COMPRESSION; mz_uint cmpr = MZ_NO_COMPRESSION;
switch (m_compression) { switch (m_compression) {
@ -175,7 +192,9 @@ void Zipper::add_entry(const std::string &name, const uint8_t *data, size_t l)
void Zipper::finish_entry() void Zipper::finish_entry()
{ {
if(!m_data.empty() > 0 && !m_entry.empty()) { if(!m_impl->is_alive()) return;
if(!m_data.empty() && !m_entry.empty()) {
mz_uint compression = MZ_NO_COMPRESSION; mz_uint compression = MZ_NO_COMPRESSION;
switch (m_compression) { switch (m_compression) {
@ -198,12 +217,12 @@ std::string Zipper::get_name() const {
return boost::filesystem::path(m_impl->m_zipname).stem().string(); return boost::filesystem::path(m_impl->m_zipname).stem().string();
} }
void Zipper::close() void Zipper::finalize()
{ {
finish_entry(); finish_entry();
if(!mz_zip_writer_finalize_archive(&m_impl->arch)) m_impl->blow_up(); if(m_impl->is_alive()) if(!mz_zip_writer_finalize_archive(&m_impl->arch))
if(!mz_zip_writer_end(&m_impl->arch)) m_impl->blow_up(); m_impl->blow_up();
} }
} }

View File

@ -47,6 +47,7 @@ public:
void add_entry(const std::string& name); void add_entry(const std::string& name);
/// Add a new binary file entry with an instantly given byte buffer. /// Add a new binary file entry with an instantly given byte buffer.
/// This method throws exactly like finish_entry() does.
void add_entry(const std::string& name, const std::uint8_t* data, size_t l); void add_entry(const std::string& name, const std::uint8_t* data, size_t l);
// Writing data to the archive works like with standard streams. The target // Writing data to the archive works like with standard streams. The target
@ -74,12 +75,16 @@ public:
/// buffer and ones an entry is added, the buffer will bind to the new entry /// buffer and ones an entry is added, the buffer will bind to the new entry
/// If the buffer was written, but no entry was added, the buffer will be /// If the buffer was written, but no entry was added, the buffer will be
/// cleared after this call. /// cleared after this call.
///
/// This method will throw a runtime exception if an error occures. The
/// entry will still be open (with the data intact) but the state of the
/// file is up to minz after the erroneous write.
void finish_entry(); void finish_entry();
/// Gets the name of the archive without the path or extension. /// Gets the name of the archive without the path or extension.
std::string get_name() const; std::string get_name() const;
void close(); void finalize();
}; };

View File

@ -649,20 +649,16 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
} }
case ConfigMenuLanguage: case ConfigMenuLanguage:
{ {
/* Before change application language, let's check unsaved changes /* Before change application language, let's check unsaved changes on 3D-Scene
* and draw user's attention to the application restarting after a language change * and draw user's attention to the application restarting after a language change
*/ */
wxMessageDialog dialog(nullptr, wxMessageDialog dialog(nullptr,
_(L("Application will be restarted after language change, " _(L("Application will be restarted after language change.")) + "\n" +
"and 3D-Scene will be cleaned.")) + "\n" + _(L("3D-Scene will be cleaned.")) + "\n\n" +
_(L("Please, check your changes before.")) + "\n\n" + _(L("Please, check your changes before.")),
_(L("Continue anyway?")),
_(L("Attention!")), _(L("Attention!")),
wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT); wxICON_QUESTION | wxOK | wxCANCEL);
if ( dialog.ShowModal() != wxID_YES) if ( dialog.ShowModal() == wxID_CANCEL)
return;
if (!wxGetApp().check_unsaved_changes())
return; return;
wxArrayString names; wxArrayString names;

View File

@ -228,6 +228,21 @@ int ObjectList::get_selected_obj_idx() const
return -1; return -1;
} }
DynamicPrintConfig& ObjectList::get_item_config(const wxDataViewItem& item) const
{
assert(item);
const ItemType type = m_objects_model->GetItemType(item);
const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
const int vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1;
assert(obj_idx >= 0 || ((type & itVolume) && vol_idx >=0));
return type & itObject|itInstance ? (*m_objects)[obj_idx]->config :
(*m_objects)[obj_idx]->volumes[vol_idx]->config;
}
wxDataViewColumn* ObjectList::create_objects_list_extruder_column(int extruders_count) wxDataViewColumn* ObjectList::create_objects_list_extruder_column(int extruders_count)
{ {
wxArrayString choices; wxArrayString choices;
@ -910,8 +925,10 @@ wxMenuItem* ObjectList::append_menu_item_split(wxMenu* menu)
wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_) wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
{ {
PrusaMenu* menu = dynamic_cast<PrusaMenu*>(menu_); PrusaMenu* menu = dynamic_cast<PrusaMenu*>(menu_);
const wxString menu_name = _(L("Add settings"));
// Delete old items from settings popupmenu // Delete old items from settings popupmenu
auto settings_id = menu->FindItem(_("Add settings")); auto settings_id = menu->FindItem(menu_name);
if (settings_id != wxNOT_FOUND) if (settings_id != wxNOT_FOUND)
menu->Destroy(settings_id); menu->Destroy(settings_id);
@ -966,14 +983,10 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
menu->m_separator_scnd = menu->AppendSeparator(); menu->m_separator_scnd = menu->AppendSeparator();
// Add full settings list // Add full settings list
auto menu_item = new wxMenuItem(menu, wxID_ANY, _(L("Add settings"))); auto menu_item = new wxMenuItem(menu, wxID_ANY, menu_name);
menu_item->SetBitmap(m_bmp_cog); menu_item->SetBitmap(m_bmp_cog);
// const auto sel_vol = get_selected_model_volume(); menu_item->SetSubMenu(create_settings_popupmenu(menu));
// if (sel_vol && sel_vol->type() >= ModelVolumeType::SUPPORT_ENFORCER)
// menu_item->Enable(false);
// else
menu_item->SetSubMenu(create_settings_popupmenu(menu));
return menu->Append(menu_item); return menu->Append(menu_item);
} }
@ -1018,6 +1031,37 @@ void ObjectList::append_menu_item_export_stl(wxMenu* menu) const
menu->AppendSeparator(); menu->AppendSeparator();
} }
void ObjectList::append_menu_item_change_extruder(wxMenu* menu) const
{
const wxString name = _(L("Change extruder"));
// Delete old menu item
const int item_id = menu->FindItem(name);
if (item_id != wxNOT_FOUND)
menu->Destroy(item_id);
const int extruders_cnt = extruders_count();
const wxDataViewItem item = GetSelection();
if (item && extruders_cnt > 1)
{
DynamicPrintConfig& config = get_item_config(item);
const int initial_extruder = !config.has("extruder") ? 0 :
config.option<ConfigOptionInt>("extruder")->value;
wxMenu* extruder_selection_menu = new wxMenu();
for (int i = 0; i <= extruders_cnt; i++)
{
const wxString& item_name = i == 0 ? _(L("Default")) : wxString::Format("%d", i);
append_menu_radio_item(extruder_selection_menu, wxID_ANY, item_name, "",
[this, i](wxCommandEvent&) { set_extruder_for_selected_items(i); }, menu)->Check(i == initial_extruder);
}
menu->AppendSubMenu(extruder_selection_menu, name, _(L("Select new extruder for the object/part")));
}
}
void ObjectList::create_object_popupmenu(wxMenu *menu) void ObjectList::create_object_popupmenu(wxMenu *menu)
{ {
#ifdef __WXOSX__ #ifdef __WXOSX__
@ -1989,7 +2033,7 @@ void ObjectList::update_selections_on_canvas()
return; return;
} }
auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, bool as_single_selection) auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, int instance_idx, bool as_single_selection)
{ {
if (m_objects_model->GetParent(item) == wxDataViewItem(0)) { if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
selection.add_object(m_objects_model->GetIdByItem(item), as_single_selection); selection.add_object(m_objects_model->GetIdByItem(item), as_single_selection);
@ -1999,7 +2043,7 @@ void ObjectList::update_selections_on_canvas()
if (m_objects_model->GetItemType(item) == itVolume) { if (m_objects_model->GetItemType(item) == itVolume) {
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item)); const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item));
const int vol_idx = m_objects_model->GetVolumeIdByItem(item); const int vol_idx = m_objects_model->GetVolumeIdByItem(item);
selection.add_volume(obj_idx, vol_idx, 0, as_single_selection); selection.add_volume(obj_idx, vol_idx, std::max(instance_idx, 0), as_single_selection);
} }
else if (m_objects_model->GetItemType(item) == itInstance) { else if (m_objects_model->GetItemType(item) == itInstance) {
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
@ -2011,9 +2055,9 @@ void ObjectList::update_selections_on_canvas()
if (sel_cnt == 1) { if (sel_cnt == 1) {
wxDataViewItem item = GetSelection(); wxDataViewItem item = GetSelection();
if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot)) if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot))
add_to_selection(m_objects_model->GetParent(item), selection, true); add_to_selection(m_objects_model->GetParent(item), selection, -1, true);
else else
add_to_selection(item, selection, true); add_to_selection(item, selection, -1, true);
wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state();
return; return;
@ -2022,9 +2066,11 @@ void ObjectList::update_selections_on_canvas()
wxDataViewItemArray sels; wxDataViewItemArray sels;
GetSelections(sels); GetSelections(sels);
// stores current instance idx before to clear the selection
int instance_idx = selection.get_instance_idx();
selection.clear(); selection.clear();
for (auto item: sels) for (auto item: sels)
add_to_selection(item, selection, false); add_to_selection(item, selection, instance_idx, false);
wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state();
} }
@ -2425,15 +2471,7 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const
for (const wxDataViewItem& item : sels) for (const wxDataViewItem& item : sels)
{ {
const ItemType type = m_objects_model->GetItemType(item); DynamicPrintConfig& config = get_item_config(item);
const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
const int vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1;
DynamicPrintConfig& config = type & itObject ? (*m_objects)[obj_idx]->config :
(*m_objects)[obj_idx]->volumes[vol_idx]->config;
if (config.has("extruder")) { if (config.has("extruder")) {
if (extruder == 0) if (extruder == 0)
@ -2446,7 +2484,16 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const
const wxString extruder_str = extruder == 0 ? wxString ("default") : const wxString extruder_str = extruder == 0 ? wxString ("default") :
wxString::Format("%d", config.option<ConfigOptionInt>("extruder")->value); wxString::Format("%d", config.option<ConfigOptionInt>("extruder")->value);
m_objects_model->SetValue(extruder_str, item, 1);
auto const type = m_objects_model->GetItemType(item);
/* We can change extruder for Object/Volume only.
* So, if Instance is selected, get its Object item and change it
*/
m_objects_model->SetValue(extruder_str, type & itInstance ? m_objects_model->GetTopParent(item) : item, 1);
const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
wxGetApp().plater()->canvas3D()->ensure_on_bed(obj_idx); wxGetApp().plater()->canvas3D()->ensure_on_bed(obj_idx);
} }

View File

@ -187,6 +187,7 @@ public:
void append_menu_items_osx(wxMenu* menu); void append_menu_items_osx(wxMenu* menu);
void append_menu_item_fix_through_netfabb(wxMenu* menu); void append_menu_item_fix_through_netfabb(wxMenu* menu);
void append_menu_item_export_stl(wxMenu* menu) const ; void append_menu_item_export_stl(wxMenu* menu) const ;
void append_menu_item_change_extruder(wxMenu* menu) const;
void create_object_popupmenu(wxMenu *menu); void create_object_popupmenu(wxMenu *menu);
void create_sla_object_popupmenu(wxMenu*menu); void create_sla_object_popupmenu(wxMenu*menu);
void create_part_popupmenu(wxMenu*menu); void create_part_popupmenu(wxMenu*menu);
@ -213,12 +214,13 @@ public:
wxPoint get_mouse_position_in_control(); wxPoint get_mouse_position_in_control();
wxBoxSizer* get_sizer() {return m_sizer;} wxBoxSizer* get_sizer() {return m_sizer;}
int get_selected_obj_idx() const; int get_selected_obj_idx() const;
DynamicPrintConfig& get_item_config(const wxDataViewItem& item) const;
bool is_parts_changed() const { return m_parts_changed; } bool is_parts_changed() const { return m_parts_changed; }
bool is_part_settings_changed() const { return m_part_settings_changed; } bool is_part_settings_changed() const { return m_part_settings_changed; }
void part_settings_changed(); void part_settings_changed();
void parts_changed(int obj_idx); void parts_changed(int obj_idx);
void part_selection_changed(); void part_selection_changed();
// Add object to the list // Add object to the list
void add_object_to_list(size_t obj_idx); void add_object_to_list(size_t obj_idx);

View File

@ -28,7 +28,7 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he
{} {}
MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id) : MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id) :
wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxRESIZE_BORDER), wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
boldfont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)), boldfont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)),
content_sizer(new wxBoxSizer(wxVERTICAL)), content_sizer(new wxBoxSizer(wxVERTICAL)),
btn_sizer(new wxBoxSizer(wxHORIZONTAL)) btn_sizer(new wxBoxSizer(wxHORIZONTAL))

View File

@ -427,7 +427,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) :
option = m_og->get_option("fill_density"); option = m_og->get_option("fill_density");
option.opt.label = L("Infill"); option.opt.label = L("Infill");
option.opt.width = 5 * wxGetApp().em_unit(); option.opt.width = 6 * wxGetApp().em_unit();
option.opt.sidetext = " "; option.opt.sidetext = " ";
line.append_option(option); line.append_option(option);
@ -2624,29 +2624,35 @@ void Plater::priv::on_right_click(Vec2dEvent& evt)
sidebar->obj_list()->append_menu_item_settings(menu); sidebar->obj_list()->append_menu_item_settings(menu);
/* Remove/Prepend "increase/decrease instances" menu items according to the view mode. if (printer_technology != ptSLA)
* Suppress to show those items for a Simple mode sidebar->obj_list()->append_menu_item_change_extruder(menu);
*/
const MenuIdentifier id = printer_technology == ptSLA ? miObjectSLA : miObjectFFF; if (menu != &part_menu)
if (wxGetApp().get_mode() == comSimple) { {
if (menu->FindItem(_(L("Increase copies"))) != wxNOT_FOUND) /* Remove/Prepend "increase/decrease instances" menu items according to the view mode.
{ * Suppress to show those items for a Simple mode
/* Detach an items from the menu, but don't delete them */
* so that they can be added back later const MenuIdentifier id = printer_technology == ptSLA ? miObjectSLA : miObjectFFF;
* (after switching to the Advanced/Expert mode) if (wxGetApp().get_mode() == comSimple) {
*/ if (menu->FindItem(_(L("Increase copies"))) != wxNOT_FOUND)
menu->Remove(items_increase[id]); {
menu->Remove(items_decrease[id]); /* Detach an items from the menu, but don't delete them
menu->Remove(items_set_number_of_copies[id]); * so that they can be added back later
* (after switching to the Advanced/Expert mode)
*/
menu->Remove(items_increase[id]);
menu->Remove(items_decrease[id]);
menu->Remove(items_set_number_of_copies[id]);
}
} }
} else {
else { if (menu->FindItem(_(L("Increase copies"))) == wxNOT_FOUND)
if (menu->FindItem(_(L("Increase copies"))) == wxNOT_FOUND) {
{ // Prepend items to the menu, if those aren't not there
// Prepend items to the menu, if those aren't not there menu->Prepend(items_set_number_of_copies[id]);
menu->Prepend(items_set_number_of_copies[id]); menu->Prepend(items_decrease[id]);
menu->Prepend(items_decrease[id]); menu->Prepend(items_increase[id]);
menu->Prepend(items_increase[id]); }
} }
} }

View File

@ -61,6 +61,24 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin
return item; return item;
} }
wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler)
{
if (id == wxID_ANY)
id = wxNewId();
wxMenuItem* item = menu->AppendRadioItem(id, string, description);
#ifdef __WXMSW__
if (event_handler != nullptr && event_handler != menu)
event_handler->Bind(wxEVT_MENU, cb, id);
else
#endif // __WXMSW__
menu->Bind(wxEVT_MENU, cb, id);
return item;
}
const unsigned int wxCheckListBoxComboPopup::DefaultWidth = 200; const unsigned int wxCheckListBoxComboPopup::DefaultWidth = 200;
const unsigned int wxCheckListBoxComboPopup::DefaultHeight = 200; const unsigned int wxCheckListBoxComboPopup::DefaultHeight = 200;
const unsigned int wxCheckListBoxComboPopup::DefaultItemHeight = 18; const unsigned int wxCheckListBoxComboPopup::DefaultItemHeight = 18;

View File

@ -25,7 +25,11 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const
wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, const std::string& icon = "", wxEvtHandler* event_handler = nullptr); std::function<void(wxCommandEvent& event)> cb, const std::string& icon = "", wxEvtHandler* event_handler = nullptr);
wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxString& string, const wxString& description, const std::string& icon = ""); wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxString& string, const wxString& description,
const std::string& icon = "");
wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler);
wxBitmap create_scaled_bitmap(const std::string& bmp_name); wxBitmap create_scaled_bitmap(const std::string& bmp_name);