X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/66ddc77b88bb674c8112d5016731e60d9dd6f4a0..bb996f289574defb0ae4339ae8e46ff3cf6fa54c:/src/ribbon/panel.cpp diff --git a/src/ribbon/panel.cpp b/src/ribbon/panel.cpp index 512ec8ae32..341661f41f 100644 --- a/src/ribbon/panel.cpp +++ b/src/ribbon/panel.cpp @@ -22,6 +22,7 @@ #include "wx/ribbon/bar.h" #include "wx/dcbuffer.h" #include "wx/display.h" +#include "wx/sizer.h" #ifndef WX_PRECOMP #include "wx/frame.h" @@ -31,6 +32,10 @@ #include "wx/msw/private.h" #endif +wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONPANEL_EXTBUTTON_ACTIVATED, wxRibbonPanelEvent); + +IMPLEMENT_DYNAMIC_CLASS(wxRibbonPanelEvent, wxCommandEvent) + IMPLEMENT_CLASS(wxRibbonPanel, wxRibbonControl) BEGIN_EVENT_TABLE(wxRibbonPanel, wxRibbonControl) @@ -38,6 +43,7 @@ BEGIN_EVENT_TABLE(wxRibbonPanel, wxRibbonControl) EVT_ERASE_BACKGROUND(wxRibbonPanel::OnEraseBackground) EVT_KILL_FOCUS(wxRibbonPanel::OnKillFocus) EVT_LEAVE_WINDOW(wxRibbonPanel::OnMouseLeave) + EVT_MOTION(wxRibbonPanel::OnMotion) EVT_LEFT_DOWN(wxRibbonPanel::OnMouseClick) EVT_PAINT(wxRibbonPanel::OnPaint) EVT_SIZE(wxRibbonPanel::OnSize) @@ -110,7 +116,7 @@ void wxRibbonPanel::CommonInit(const wxString& label, const wxBitmap& icon, long SetLabel(label); m_minimised_size = wxDefaultSize; // Unknown / none - m_smallest_unminimised_size = wxSize(INT_MAX, INT_MAX); // Unknown / none + m_smallest_unminimised_size = wxDefaultSize;// Unknown / none for IsFullySpecified() m_preferred_expand_direction = wxSOUTH; m_expanded_dummy = NULL; m_expanded_panel = NULL; @@ -118,6 +124,7 @@ void wxRibbonPanel::CommonInit(const wxString& label, const wxBitmap& icon, long m_minimised_icon = icon; m_minimised = false; m_hovered = false; + m_ext_button_hovered = false; if(m_art == NULL) { @@ -143,6 +150,11 @@ bool wxRibbonPanel::IsHovered() const return m_hovered; } +bool wxRibbonPanel::IsExtButtonHovered() const +{ + return m_ext_button_hovered; +} + void wxRibbonPanel::OnMouseEnter(wxMouseEvent& evt) { TestPositionForHover(evt.GetPosition()); @@ -177,9 +189,14 @@ void wxRibbonPanel::OnMouseLeaveChild(wxMouseEvent& evt) evt.Skip(); } +void wxRibbonPanel::OnMotion(wxMouseEvent& evt) +{ + TestPositionForHover(evt.GetPosition()); +} + void wxRibbonPanel::TestPositionForHover(const wxPoint& pos) { - bool hovered = false; + bool hovered = false, ext_button_hovered = false; if(pos.x >= 0 && pos.y >= 0) { wxSize size = GetSize(); @@ -188,9 +205,17 @@ void wxRibbonPanel::TestPositionForHover(const wxPoint& pos) hovered = true; } } - if(hovered != m_hovered) + if(hovered) + { + if(HasExtButton()) + ext_button_hovered = m_ext_button_rect.Contains(pos); + else + ext_button_hovered = false; + } + if(hovered != m_hovered || ext_button_hovered != m_ext_button_hovered) { m_hovered = hovered; + m_ext_button_hovered = ext_button_hovered; Refresh(false); } } @@ -215,6 +240,15 @@ void wxRibbonPanel::RemoveChild(wxWindowBase *child) wxRibbonControl::RemoveChild(child); } +bool wxRibbonPanel::HasExtButton()const +{ + wxRibbonBar* bar = GetAncestorRibbonBar(); + if(bar==NULL) + return false; + return (m_flags & wxRIBBON_PANEL_EXT_BUTTON) && + (bar->GetWindowStyleFlag() & wxRIBBON_BAR_SHOW_PANEL_EXT_BUTTONS); +} + void wxRibbonPanel::OnSize(wxSizeEvent& evt) { if(GetAutoLayout()) @@ -233,11 +267,13 @@ void wxRibbonPanel::DoSetSize(int x, int y, int width, int height, int sizeFlags // will refuse to grow any larger while in limbo between minimised and non. bool minimised = (m_flags & wxRIBBON_PANEL_NO_AUTO_MINIMISE) == 0 && - IsMinimised(wxSize(width, height)); + IsMinimised(wxSize(width, height)); // check if would be at this size if(minimised != m_minimised) { m_minimised = minimised; - + // Note that for sizers, this routine disallows the use of mixed shown + // and hidden controls + // TODO ? use some list of user set invisible children to restore status. for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext()) @@ -247,17 +283,29 @@ void wxRibbonPanel::DoSetSize(int x, int y, int width, int height, int sizeFlags Refresh(); } - + wxRibbonControl::DoSetSize(x, y, width, height, sizeFlags); } +// Checks if panel would be minimised at (client size) at_size bool wxRibbonPanel::IsMinimised(wxSize at_size) const { + if(GetSizer()) + { + // we have no information on size change direction + // so check both + wxSize size = GetMinNotMinimisedSize(); + if(size.x > at_size.x || size.y > at_size.y) + return true; + + return false; + } + if(!m_minimised_size.IsFullySpecified()) return false; return (at_size.GetX() <= m_minimised_size.GetX() && - at_size.GetY() <= m_minimised_size.GetY()) || + at_size.GetY() <= m_minimised_size.GetY()) || at_size.GetX() < m_smallest_unminimised_size.GetX() || at_size.GetY() < m_smallest_unminimised_size.GetY(); } @@ -288,7 +336,31 @@ bool wxRibbonPanel::IsSizingContinuous() const { // A panel never sizes continuously, even if all of its children can, // as it would appear out of place along side non-continuous panels. - return false; + + // JS 2012-03-09: introducing wxRIBBON_PANEL_STRETCH to allow + // the panel to fill its parent page. For example we might have + // a list of styles in one of the pages, which should stretch to + // fill available space. + return (m_flags & wxRIBBON_PANEL_STRETCH) != 0; +} + +// Finds the best width and height given the parent's width and height +wxSize wxRibbonPanel::GetBestSizeForParentSize(const wxSize& parentSize) const +{ + if (GetChildren().GetCount() == 1) + { + wxWindow* win = GetChildren().GetFirst()->GetData(); + wxRibbonControl* control = wxDynamicCast(win, wxRibbonControl); + if (control) + { + wxClientDC temp_dc((wxRibbonPanel*) this); + wxSize clientParentSize = m_art->GetPanelClientSize(temp_dc, this, parentSize, NULL); + wxSize childSize = control->GetBestSizeForParentSize(clientParentSize); + wxSize overallSize = m_art->GetPanelSize(temp_dc, this, childSize, NULL); + return overallSize; + } + } + return GetSize(); } wxSize wxRibbonPanel::DoGetNextSmallerSize(wxOrientation direction, @@ -301,46 +373,70 @@ wxSize wxRibbonPanel::DoGetNextSmallerSize(wxOrientation direction, return m_expanded_panel->DoGetNextSmallerSize(direction, relative_to); } - // TODO: Check for, and delegate to, a sizer - - // Simple (and common) case of single ribbon child - if(GetChildren().GetCount() == 1) + if(m_art != NULL) { - wxWindow* child = GetChildren().Item(0)->GetData(); - wxRibbonControl* ribbon_child = wxDynamicCast(child, wxRibbonControl); - if(m_art != NULL && ribbon_child != NULL) + wxClientDC dc((wxRibbonPanel*) this); + wxSize child_relative = m_art->GetPanelClientSize(dc, this, relative_to, NULL); + wxSize smaller(-1, -1); + bool minimise = false; + + if(GetSizer()) { - wxClientDC dc((wxRibbonPanel*) this); - wxSize child_relative = m_art->GetPanelClientSize(dc, this, relative_to, NULL); - wxSize smaller = ribbon_child->GetNextSmallerSize(direction, child_relative); - if(smaller == child_relative) + // Get smallest non minimised size + smaller = GetMinSize(); + // and adjust to child_relative for parent page + if(m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL) { - if(CanAutoMinimise()) - { - wxSize minimised = m_minimised_size; - switch(direction) - { - case wxHORIZONTAL: - minimised.SetHeight(relative_to.GetHeight()); - break; - case wxVERTICAL: - minimised.SetWidth(relative_to.GetWidth()); - break; - default: - break; - } - return minimised; - } - else + minimise = (child_relative.y <= smaller.y); + if(smaller.x < child_relative.x) + smaller.x = child_relative.x; + } + else + { + minimise = (child_relative.x <= smaller.x); + if(smaller.y < child_relative.y) + smaller.y = child_relative.y; + } + } + else if(GetChildren().GetCount() == 1) + { + // Simple (and common) case of single ribbon child or Sizer + wxWindow* child = GetChildren().Item(0)->GetData(); + wxRibbonControl* ribbon_child = wxDynamicCast(child, wxRibbonControl); + if(ribbon_child != NULL) + { + smaller = ribbon_child->GetNextSmallerSize(direction, child_relative); + minimise = (smaller == child_relative); + } + } + + if(minimise) + { + if(CanAutoMinimise()) + { + wxSize minimised = m_minimised_size; + switch(direction) { - return relative_to; + case wxHORIZONTAL: + minimised.SetHeight(relative_to.GetHeight()); + break; + case wxVERTICAL: + minimised.SetWidth(relative_to.GetWidth()); + break; + default: + break; } + return minimised; } else { - return m_art->GetPanelSize(dc, this, smaller, NULL); + return relative_to; } } + else if(smaller.IsFullySpecified()) // Use fallback if !(sizer/child = 1) + { + return m_art->GetPanelSize(dc, this, smaller, NULL); + } } // Fallback: Decrease by 20% (or minimum size, whichever larger) @@ -398,25 +494,47 @@ wxSize wxRibbonPanel::DoGetNextLargerSize(wxOrientation direction, } } - // TODO: Check for, and delegate to, a sizer - - // Simple (and common) case of single ribbon child - if(GetChildren().GetCount() == 1) + if(m_art != NULL) { - wxWindow* child = GetChildren().Item(0)->GetData(); - wxRibbonControl* ribbon_child = wxDynamicCast(child, wxRibbonControl); - if(ribbon_child != NULL) + wxClientDC dc((wxRibbonPanel*) this); + wxSize child_relative = m_art->GetPanelClientSize(dc, this, relative_to, NULL); + wxSize larger(-1, -1); + + if(GetSizer()) + { + // We could just let the sizer expand in flow direction but see comment + // in IsSizingContinuous() + larger = GetPanelSizerBestSize(); + // and adjust for page in non flow direction + if(m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL) + { + if(larger.x != child_relative.x) + larger.x = child_relative.x; + } + else if(larger.y != child_relative.y) + { + larger.y = child_relative.y; + } + } + else if(GetChildren().GetCount() == 1) + { + // Simple (and common) case of single ribbon child + wxWindow* child = GetChildren().Item(0)->GetData(); + wxRibbonControl* ribbon_child = wxDynamicCast(child, wxRibbonControl); + if(ribbon_child != NULL) + { + larger = ribbon_child->GetNextLargerSize(direction, child_relative); + } + } + + if(larger.IsFullySpecified()) // Use fallback if !(sizer/child = 1) { - wxClientDC dc((wxRibbonPanel*) this); - wxSize child_relative = m_art->GetPanelClientSize(dc, this, relative_to, NULL); - wxSize larger = ribbon_child->GetNextLargerSize(direction, child_relative); if(larger == child_relative) { return relative_to; } else { - wxClientDC dc((wxRibbonPanel*) this); return m_art->GetPanelSize(dc, this, larger, NULL); } } @@ -467,11 +585,15 @@ wxSize wxRibbonPanel::GetMinSize() const wxSize wxRibbonPanel::GetMinNotMinimisedSize() const { - // TODO: Ask sizer - - // Common case of no sizer and single child taking up the entire panel - if(GetChildren().GetCount() == 1) + // Ask sizer if present + if(GetSizer()) + { + wxClientDC dc((wxRibbonPanel*) this); + return m_art->GetPanelSize(dc, this, GetPanelSizerMinSize(), NULL); + } + else if(GetChildren().GetCount() == 1) { + // Common case of single child taking up the entire panel wxWindow* child = GetChildren().Item(0)->GetData(); wxClientDC dc((wxRibbonPanel*) this); return m_art->GetPanelSize(dc, this, child->GetMinSize(), NULL); @@ -480,13 +602,47 @@ wxSize wxRibbonPanel::GetMinNotMinimisedSize() const return wxRibbonControl::GetMinSize(); } -wxSize wxRibbonPanel::DoGetBestSize() const +wxSize wxRibbonPanel::GetPanelSizerMinSize() const +{ + // Called from Realize() to set m_smallest_unminimised_size and from other + // functions to get the minimum size. + // The panel will be invisible when minimised and sizer calcs will be 0 + // Uses m_smallest_unminimised_size in preference to GetSizer()->CalcMin() + // to eliminate flicker. + + // Check if is visible and not previously calculated + if(IsShown() && !m_smallest_unminimised_size.IsFullySpecified()) + { + return GetSizer()->CalcMin(); + } + // else use previously calculated m_smallest_unminimised_size + wxClientDC dc((wxRibbonPanel*) this); + return m_art->GetPanelClientSize(dc, + this, + m_smallest_unminimised_size, + NULL); +} + +wxSize wxRibbonPanel::GetPanelSizerBestSize() const { - // TODO: Ask sizer + wxSize size = GetPanelSizerMinSize(); + // TODO allow panel to increase its size beyond minimum size + // by steps similarly to ribbon control panels (preferred for aesthetics) + // or continuously. + return size; +} - // Common case of no sizer and single child taking up the entire panel - if(GetChildren().GetCount() == 1) +wxSize wxRibbonPanel::DoGetBestSize() const +{ + // Ask sizer if present + if( GetSizer()) + { + wxClientDC dc((wxRibbonPanel*) this); + return m_art->GetPanelSize(dc, this, GetPanelSizerBestSize(), NULL); + } + else if(GetChildren().GetCount() == 1) { + // Common case of no sizer and single child taking up the entire panel wxWindow* child = GetChildren().Item(0)->GetData(); wxClientDC dc((wxRibbonPanel*) this); return m_art->GetPanelSize(dc, this, child->GetBestSize(), NULL); @@ -515,8 +671,13 @@ bool wxRibbonPanel::Realize() } wxSize minimum_children_size(0, 0); - // TODO: Ask sizer if there is one - if(GetChildren().GetCount() == 1) + + // Ask sizer if there is one present + if(GetSizer()) + { + minimum_children_size = GetPanelSizerMinSize(); + } + else if(GetChildren().GetCount() == 1) { minimum_children_size = GetChildren().GetFirst()->GetData()->GetMinSize(); } @@ -582,10 +743,10 @@ bool wxRibbonPanel::Layout() wxClientDC dc(this); wxSize size = m_art->GetPanelClientSize(dc, this, GetSize(), &position); - // If there is a sizer, use it instead - if ( GetSizer() ) + // If there is a sizer, use it + if(GetSizer()) { - GetSizer()->SetDimension(position.x, position.y, size.GetWidth(), size.GetHeight()); + GetSizer()->SetDimension(position, size); // SetSize and Layout() } else if(GetChildren().GetCount() == 1) { @@ -593,6 +754,10 @@ bool wxRibbonPanel::Layout() wxWindow* child = GetChildren().Item(0)->GetData(); child->SetSize(position.x, position.y, size.GetWidth(), size.GetHeight()); } + + if(HasExtButton()) + m_ext_button_rect = m_art->GetPanelExtButtonArea(dc, this, GetSize()); + return true; } @@ -609,6 +774,13 @@ void wxRibbonPanel::OnMouseClick(wxMouseEvent& WXUNUSED(evt)) ShowExpanded(); } } + else if(IsExtButtonHovered()) + { + wxRibbonPanelEvent notification(wxEVT_COMMAND_RIBBONPANEL_EXTBUTTON_ACTIVATED, GetId()); + notification.SetEventObject(this); + notification.SetPanel(this); + ProcessEvent(notification); + } } wxRibbonPanel* wxRibbonPanel::GetExpandedDummy() @@ -633,6 +805,13 @@ bool wxRibbonPanel::ShowExpanded() } wxSize size = GetBestSize(); + + // Special case for flexible panel layout, where GetBestSize doesn't work + if (GetFlags() & wxRIBBON_PANEL_FLEXIBLE) + { + size = GetBestSizeForParentSize(wxSize(400, 1000)); + } + wxPoint pos = GetExpandedPosition(wxRect(GetScreenPosition(), GetSize()), size, m_preferred_expand_direction).GetTopLeft(); @@ -641,7 +820,7 @@ bool wxRibbonPanel::ShowExpanded() pos, size, wxFRAME_NO_TASKBAR | wxBORDER_NONE); m_expanded_panel = new wxRibbonPanel(container, wxID_ANY, - GetLabel(), m_minimised_icon, wxPoint(0, 0), size, m_flags); + GetLabel(), m_minimised_icon, wxPoint(0, 0), size, (m_flags /* & ~wxRIBBON_PANEL_FLEXIBLE */)); m_expanded_panel->SetArtProvider(m_art); m_expanded_panel->m_expanded_dummy = this; @@ -661,10 +840,17 @@ bool wxRibbonPanel::ShowExpanded() child->Show(); } - // TODO: Move sizer to new panel + // Move sizer to new panel + if(GetSizer()) + { + wxSizer* sizer = GetSizer(); + SetSizer(NULL, false); + m_expanded_panel->SetSizer(sizer); + } m_expanded_panel->Realize(); Refresh(); + container->SetMinClientSize(size); container->Show(); m_expanded_panel->SetFocus(); @@ -782,7 +968,13 @@ bool wxRibbonPanel::HideExpanded() child->Hide(); } - // TODO: Move sizer back + // Move sizer back + if(GetSizer()) + { + wxSizer* sizer = GetSizer(); + SetSizer(NULL, false); + m_expanded_dummy->SetSizer(sizer); + } m_expanded_dummy->m_expanded_panel = NULL; m_expanded_dummy->Realize(); @@ -907,4 +1099,9 @@ wxRect wxRibbonPanel::GetExpandedPosition(wxRect panel, return best; } +void wxRibbonPanel::HideIfExpanded() +{ + wxStaticCast(m_parent, wxRibbonPage)->HideIfExpanded(); +} + #endif // wxUSE_RIBBON