#include "wx/ribbon/bar.h"
#include "wx/ribbon/art.h"
#include "wx/dcbuffer.h"
+#include "wx/app.h"
+#include "wx/vector.h"
#ifndef WX_PRECOMP
#endif
wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBAR_TAB_RIGHT_DOWN, wxRibbonBarEvent);
wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBAR_TAB_RIGHT_UP, wxRibbonBarEvent);
wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBAR_TAB_LEFT_DCLICK, wxRibbonBarEvent);
+wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBAR_TOGGLED, wxRibbonBarEvent);
+wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBAR_HELP_CLICKED, wxRibbonBarEvent);
IMPLEMENT_CLASS(wxRibbonBar, wxRibbonControl)
IMPLEMENT_DYNAMIC_CLASS(wxRibbonBarEvent, wxNotifyEvent)
EVT_RIGHT_UP(wxRibbonBar::OnMouseRightUp)
EVT_LEFT_DCLICK(wxRibbonBar::OnMouseDoubleClick)
EVT_SIZE(wxRibbonBar::OnSize)
+ EVT_KILL_FOCUS(wxRibbonBar::OnKillFocus)
END_EVENT_TABLE()
void wxRibbonBar::AddPage(wxRibbonPage *page)
info.page = page;
info.active = false;
info.hovered = false;
+ info.highlight = false;
+ info.shown = true;
// info.rect not set (intentional)
wxClientDC dcTemp(this);
return m_pages.Item(m_current_page).page->DismissExpandedPanel();
}
-void wxRibbonBar::ShowPanels(const bool show)
+void wxRibbonBar::ShowPanels(bool show)
{
m_arePanelsShown = show;
SetMinSize(wxSize(GetSize().GetWidth(), DoGetBestSize().GetHeight()));
for(i = 0; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
RepositionPage(info.page);
if(!info.page->Realize())
{
{
RefreshTabBar();
}
+ if ( m_flags & wxRIBBON_BAR_SHOW_TOGGLE_BUTTON )
+ HitTestRibbonButton(m_toggle_button_rect, evt.GetPosition(), m_toggle_button_hovered);
+ if ( m_flags & wxRIBBON_BAR_SHOW_HELP_BUTTON )
+ HitTestRibbonButton(m_help_button_rect, evt.GetPosition(), m_help_button_hovered);
}
void wxRibbonBar::OnMouseLeave(wxMouseEvent& WXUNUSED(evt))
{
RefreshTabBar();
}
+ if(m_toggle_button_hovered)
+ {
+ m_bar_hovered = false;
+ m_toggle_button_hovered = false;
+ Refresh(false);
+ }
+ if ( m_help_button_hovered )
+ {
+ m_help_button_hovered = false;
+ m_bar_hovered = false;
+ Refresh(false);
+ }
}
wxRibbonPage* wxRibbonBar::GetPage(int n)
return m_pages.Item(n).page;
}
+size_t wxRibbonBar::GetPageCount() const
+{
+ return m_pages.GetCount();
+}
+
+bool wxRibbonBar::IsPageShown(size_t page) const
+{
+ if (page >= m_pages.GetCount())
+ return false;
+ return m_pages.Item(page).shown;
+}
+
+void wxRibbonBar::ShowPage(size_t page, bool show)
+{
+ if(page >= m_pages.GetCount())
+ return;
+ m_pages.Item(page).shown = show;
+}
+
+bool wxRibbonBar::IsPageHighlighted(size_t page) const
+{
+ if (page >= m_pages.GetCount())
+ return false;
+ return m_pages.Item(page).highlight;
+}
+
+void wxRibbonBar::AddPageHighlight(size_t page, bool highlight)
+{
+ if(page >= m_pages.GetCount())
+ return;
+ m_pages.Item(page).highlight = highlight;
+}
+
+void wxRibbonBar::DeletePage(size_t n)
+{
+ if(n < m_pages.GetCount())
+ {
+ wxRibbonPage *page = m_pages.Item(n).page;
+
+ // Schedule page object for destruction and not destroying directly
+ // as this function can be called in an event handler and page functions
+ // can be called afeter removing.
+ // Like in wxRibbonButtonBar::OnMouseUp
+ if(!wxTheApp->IsScheduledForDestruction(page))
+ {
+ wxTheApp->ScheduleForDestruction(page);
+ }
+
+ m_pages.RemoveAt(n);
+
+ if(m_current_page == static_cast<int>(n))
+ {
+ m_current_page = -1;
+
+ if(m_pages.GetCount() > 0)
+ {
+ if(n >= m_pages.GetCount())
+ {
+ SetActivePage(m_pages.GetCount() - 1);
+ }
+ else
+ {
+ SetActivePage(n - 1);
+ }
+ }
+ }
+ else if(m_current_page > static_cast<int>(n))
+ {
+ m_current_page--;
+ }
+ }
+}
+
+void wxRibbonBar::ClearPages()
+{
+ size_t i;
+ for(i=0; i<m_pages.GetCount(); i++)
+ {
+ wxRibbonPage *page = m_pages.Item(i).page;
+ // Schedule page object for destruction and not destroying directly
+ // as this function can be called in an event handler and page functions
+ // can be called afeter removing.
+ // Like in wxRibbonButtonBar::OnMouseUp
+ if(!wxTheApp->IsScheduledForDestruction(page))
+ {
+ wxTheApp->ScheduleForDestruction(page);
+ }
+ }
+ m_pages.Empty();
+ Realize();
+ m_current_page = -1;
+ Refresh();
+}
+
bool wxRibbonBar::SetActivePage(size_t page)
{
if(m_current_page == (int)page)
}
m_current_page = (int)page;
m_pages.Item(page).active = true;
+ m_pages.Item(page).shown = true;
{
wxRibbonPage* wnd = m_pages.Item(page).page;
RepositionPage(wnd);
return false;
}
+int wxRibbonBar::GetPageNumber(wxRibbonPage* page) const
+{
+ size_t numpages = m_pages.GetCount();
+ for(size_t i = 0; i < numpages; ++i)
+ {
+ if(m_pages.Item(i).page == page)
+ {
+ return i;
+ }
+ }
+ return wxNOT_FOUND;
+}
+
+
int wxRibbonBar::GetActivePage() const
{
return m_current_page;
RecalculateTabSizes();
}
-static int OrderPageTabInfoBySmallWidthAsc(wxRibbonPageTabInfo **first, wxRibbonPageTabInfo **second)
+struct PageComparedBySmallWidthAsc
{
- return (**first).small_must_have_separator_width - (**second).small_must_have_separator_width;
-}
+ wxEXPLICIT PageComparedBySmallWidthAsc(wxRibbonPageTabInfo* page)
+ : m_page(page)
+ {
+ }
+
+ bool operator<(const PageComparedBySmallWidthAsc& other) const
+ {
+ return m_page->small_must_have_separator_width
+ < other.m_page->small_must_have_separator_width;
+ }
+
+ wxRibbonPageTabInfo *m_page;
+};
void wxRibbonBar::RecalculateTabSizes()
{
for(i = 0; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
info.rect.x = x;
info.rect.y = y;
info.rect.width = info.ideal_width;
for(i = 0; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
info.rect.x = x;
info.rect.y = y;
info.rect.width = info.minimum_width;
}
{
wxClientDC temp_dc(this);
+ int right_button_pos = GetClientSize().GetWidth() - m_tab_margin_right - m_tab_scroll_right_button_rect.GetWidth();
+ if ( right_button_pos < m_tab_margin_left )
+ right_button_pos = m_tab_margin_left;
+
m_tab_scroll_left_button_rect.SetWidth(m_art->GetScrollButtonMinimumSize(temp_dc, this, wxRIBBON_SCROLL_BTN_LEFT | wxRIBBON_SCROLL_BTN_NORMAL | wxRIBBON_SCROLL_BTN_FOR_TABS).GetWidth());
m_tab_scroll_left_button_rect.SetHeight(m_tab_height);
m_tab_scroll_left_button_rect.SetX(m_tab_margin_left);
m_tab_scroll_left_button_rect.SetY(0);
m_tab_scroll_right_button_rect.SetWidth(m_art->GetScrollButtonMinimumSize(temp_dc, this, wxRIBBON_SCROLL_BTN_RIGHT | wxRIBBON_SCROLL_BTN_NORMAL | wxRIBBON_SCROLL_BTN_FOR_TABS).GetWidth());
m_tab_scroll_right_button_rect.SetHeight(m_tab_height);
- m_tab_scroll_right_button_rect.SetX(GetClientSize().GetWidth() - m_tab_margin_right - m_tab_scroll_right_button_rect.GetWidth());
+ m_tab_scroll_right_button_rect.SetX(right_button_pos);
m_tab_scroll_right_button_rect.SetY(0);
}
if(m_tab_scroll_amount == 0)
for(i = 0; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
info.rect.x -= m_tab_scroll_amount;
}
}
for(i = 0; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
if(info.small_must_have_separator_width < smallest_tab_width)
{
smallest_tab_width = info.small_must_have_separator_width;
for(i = 0; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
int delta = info.ideal_width - info.small_must_have_separator_width;
info.rect.x = x;
info.rect.y = y;
for(i = 0; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
if(info.minimum_width < smallest_tab_width)
{
total_small_width += smallest_tab_width;
if(width >= total_small_width)
{
// Do (2)
- wxRibbonPageTabInfoArray sorted_pages;
- for(i = 0; i < numtabs; ++i)
- {
- // Sneaky obj array trickery to not copy the tab descriptors
- sorted_pages.Add(&m_pages.Item(i));
- }
- sorted_pages.Sort(OrderPageTabInfoBySmallWidthAsc);
+ wxVector<PageComparedBySmallWidthAsc> sorted_pages;
+ sorted_pages.reserve(numtabs);
+ for ( i = 0; i < numtabs; ++i )
+ sorted_pages.push_back(PageComparedBySmallWidthAsc(&m_pages.Item(i)));
+
+ wxVectorSort(sorted_pages);
width -= tabsep * (numtabs - 1);
for(i = 0; i < numtabs; ++i)
{
- wxRibbonPageTabInfo& info = sorted_pages.Item(i);
- if(info.small_must_have_separator_width * (int)(numtabs - i) <= width)
+ wxRibbonPageTabInfo* info = sorted_pages[i].m_page;
+ if (!info->shown)
+ continue;
+ if(info->small_must_have_separator_width * (int)(numtabs - i) <= width)
{
- info.rect.width = info.small_must_have_separator_width;;
+ info->rect.width = info->small_must_have_separator_width;;
}
else
{
- info.rect.width = width / (numtabs - i);
+ info->rect.width = width / (numtabs - i);
}
- width -= info.rect.width;
+ width -= info->rect.width;
}
for(i = 0; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
info.rect.x = x;
info.rect.y = y;
info.rect.height = m_tab_height;
x += info.rect.width + tabsep;
- sorted_pages.Detach(numtabs - (i + 1));
}
}
else
for(i = 0; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
int delta = smallest_tab_width - info.minimum_width;
info.rect.x = x;
info.rect.y = y;
m_tab_scroll_right_button_state = wxRIBBON_SCROLL_BTN_NORMAL;
m_tab_scroll_buttons_shown = false;
m_arePanelsShown = true;
+ m_help_button_hovered = false;
}
wxRibbonBar::wxRibbonBar(wxWindow* parent,
m_tabs_total_width_minimum = 0;
m_tab_margin_left = 50;
m_tab_margin_right = 20;
+ if ( m_flags & wxRIBBON_BAR_SHOW_TOGGLE_BUTTON )
+ m_tab_margin_right += 20;
+ if ( m_flags & wxRIBBON_BAR_SHOW_HELP_BUTTON )
+ m_tab_margin_right += 20;
m_tab_height = 20; // initial guess
m_tab_scroll_amount = 0;
m_current_page = -1;
SetArtProvider(new wxRibbonDefaultArtProvider);
}
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
+
+ m_toggle_button_hovered = false;
+ m_bar_hovered = false;
+
+ m_ribbon_state = wxRIBBON_BAR_PINNED;
}
void wxRibbonBar::SetArtProvider(wxRibbonArtProvider* art)
DoEraseBackground(dc);
+ if ( m_flags & wxRIBBON_BAR_SHOW_HELP_BUTTON )
+ m_help_button_rect = m_art->GetRibbonHelpButtonArea(GetSize());
+ if ( m_flags & wxRIBBON_BAR_SHOW_TOGGLE_BUTTON )
+ m_toggle_button_rect = m_art->GetBarToggleButtonArea(GetSize());
+
size_t numtabs = m_pages.GetCount();
double sep_visibility = 0.0;
bool draw_sep = false;
for(i = 0; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
dc.DestroyClippingRegion();
if(m_tab_scroll_buttons_shown)
for(i = 0; i < numtabs - 1; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
rect.x = info.rect.x + info.rect.width;
if(m_tab_scroll_buttons_shown && !tabs_rect.Intersects(rect))
}
if(m_tab_scroll_buttons_shown)
{
- dc.DestroyClippingRegion();
if(m_tab_scroll_left_button_rect.GetWidth() != 0)
{
+ dc.DestroyClippingRegion();
+ dc.SetClippingRegion(m_tab_scroll_left_button_rect);
m_art->DrawScrollButton(dc, this, m_tab_scroll_left_button_rect, wxRIBBON_SCROLL_BTN_LEFT | m_tab_scroll_left_button_state | wxRIBBON_SCROLL_BTN_FOR_TABS);
}
if(m_tab_scroll_right_button_rect.GetWidth() != 0)
{
+ dc.DestroyClippingRegion();
+ dc.SetClippingRegion(m_tab_scroll_right_button_rect);
m_art->DrawScrollButton(dc, this, m_tab_scroll_right_button_rect, wxRIBBON_SCROLL_BTN_RIGHT | m_tab_scroll_right_button_state | wxRIBBON_SCROLL_BTN_FOR_TABS);
}
}
+
+ if ( m_flags & wxRIBBON_BAR_SHOW_HELP_BUTTON )
+ m_art->DrawHelpButton(dc, this, m_help_button_rect);
+ if ( m_flags & wxRIBBON_BAR_SHOW_TOGGLE_BUTTON )
+ m_art->DrawToggleButton(dc, this, m_toggle_button_rect, m_ribbon_state);
+
}
void wxRibbonBar::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
for(i = 0; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
if(info.rect.Contains(position))
{
if(index != NULL)
void wxRibbonBar::OnMouseLeftDown(wxMouseEvent& evt)
{
wxRibbonPageTabInfo *tab = HitTestTabs(evt.GetPosition());
+ SetFocus();
+ if ( tab )
+ {
+ if ( m_ribbon_state == wxRIBBON_BAR_MINIMIZED )
+ {
+ ShowPanels();
+ m_ribbon_state = wxRIBBON_BAR_EXPANDED;
+ }
+ else if ( (tab == &m_pages.Item(m_current_page)) && (m_ribbon_state == wxRIBBON_BAR_EXPANDED) )
+ {
+ HidePanels();
+ m_ribbon_state = wxRIBBON_BAR_MINIMIZED;
+ }
+ }
+ else
+ {
+ if ( m_ribbon_state == wxRIBBON_BAR_EXPANDED )
+ {
+ HidePanels();
+ m_ribbon_state = wxRIBBON_BAR_MINIMIZED;
+ }
+ }
if(tab && tab != &m_pages.Item(m_current_page))
{
wxRibbonBarEvent query(wxEVT_COMMAND_RIBBONBAR_PAGE_CHANGING, GetId(), tab->page);
RefreshTabBar();
}
}
+
+ wxPoint position = evt.GetPosition();
+
+ if(position.x >= 0 && position.y >= 0)
+ {
+ wxSize size = GetSize();
+ if(position.x < size.GetWidth() && position.y < size.GetHeight())
+ {
+ if(m_toggle_button_rect.Contains(position))
+ {
+ bool pshown = ArePanelsShown();
+ ShowPanels(!pshown);
+ if ( pshown )
+ m_ribbon_state = wxRIBBON_BAR_MINIMIZED;
+ else
+ m_ribbon_state = wxRIBBON_BAR_PINNED;
+ wxRibbonBarEvent event(wxEVT_COMMAND_RIBBONBAR_TOGGLED, GetId());
+ event.SetEventObject(this);
+ ProcessWindowEvent(event);
+ }
+ if ( m_help_button_rect.Contains(position) )
+ {
+ wxRibbonBarEvent event(wxEVT_COMMAND_RIBBONBAR_HELP_CLICKED, GetId());
+ event.SetEventObject(this);
+ ProcessWindowEvent(event);
+ }
+ }
+ }
}
void wxRibbonBar::OnMouseLeftUp(wxMouseEvent& WXUNUSED(evt))
for(i = 0; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
info.rect.SetX(info.rect.GetX() - amount);
}
if(show_right != (m_tab_scroll_right_button_rect.GetWidth() != 0) ||
void wxRibbonBar::OnMouseDoubleClick(wxMouseEvent& evt)
{
- DoMouseButtonCommon(evt, wxEVT_COMMAND_RIBBONBAR_TAB_LEFT_DCLICK);
+ wxRibbonPageTabInfo *tab = HitTestTabs(evt.GetPosition());
+ SetFocus();
+ if ( tab && tab == &m_pages.Item(m_current_page) )
+ {
+ if ( m_ribbon_state == wxRIBBON_BAR_PINNED )
+ {
+ m_ribbon_state = wxRIBBON_BAR_MINIMIZED;
+ HidePanels();
+ }
+ else
+ {
+ m_ribbon_state = wxRIBBON_BAR_PINNED;
+ ShowPanels();
+ }
+ }
}
void wxRibbonBar::DoMouseButtonCommon(wxMouseEvent& evt, wxEventType tab_event_type)
for(i = 1; i < numtabs; ++i)
{
wxRibbonPageTabInfo& info = m_pages.Item(i);
+ if (!info.shown)
+ continue;
wxSize page_min = info.page->GetMinSize();
min_size.x = wxMax(min_size.x, page_min.x);
return best;
}
+void wxRibbonBar::HitTestRibbonButton(const wxRect& rect, const wxPoint& position, bool &hover_flag)
+{
+ bool hovered = false, toggle_button_hovered = false;
+ if(position.x >= 0 && position.y >= 0)
+ {
+ wxSize size = GetSize();
+ if(position.x < size.GetWidth() && position.y < size.GetHeight())
+ {
+ hovered = true;
+ }
+ }
+ if(hovered)
+ {
+ toggle_button_hovered = rect.Contains(position);
+
+ if ( hovered != m_bar_hovered || toggle_button_hovered != hover_flag )
+ {
+ m_bar_hovered = hovered;
+ hover_flag = toggle_button_hovered;
+ Refresh(false);
+ }
+ }
+}
+
+void wxRibbonBar::HideIfExpanded()
+{
+ if ( m_ribbon_state == wxRIBBON_BAR_EXPANDED )
+ {
+ HidePanels();
+ m_ribbon_state = wxRIBBON_BAR_MINIMIZED;
+ }
+ else
+ {
+ ShowPanels();
+ m_ribbon_state = wxRIBBON_BAR_PINNED;
+ }
+}
+
+void wxRibbonBar::OnKillFocus(wxFocusEvent& WXUNUSED(evt))
+{
+ HideIfExpanded();
+}
+
#endif // wxUSE_RIBBON