diff --git a/src/slic3r/GUI/Widgets/ComboBox.cpp b/src/slic3r/GUI/Widgets/ComboBox.cpp index 783e1caadf..b0d3746ad2 100644 --- a/src/slic3r/GUI/Widgets/ComboBox.cpp +++ b/src/slic3r/GUI/Widgets/ComboBox.cpp @@ -69,6 +69,11 @@ ComboBox::ComboBox(wxWindow *parent, e.SetId(GetId()); GetEventHandler()->ProcessEvent(e); }); + drop.Bind(EVT_DROPDOWN_ITEM_ACTION, [this](wxCommandEvent &e) { + e.SetEventObject(this); + e.SetId(GetId()); + GetEventHandler()->ProcessEvent(e); + }); drop.Bind(EVT_DISMISS, [this](auto &) { drop_down = false; wxCommandEvent e(wxEVT_COMBOBOX_CLOSEUP); @@ -222,7 +227,7 @@ int ComboBox::Append(const wxString &text, int style) { auto valid_bit_map = (&bitmap && bitmap.IsOk()) ? bitmap : wxNullBitmap; - Item item{text, wxEmptyString, valid_bit_map, valid_bit_map, clientData, group_key, group_label}; + Item item{text, wxEmptyString, valid_bit_map, valid_bit_map, wxNullBitmap, clientData, group_key, group_label}; item.style = style; items.push_back(item); SetClientDataType(wxClientData_Void); @@ -268,6 +273,27 @@ void ComboBox::ForceDropdownOpen() } } +void ComboBox::RefreshDropdownIfOpen() +{ + if (!drop_down) + return; + + drop.hover_item = -1; + drop.offset = wxPoint(); + if (drop.subDropDown) { + drop.subDropDown->group.clear(); + drop.subDropDown->hover_item = -1; + drop.subDropDown->offset = wxPoint(); + if (drop.subDropDown->IsShown()) + drop.subDropDown->Dismiss(); + } + + drop.need_sync = true; + drop.messureSize(); + drop.autoPosition(); + drop.paintNow(); +} + unsigned int ComboBox::GetCount() const { return items.size(); } void ComboBox::set_replace_text(wxString text, wxString image_name) @@ -321,6 +347,13 @@ void ComboBox::SetItemBitmap(unsigned int n, wxBitmap const &bitmap) drop.Invalidate(); } +void ComboBox::SetItemActionBitmap(unsigned int n, wxBitmap const &bitmap) +{ + if (n >= items.size()) return; + items[n].action_icon = (&bitmap && bitmap.IsOk()) ? bitmap : wxNullBitmap; + drop.Invalidate(); +} + int ComboBox::DoInsertItems(const wxArrayStringsAdapter &items, unsigned int pos, void ** clientData, @@ -328,7 +361,7 @@ int ComboBox::DoInsertItems(const wxArrayStringsAdapter &items, { if (pos > this->items.size()) return -1; for (int i = 0; i < items.GetCount(); ++i) { - Item item { items[i], wxEmptyString, wxNullBitmap, wxNullBitmap, clientData ? clientData[i] : NULL }; + Item item { items[i], wxEmptyString, wxNullBitmap, wxNullBitmap, wxNullBitmap, clientData ? clientData[i] : NULL }; this->items.insert(this->items.begin() + pos, item); ++pos; } diff --git a/src/slic3r/GUI/Widgets/ComboBox.hpp b/src/slic3r/GUI/Widgets/ComboBox.hpp index 552909b477..241458a7dd 100644 --- a/src/slic3r/GUI/Widgets/ComboBox.hpp +++ b/src/slic3r/GUI/Widgets/ComboBox.hpp @@ -80,10 +80,12 @@ public: wxBitmap GetItemBitmap(unsigned int n); void SetItemBitmap(unsigned int n, wxBitmap const &bitmap); + void SetItemActionBitmap(unsigned int n, wxBitmap const &bitmap); bool is_drop_down(){return drop_down;} void DeleteOneItem(unsigned int pos) { DoDeleteOneItem(pos); } void ForceDropdownOpen(); + void RefreshDropdownIfOpen(); protected: virtual int DoInsertItems(const wxArrayStringsAdapter &items, diff --git a/src/slic3r/GUI/Widgets/DropDown.cpp b/src/slic3r/GUI/Widgets/DropDown.cpp index 973113d0ac..7cb9aa6709 100644 --- a/src/slic3r/GUI/Widgets/DropDown.cpp +++ b/src/slic3r/GUI/Widgets/DropDown.cpp @@ -13,6 +13,7 @@ #include wxDEFINE_EVENT(EVT_DISMISS, wxCommandEvent); +wxDEFINE_EVENT(EVT_DROPDOWN_ITEM_ACTION, wxCommandEvent); BEGIN_EVENT_TABLE(DropDown, PopupWindow) @@ -225,6 +226,29 @@ static wxSize GetBmpSize(wxBitmap & bmp) #endif } +wxSize DropDown::actionIconSize() const +{ + wxSize size; + std::set groups; + for (const Item& item : items) { + if (group.IsEmpty()) { + if (!item.group_key.IsEmpty()) { + if (groups.find(item.group_key) != groups.end()) + continue; + groups.insert(item.group_key); + } + } else if (item.group_key != group) { + continue; + } + + wxBitmap icon = item.action_icon; + wxSize icon_size = GetBmpSize(icon); + size.x = std::max(size.x, icon_size.x); + size.y = std::max(size.y, icon_size.y); + } + return size; +} + static void _DrawSplitItem(const wxWindow* w, wxDC& dc, wxString split_text, wxPoint start_pt, int item_width, int item_height) { // save dc @@ -354,6 +378,9 @@ void DropDown::render(wxDC &dc) rcContent.width -= szBmp.x + 5; } + const wxSize action_icon_size = actionIconSize(); + const int action_column_width = action_icon_size.x > 0 ? action_icon_size.x + FromDIP(16) : 0; + std::set groups; // draw texts & icons int index = 0; @@ -392,6 +419,7 @@ void DropDown::render(wxDC &dc) } if (rcContent.y > size.y) break; wxPoint pt = rcContent.GetLeftTop(); + int rcContent_width = rcContent.width; if (item.style & DD_ITEM_STYLE_SPLIT_ITEM) { _DrawSplitItem(this, dc, item.text, pt, rowSize.GetWidth(), rowSize.GetHeight()); @@ -417,13 +445,27 @@ void DropDown::render(wxDC &dc) auto text = group.IsEmpty() ? (item.group_key.IsEmpty() ? item.text : item.group_label) : item.text; + if (action_column_width > 0) + rcContent.width -= action_column_width; + + if (item.action_icon.IsOk()) { + auto action_size = GetBmpSize(item.action_icon); + wxPoint action_pt(rcContent.x + rcContent_width - action_size.x - FromDIP(8), + rcContent.y + (rcContent.height - action_size.y) / 2); + dc.DrawBitmap(item.action_icon, action_pt); + } + if (!text_off && !text.IsEmpty()) { wxSize tSize = dc.GetMultiLineTextExtent(text); if (pt.x + tSize.x > rcContent.GetRight()) { - if (is_hover && item.tip.IsEmpty()) - SetToolTip(text); - text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END, - rcContent.GetRight() - pt.x); + int max_text_width = rcContent.GetRight() - pt.x; + if (max_text_width <= 0) { + text.clear(); + } else { + if (is_hover && item.tip.IsEmpty()) + SetToolTip(text); + text = wxControl::Ellipsize(text, dc, wxELLIPSIZE_END, max_text_width); + } } pt.y += (rcContent.height - textSize.y) / 2; dc.SetFont(GetFont()); @@ -436,6 +478,7 @@ void DropDown::render(wxDC &dc) dc.DrawBitmap(arrow_bitmap.bmp(), pt); } } + rcContent.width = rcContent_width; rcContent.y += rowSize.y; } } @@ -545,6 +588,8 @@ void DropDown::messureSize() size1.x += size2.x + (text_off ? 0 : 5); } } + if (item.action_icon.IsOk()) + size1.x += GetBmpSize(item.action_icon).x + FromDIP(16); if (size1.x > textSize.x) textSize = size1; } if (!align_icon) iconSize.x = 0; @@ -616,6 +661,11 @@ void DropDown::messureSize() e.SetId(GetId()); GetEventHandler()->ProcessEvent(e); }); + subDropDown->Bind(EVT_DROPDOWN_ITEM_ACTION, [this](wxCommandEvent &e) { + e.SetEventObject(this); + e.SetId(GetId()); + GetEventHandler()->ProcessEvent(e); + }); } need_sync = false; } @@ -694,6 +744,19 @@ void DropDown::mouseReleased(wxMouseEvent& event) if (hover_item < 0) return; if (hover_item >= 0 && (subDropDown == nullptr || subDropDown->group.empty())) { // not moved + int index = hoverIndex(); + if (index >= 0 && items[index].action_icon.IsOk()) { + wxSize action_size = actionIconSize(); + int action_right = GetSize().x; + if (rowSize.y * count > GetSize().y) + action_right -= 6; + int action_left = action_right - action_size.x - FromDIP(16); + if (event.GetX() >= action_left && event.GetX() <= action_right) { + sendDropDownActionEvent(index); + paintNow(); + return; + } + } sendDropDownEvent(); if (mainDropDown) mainDropDown->hover_item = -1; // To Dismiss mainDropDown @@ -810,6 +873,17 @@ void DropDown::sendDropDownEvent() GetEventHandler()->ProcessEvent(event); } +void DropDown::sendDropDownActionEvent(int index) +{ + if (index < 0 || index >= int(items.size()) || (items[index].style & DD_ITEM_STYLE_DISABLED)) + return; + wxCommandEvent event(EVT_DROPDOWN_ITEM_ACTION, GetId()); + event.SetEventObject(this); + event.SetInt(index); + event.SetString(items[index].text); + GetEventHandler()->ProcessEvent(event); +} + void DropDown::Dismiss() { if (subDropDown && subDropDown->IsShown()) diff --git a/src/slic3r/GUI/Widgets/DropDown.hpp b/src/slic3r/GUI/Widgets/DropDown.hpp index 09041e3dc0..a2ad873b94 100644 --- a/src/slic3r/GUI/Widgets/DropDown.hpp +++ b/src/slic3r/GUI/Widgets/DropDown.hpp @@ -15,6 +15,7 @@ #define DD_ITEM_STYLE_DISABLED 0x0002 // ----text----, text with horizontal line arounds wxDECLARE_EVENT(EVT_DISMISS, wxCommandEvent); +wxDECLARE_EVENT(EVT_DROPDOWN_ITEM_ACTION, wxCommandEvent); class DropDown : public PopupWindow { @@ -25,6 +26,7 @@ public: wxString text_static_tips;// display static tips for TextInput.eg.PrinterInfoBox wxBitmap icon; wxBitmap icon_textctrl;// display icon for TextInput.eg.PrinterInfoBox + wxBitmap action_icon; void * data{nullptr}; wxString group_key{}; wxString group_label{}; @@ -123,6 +125,7 @@ private: int hoverIndex(); int selectedItem(); + wxSize actionIconSize() const; friend class ComboBox; void messureSize(); @@ -136,6 +139,7 @@ private: void mouseWheelMoved(wxMouseEvent &event); void sendDropDownEvent(); + void sendDropDownActionEvent(int index); DECLARE_EVENT_TABLE()