Add support for stretchable spaces to wxToolBar.
Stretchable spaces consume all extra toolbar space not allocated to the fixed size items. They can in particular be used to right-align (some) toolbar tools. Add and document the new API, change the sample to show it and implement it for MSW, GTK and OS X/Cocoa. Also refactor MSW background erasing/repainting code to avoid duplicated calls to DrawThemeBackground(), call it from a new helper MSWEraseRect() function. Note that we may want to add support for "invisible" separators, IOW non-stretchable spaces. This could be easily done for MSW after the changes in this commit and is supported natively by GTK+ and Cocoa so implementing this would be trivial if there is any interest. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@62850 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -445,6 +445,7 @@ All (GUI):
|
||||
|
||||
- Added support for showing bitmaps in wxButton.
|
||||
- Added wxInfoBar.
|
||||
- Added stretchable spaces support to wxToolBar.
|
||||
- Added support for corner, row and column headers renderers to wxGrid.
|
||||
- wxWindow::SetAutoLayout() now works for all windows, not just panels.
|
||||
- Support wxListCtrl columns, items and image lists in XRC (Kinaou Hervé).
|
||||
|
@@ -142,6 +142,10 @@ protected:
|
||||
// the total number of toolbar elements
|
||||
size_t m_nButtons;
|
||||
|
||||
// the sum of the sizes of the fixed items (i.e. excluding stretchable
|
||||
// spaces) in the toolbar direction
|
||||
int m_totalFixedSize;
|
||||
|
||||
// the tool the cursor is in
|
||||
wxToolBarToolBase *m_pInTool;
|
||||
|
||||
@@ -149,6 +153,17 @@ private:
|
||||
// makes sure tool bitmap size is sufficient for all tools
|
||||
void AdjustToolBitmapSize();
|
||||
|
||||
// update the sizes of stretchable spacers to consume all extra space we
|
||||
// have
|
||||
void UpdateStretchableSpacersSize();
|
||||
|
||||
// redraw the background of the given part of the window (or entire window
|
||||
// if the parameter is NULL) to erase separator drawn in it
|
||||
//
|
||||
// return true if the background was erased using DrawThemeBackground()
|
||||
bool MSWEraseRect(wxDC& dc, const wxRect *rectItem = NULL);
|
||||
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
DECLARE_DYNAMIC_CLASS(wxToolBar)
|
||||
wxDECLARE_NO_COPY_CLASS(wxToolBar);
|
||||
|
@@ -101,11 +101,6 @@ public:
|
||||
m_control = control;
|
||||
}
|
||||
|
||||
m_toolStyle = wxTOOL_STYLE_CONTROL;
|
||||
|
||||
m_dropdownMenu = 0;
|
||||
}
|
||||
|
||||
virtual ~wxToolBarToolBase();
|
||||
|
||||
// accessors
|
||||
@@ -123,10 +118,12 @@ public:
|
||||
|
||||
wxToolBarBase *GetToolBar() const { return m_tbar; }
|
||||
|
||||
// style
|
||||
// style/kind
|
||||
bool IsStretchable() const { return m_stretchable; }
|
||||
bool IsButton() const { return m_toolStyle == wxTOOL_STYLE_BUTTON; }
|
||||
bool IsControl() const { return m_toolStyle == wxTOOL_STYLE_CONTROL; }
|
||||
bool IsSeparator() const { return m_toolStyle == wxTOOL_STYLE_SEPARATOR; }
|
||||
bool IsStretchableSpace() const { return IsSeparator() && IsStretchable(); }
|
||||
int GetStyle() const { return m_toolStyle; }
|
||||
wxItemKind GetKind() const
|
||||
{
|
||||
@@ -135,6 +132,13 @@ public:
|
||||
return m_kind;
|
||||
}
|
||||
|
||||
void MakeStretchable()
|
||||
{
|
||||
wxASSERT_MSG( IsSeparator(), "only separators can be stretchable" );
|
||||
|
||||
m_stretchable = true;
|
||||
}
|
||||
|
||||
// state
|
||||
bool IsEnabled() const { return m_enabled; }
|
||||
bool IsToggled() const { return m_toggled; }
|
||||
@@ -214,6 +218,7 @@ protected:
|
||||
|
||||
m_clientData = NULL;
|
||||
|
||||
m_stretchable = false;
|
||||
m_toggled = false;
|
||||
m_enabled = true;
|
||||
|
||||
@@ -223,7 +228,7 @@ protected:
|
||||
wxToolBarBase *m_tbar; // the toolbar to which we belong (may be NULL)
|
||||
|
||||
// tool parameters
|
||||
int m_toolStyle; // see enum wxToolBarToolStyle
|
||||
wxToolBarToolStyle m_toolStyle;
|
||||
wxWindowIDRef m_id; // the tool id, wxID_SEPARATOR for separator
|
||||
wxItemKind m_kind; // for normal buttons may be wxITEM_NORMAL/CHECK/RADIO
|
||||
|
||||
@@ -234,6 +239,9 @@ protected:
|
||||
wxControl *m_control;
|
||||
};
|
||||
|
||||
// true if this tool is stretchable: currently is only value for separators
|
||||
bool m_stretchable;
|
||||
|
||||
// tool state
|
||||
bool m_toggled;
|
||||
bool m_enabled;
|
||||
@@ -362,6 +370,12 @@ public:
|
||||
virtual wxToolBarToolBase *AddSeparator();
|
||||
virtual wxToolBarToolBase *InsertSeparator(size_t pos);
|
||||
|
||||
// add a stretchable space to the toolbar: this is similar to a separator
|
||||
// except that it's always blank and that all the extra space the toolbar
|
||||
// has is [equally] distributed among the stretchable spaces in it
|
||||
virtual wxToolBarToolBase *AddStretchableSpace();
|
||||
virtual wxToolBarToolBase *InsertStretchableSpace(size_t pos);
|
||||
|
||||
// remove the tool from the toolbar: the caller is responsible for actually
|
||||
// deleting the pointer
|
||||
virtual wxToolBarToolBase *RemoveTool(int toolid);
|
||||
@@ -606,6 +620,17 @@ protected:
|
||||
virtual wxToolBarToolBase *CreateTool(wxControl *control,
|
||||
const wxString& label) = 0;
|
||||
|
||||
// this one is not virtual but just a simple helper/wrapper around
|
||||
// CreateTool() for separators
|
||||
wxToolBarToolBase *CreateSeparator()
|
||||
{
|
||||
return CreateTool(wxID_SEPARATOR,
|
||||
wxEmptyString,
|
||||
wxNullBitmap, wxNullBitmap,
|
||||
wxITEM_SEPARATOR, NULL,
|
||||
wxEmptyString, wxEmptyString);
|
||||
}
|
||||
|
||||
// helper functions
|
||||
// ----------------
|
||||
|
||||
|
@@ -228,10 +228,27 @@ public:
|
||||
platform so it can be a vertical line (MSW, some versions of GTK) or
|
||||
just an empty space or something else.
|
||||
|
||||
@see AddTool(), SetToolSeparation()
|
||||
@see AddTool(), SetToolSeparation(), AddStretchableSpace()
|
||||
*/
|
||||
virtual wxToolBarToolBase* AddSeparator();
|
||||
|
||||
/**
|
||||
Adds a stretchable space to the toolbar.
|
||||
|
||||
Any space not taken up by the fixed items (all items except for
|
||||
stretchable spaces) is distributed in equal measure between the
|
||||
stretchable spaces in the toolbar. The most common use for this method
|
||||
is to add a single stretchable space before the items which should be
|
||||
right-aligned in the toolbar, but more exotic possibilities are
|
||||
possible, e.g. a stretchable space may be added in the beginning and
|
||||
the end of the toolbar to centre all toolbar items.
|
||||
|
||||
@see AddTool(), AddSeparator(), InsertStretchableSpace()
|
||||
|
||||
@since 2.9.1
|
||||
*/
|
||||
wxToolBarToolBase *AddStretchableSpace();
|
||||
|
||||
//@{
|
||||
/**
|
||||
Adds a tool to the toolbar.
|
||||
@@ -525,6 +542,17 @@ public:
|
||||
*/
|
||||
virtual wxToolBarToolBase* InsertSeparator(size_t pos);
|
||||
|
||||
/**
|
||||
Inserts a stretchable space at the given position.
|
||||
|
||||
See AddStretchableSpace() for details about stretchable spaces.
|
||||
|
||||
@see InsertTool(), InsertSeparator()
|
||||
|
||||
@since 2.9.1
|
||||
*/
|
||||
wxToolBarToolBase *InsertStretchableSpace(size_t pos);
|
||||
|
||||
//@{
|
||||
/**
|
||||
Inserts the tool with the specified attributes into the toolbar at the
|
||||
|
@@ -310,7 +310,7 @@ bool MyApp::OnInit()
|
||||
// Create the main frame window
|
||||
MyFrame* frame = new MyFrame((wxFrame *) NULL, wxID_ANY,
|
||||
wxT("wxToolBar Sample"),
|
||||
wxPoint(100, 100), wxSize(550, 300));
|
||||
wxPoint(100, 100), wxSize(650, 300));
|
||||
|
||||
frame->Show(true);
|
||||
|
||||
@@ -474,9 +474,12 @@ void MyFrame::PopulateToolbar(wxToolBarBase* toolBar)
|
||||
#endif // USE_CONTROLS_IN_TOOLBAR
|
||||
|
||||
toolBar->AddTool(wxID_SAVE, wxT("Save"), toolBarBitmaps[Tool_save], wxT("Toggle button 1"), wxITEM_CHECK);
|
||||
|
||||
toolBar->AddSeparator();
|
||||
toolBar->AddTool(wxID_COPY, wxT("Copy"), toolBarBitmaps[Tool_copy], wxT("Toggle button 2"), wxITEM_CHECK);
|
||||
toolBar->AddTool(wxID_CUT, wxT("Cut"), toolBarBitmaps[Tool_cut], wxT("Toggle/Untoggle help button"));
|
||||
toolBar->AddTool(wxID_PASTE, wxT("Paste"), toolBarBitmaps[Tool_paste], wxT("Paste"));
|
||||
toolBar->AddSeparator();
|
||||
|
||||
if ( m_useCustomDisabled )
|
||||
{
|
||||
@@ -500,7 +503,9 @@ void MyFrame::PopulateToolbar(wxToolBarBase* toolBar)
|
||||
wxT("Delete this tool. This is a very long tooltip to test whether it does the right thing when the tooltip is more than Windows can cope with."));
|
||||
}
|
||||
|
||||
toolBar->AddSeparator();
|
||||
// add a stretchable space before the "Help" button to make it
|
||||
// right-aligned
|
||||
toolBar->AddStretchableSpace();
|
||||
toolBar->AddTool(wxID_HELP, wxT("Help"), toolBarBitmaps[Tool_help], wxT("Help button"), wxITEM_CHECK);
|
||||
|
||||
if ( !m_pathBmp.empty() )
|
||||
@@ -899,14 +904,12 @@ void MyFrame::DoToggleHelp()
|
||||
|
||||
void MyFrame::OnToggleSearch(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
static const int searchPos = 3;
|
||||
|
||||
wxToolBarBase * const tb = GetToolBar();
|
||||
if ( !m_searchTool )
|
||||
{
|
||||
wxSearchCtrl * const srch = new wxSearchCtrl(tb, wxID_ANY, "needle");
|
||||
srch->SetMinSize(wxSize(80, -1));
|
||||
m_searchTool = tb->InsertControl(searchPos, srch);
|
||||
m_searchTool = tb->AddControl(srch);
|
||||
}
|
||||
else // tool already exists
|
||||
{
|
||||
@@ -919,7 +922,7 @@ void MyFrame::OnToggleSearch(wxCommandEvent& WXUNUSED(event))
|
||||
}
|
||||
else // tool exists in detached state, attach it back
|
||||
{
|
||||
tb->InsertTool(searchPos, m_searchTool);
|
||||
tb->AddTool(m_searchTool);
|
||||
win->Show();
|
||||
}
|
||||
}
|
||||
|
@@ -259,11 +259,29 @@ wxToolBarToolBase *wxToolBarBase::AddSeparator()
|
||||
|
||||
wxToolBarToolBase *wxToolBarBase::InsertSeparator(size_t pos)
|
||||
{
|
||||
return DoInsertNewTool(pos, CreateTool(wxID_SEPARATOR,
|
||||
wxEmptyString,
|
||||
wxNullBitmap, wxNullBitmap,
|
||||
wxITEM_SEPARATOR, NULL,
|
||||
wxEmptyString, wxEmptyString));
|
||||
return DoInsertNewTool(pos, CreateSeparator());
|
||||
}
|
||||
|
||||
wxToolBarToolBase *wxToolBarBase::AddStretchableSpace()
|
||||
{
|
||||
return InsertStretchableSpace(GetToolsCount());
|
||||
}
|
||||
|
||||
wxToolBarToolBase *wxToolBarBase::InsertStretchableSpace(size_t pos)
|
||||
{
|
||||
wxToolBarToolBase * const tool = CreateSeparator();
|
||||
if ( tool )
|
||||
{
|
||||
// this is a hack but we know that all the current implementations
|
||||
// don't really use the tool when it's created, they will do it
|
||||
// InsertTool() at earliest and maybe even in Realize() much later
|
||||
//
|
||||
// so we can create the tool as a plain separator and mark it as being
|
||||
// a stretchable space later
|
||||
tool->MakeStretchable();
|
||||
}
|
||||
|
||||
return DoInsertNewTool(pos, tool);
|
||||
}
|
||||
|
||||
wxToolBarToolBase *wxToolBarBase::RemoveTool(int id)
|
||||
|
@@ -519,6 +519,15 @@ bool wxToolBar::DoInsertTool(size_t pos, wxToolBarToolBase *toolBase)
|
||||
|
||||
case wxTOOL_STYLE_SEPARATOR:
|
||||
tool->m_item = gtk_separator_tool_item_new();
|
||||
if ( tool->IsStretchable() )
|
||||
{
|
||||
gtk_separator_tool_item_set_draw
|
||||
(
|
||||
GTK_SEPARATOR_TOOL_ITEM(tool->m_item),
|
||||
FALSE
|
||||
);
|
||||
gtk_tool_item_set_expand(tool->m_item, TRUE);
|
||||
}
|
||||
gtk_toolbar_insert(m_toolbar, tool->m_item, int(pos));
|
||||
break;
|
||||
|
||||
|
@@ -149,7 +149,7 @@ public:
|
||||
clientData, shortHelp, longHelp)
|
||||
{
|
||||
m_nSepCount = 0;
|
||||
m_staticText = 0;
|
||||
m_staticText = NULL;
|
||||
}
|
||||
|
||||
wxToolBarTool(wxToolBar *tbar, wxControl *control, const wxString& label)
|
||||
@@ -210,6 +210,29 @@ public:
|
||||
void SetSeparatorsCount(size_t count) { m_nSepCount = count; }
|
||||
size_t GetSeparatorsCount() const { return m_nSepCount; }
|
||||
|
||||
// we need ids for the spacers which we want to modify later on, this
|
||||
// function will allocate a valid/unique id for a spacer if not done yet
|
||||
void AllocSpacerId()
|
||||
{
|
||||
if ( m_id == wxID_SEPARATOR )
|
||||
m_id = wxWindow::NewControlId();
|
||||
}
|
||||
|
||||
// this method is used for controls only and offsets the control by the
|
||||
// given amount (in pixels) in horizontal direction
|
||||
void MoveBy(int offset)
|
||||
{
|
||||
wxControl * const control = GetControl();
|
||||
|
||||
control->Move(control->GetPosition().x + offset, wxDefaultCoord);
|
||||
|
||||
if ( m_staticText )
|
||||
{
|
||||
m_staticText->Move(m_staticText->GetPosition().x + offset,
|
||||
wxDefaultCoord);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_nSepCount;
|
||||
wxStaticText *m_staticText;
|
||||
@@ -281,6 +304,7 @@ void wxToolBar::Init()
|
||||
m_disabledImgList = NULL;
|
||||
|
||||
m_nButtons = 0;
|
||||
m_totalFixedSize = 0;
|
||||
|
||||
// even though modern Windows applications typically use 24*24 (or even
|
||||
// 32*32) size for their bitmaps, the native control itself still uses the
|
||||
@@ -582,15 +606,7 @@ bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool)
|
||||
wxToolBarTool *tool2 = (wxToolBarTool*)node->GetData();
|
||||
if ( tool2->IsControl() )
|
||||
{
|
||||
wxControl * const control = tool2->GetControl();
|
||||
|
||||
int x;
|
||||
control->GetPosition(&x, NULL);
|
||||
control->Move(x - width, wxDefaultCoord);
|
||||
|
||||
wxStaticText * const staticText = tool2->GetStaticText();
|
||||
if ( staticText )
|
||||
staticText->Move(x - width, wxDefaultCoord);
|
||||
tool2->MoveBy(-width);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -900,7 +916,7 @@ bool wxToolBar::Realize()
|
||||
int i = 0;
|
||||
for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
wxToolBarToolBase *tool = node->GetData();
|
||||
wxToolBarTool *tool = static_cast<wxToolBarTool *>(node->GetData());
|
||||
|
||||
// don't add separators to the vertical toolbar with old comctl32.dll
|
||||
// versions as they didn't handle this properly
|
||||
@@ -918,10 +934,16 @@ bool wxToolBar::Realize()
|
||||
switch ( tool->GetStyle() )
|
||||
{
|
||||
case wxTOOL_STYLE_CONTROL:
|
||||
button.idCommand = tool->GetId();
|
||||
// fall through: create just a separator too
|
||||
|
||||
case wxTOOL_STYLE_SEPARATOR:
|
||||
if ( tool->IsStretchableSpace() )
|
||||
{
|
||||
// we're going to modify the size of this button later and
|
||||
// so we need a valid id for it and not wxID_SEPARATOR
|
||||
// which is used by spacers by default
|
||||
tool->AllocSpacerId();
|
||||
}
|
||||
|
||||
button.idCommand = tool->GetId();
|
||||
button.fsState = TBSTATE_ENABLED;
|
||||
button.fsStyle = TBSTYLE_SEP;
|
||||
break;
|
||||
@@ -1017,33 +1039,38 @@ bool wxToolBar::Realize()
|
||||
}
|
||||
|
||||
|
||||
// Deal with the controls finally
|
||||
// ------------------------------
|
||||
// Adjust controls and stretchable spaces
|
||||
// --------------------------------------
|
||||
|
||||
// adjust the controls size to fit nicely in the toolbar
|
||||
int y = 0;
|
||||
size_t index = 0;
|
||||
for ( node = m_tools.GetFirst(); node; node = node->GetNext(), index++ )
|
||||
// adjust the controls size to fit nicely in the toolbar and compute its
|
||||
// total size while doing it
|
||||
m_totalFixedSize = 0;
|
||||
int toolIndex = 0;
|
||||
for ( node = m_tools.GetFirst(); node; node = node->GetNext(), toolIndex++ )
|
||||
{
|
||||
wxToolBarTool *tool = (wxToolBarTool*)node->GetData();
|
||||
wxToolBarTool * const tool = (wxToolBarTool*)node->GetData();
|
||||
|
||||
// we calculate the running y coord for vertical toolbars so we need to
|
||||
// get the items size for all items but for the horizontal ones we
|
||||
// don't need to deal with the non controls
|
||||
bool isControl = tool->IsControl();
|
||||
if ( !isControl && !IsVertical() )
|
||||
continue;
|
||||
const RECT r = wxGetTBItemRect(GetHwnd(), toolIndex);
|
||||
|
||||
const RECT r = wxGetTBItemRect(GetHwnd(), index);
|
||||
if ( !isControl )
|
||||
if ( !tool->IsControl() )
|
||||
{
|
||||
// can only be control if isVertical
|
||||
y += r.bottom - r.top;
|
||||
if ( IsVertical() )
|
||||
m_totalFixedSize += r.bottom - r.top;
|
||||
else
|
||||
m_totalFixedSize += r.right - r.left;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
wxControl *control = tool->GetControl();
|
||||
if ( IsVertical() )
|
||||
{
|
||||
// don't embed controls in the vertical toolbar, this doesn't look
|
||||
// good and wxGTK doesn't do it neither (and the code below can't
|
||||
// deal with this case)
|
||||
continue;
|
||||
}
|
||||
|
||||
wxControl * const control = tool->GetControl();
|
||||
wxStaticText * const staticText = tool->GetStaticText();
|
||||
|
||||
wxSize size = control->GetSize();
|
||||
@@ -1054,9 +1081,6 @@ bool wxToolBar::Realize()
|
||||
staticTextSize.y += 3; // margin between control and its label
|
||||
}
|
||||
|
||||
// the position of the leftmost controls corner
|
||||
int left = wxDefaultCoord;
|
||||
|
||||
// TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+
|
||||
#ifdef TB_SETBUTTONINFO
|
||||
// available in headers, now check whether it is available now
|
||||
@@ -1082,7 +1106,6 @@ bool wxToolBar::Realize()
|
||||
{
|
||||
// try adding several separators to fit the controls width
|
||||
int widthSep = r.right - r.left;
|
||||
left = r.left;
|
||||
|
||||
TBBUTTON tbb;
|
||||
wxZeroMemory(tbb);
|
||||
@@ -1094,17 +1117,17 @@ bool wxToolBar::Realize()
|
||||
for ( size_t nSep = 0; nSep < nSeparators; nSep++ )
|
||||
{
|
||||
if ( !::SendMessage(GetHwnd(), TB_INSERTBUTTON,
|
||||
index, (LPARAM)&tbb) )
|
||||
toolIndex, (LPARAM)&tbb) )
|
||||
{
|
||||
wxLogLastError(wxT("TB_INSERTBUTTON"));
|
||||
}
|
||||
|
||||
index++;
|
||||
toolIndex++;
|
||||
}
|
||||
|
||||
// remember the number of separators we used - we'd have to
|
||||
// delete all of them later
|
||||
((wxToolBarTool *)tool)->SetSeparatorsCount(nSeparators);
|
||||
tool->SetSeparatorsCount(nSeparators);
|
||||
|
||||
// adjust the controls width to exactly cover the separators
|
||||
size.x = (nSeparators + 1)*widthSep;
|
||||
@@ -1139,33 +1162,19 @@ bool wxToolBar::Realize()
|
||||
staticText->Show();
|
||||
}
|
||||
|
||||
int top;
|
||||
if ( IsVertical() )
|
||||
{
|
||||
left = 0;
|
||||
top = y;
|
||||
|
||||
y += height + 2 * GetMargins().y;
|
||||
}
|
||||
else // horizontal toolbar
|
||||
{
|
||||
if ( left == wxDefaultCoord )
|
||||
left = r.left;
|
||||
|
||||
top = r.top;
|
||||
}
|
||||
|
||||
control->Move(left, top + (diff + 1) / 2);
|
||||
control->Move(r.left, r.top + (diff + 1) / 2);
|
||||
if ( staticText )
|
||||
{
|
||||
staticText->Move(left + (size.x - staticTextSize.x)/2,
|
||||
staticText->Move(r.left + (size.x - staticTextSize.x)/2,
|
||||
r.bottom - staticTextSize.y);
|
||||
}
|
||||
|
||||
m_totalFixedSize += size.x;
|
||||
}
|
||||
|
||||
// the max index is the "real" number of buttons - i.e. counting even the
|
||||
// separators which we added just for aligning the controls
|
||||
m_nButtons = index;
|
||||
m_nButtons = toolIndex;
|
||||
|
||||
if ( !IsVertical() )
|
||||
{
|
||||
@@ -1186,6 +1195,77 @@ bool wxToolBar::Realize()
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxToolBar::UpdateStretchableSpacersSize()
|
||||
{
|
||||
// we can't resize the spacers if TB_SETBUTTONINFO is not supported
|
||||
if ( wxApp::GetComCtl32Version() < 471 )
|
||||
return;
|
||||
|
||||
// check if we have any stretchable spacers in the first place
|
||||
unsigned numSpaces = 0;
|
||||
wxToolBarToolsList::compatibility_iterator node;
|
||||
for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
wxToolBarTool * const tool = (wxToolBarTool*)node->GetData();
|
||||
if ( tool->IsStretchableSpace() )
|
||||
numSpaces++;
|
||||
}
|
||||
|
||||
if ( !numSpaces )
|
||||
return;
|
||||
|
||||
// we do, adjust their size: either distribute the extra size among them or
|
||||
// reduce their size if there is not enough place for all tools
|
||||
const int totalSize = IsVertical() ? GetClientSize().y : GetClientSize().x;
|
||||
const int extraSize = totalSize - m_totalFixedSize;
|
||||
const int sizeSpacer = extraSize > 0 ? extraSize / numSpaces : 0;
|
||||
|
||||
// the last spacer should consume all remaining space if we have too much
|
||||
// of it (which can be greater than sizeSpacer because of the rounding)
|
||||
const int sizeLastSpacer = extraSize > 0
|
||||
? extraSize - (numSpaces - 1)*sizeSpacer
|
||||
: 0;
|
||||
|
||||
// cumulated offset by which we need to move all the following controls to
|
||||
// the right: while the toolbar takes care of the normal items, we must
|
||||
// move the controls manually ourselves to ensure they remain at the
|
||||
// correct place
|
||||
int offset = 0;
|
||||
int toolIndex = 0;
|
||||
for ( node = m_tools.GetFirst(); node; node = node->GetNext(), toolIndex++ )
|
||||
{
|
||||
wxToolBarTool * const tool = (wxToolBarTool*)node->GetData();
|
||||
|
||||
if ( tool->IsControl() && offset )
|
||||
{
|
||||
tool->MoveBy(offset);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !tool->IsStretchableSpace() )
|
||||
continue;
|
||||
|
||||
const RECT rcOld = wxGetTBItemRect(GetHwnd(), toolIndex);
|
||||
|
||||
WinStruct<TBBUTTONINFO> tbbi;
|
||||
tbbi.dwMask = TBIF_SIZE;
|
||||
tbbi.cx = --numSpaces ? sizeSpacer : sizeLastSpacer;
|
||||
|
||||
if ( !::SendMessage(GetHwnd(), TB_SETBUTTONINFO,
|
||||
tool->GetId(), (LPARAM)&tbbi) )
|
||||
{
|
||||
wxLogLastError(wxT("TB_SETBUTTONINFO"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// we successfully resized this one, move all the controls after it
|
||||
// by the corresponding amount (may be positive or negative)
|
||||
offset += tbbi.cx - (rcOld.right - rcOld.left);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// message handlers
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -1576,12 +1656,7 @@ void wxToolBar::OnEraseBackground(wxEraseEvent& event)
|
||||
RECT rect = wxGetClientRect(GetHwnd());
|
||||
|
||||
wxDC *dc = event.GetDC();
|
||||
if (!dc) return;
|
||||
wxMSWDCImpl *impl = (wxMSWDCImpl*) dc->GetImpl();
|
||||
HDC hdc = GetHdcOf(*impl);
|
||||
|
||||
int majorVersion, minorVersion;
|
||||
wxGetOsVersion(& majorVersion, & minorVersion);
|
||||
HDC hdc = GetHdcOf(*dc);
|
||||
|
||||
#if wxUSE_UXTHEME
|
||||
// we may need to draw themed colour so that we appear correctly on
|
||||
@@ -1606,36 +1681,13 @@ void wxToolBar::OnEraseBackground(wxEraseEvent& event)
|
||||
}
|
||||
}
|
||||
|
||||
// Only draw a rebar theme on Vista, since it doesn't jive so well with XP
|
||||
if ( !UseBgCol() && majorVersion >= 6 )
|
||||
{
|
||||
wxUxThemeEngine *theme = wxUxThemeEngine::GetIfActive();
|
||||
if ( theme )
|
||||
{
|
||||
wxUxThemeHandle hTheme(this, L"REBAR");
|
||||
|
||||
RECT r;
|
||||
wxRect rect = GetClientRect();
|
||||
wxCopyRectToRECT(rect, r);
|
||||
|
||||
HRESULT hr = theme->DrawThemeBackground(hTheme, hdc, 0, 0, & r, NULL);
|
||||
if ( hr == S_OK )
|
||||
if ( MSWEraseRect(*dc) )
|
||||
return;
|
||||
|
||||
// it can also return S_FALSE which seems to simply say that it
|
||||
// didn't draw anything but no error really occurred
|
||||
if ( FAILED(hr) )
|
||||
{
|
||||
wxLogApiError(wxT("DrawThemeParentBackground(toolbar)"), hr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_UXTHEME
|
||||
|
||||
// we need to always draw our background under XP, as otherwise it doesn't
|
||||
// appear correctly with some themes (e.g. Zune one)
|
||||
if ( majorVersion == 5 ||
|
||||
if ( wxGetWinVersion() == wxWinVersion_XP ||
|
||||
UseBgCol() || (GetMSWToolbarStyle() & TBSTYLE_TRANSPARENT) )
|
||||
{
|
||||
// do draw our background
|
||||
@@ -1648,7 +1700,7 @@ void wxToolBar::OnEraseBackground(wxEraseEvent& event)
|
||||
wxCHANGE_HDC_MAP_MODE(hdc, MM_TEXT);
|
||||
::FillRect(hdc, &rect, hBrush);
|
||||
}
|
||||
else // we have no non default background colour
|
||||
else // we have no non-default background colour
|
||||
{
|
||||
// let the system do it for us
|
||||
event.Skip();
|
||||
@@ -1699,45 +1751,100 @@ bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
|
||||
SetSize(w, h);
|
||||
}
|
||||
|
||||
UpdateStretchableSpacersSize();
|
||||
|
||||
// message processed
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef __WXWINCE__
|
||||
|
||||
bool wxToolBar::MSWEraseRect(wxDC& dc, const wxRect *rectItem)
|
||||
{
|
||||
// erase the given rectangle to hide the separator
|
||||
#if wxUSE_UXTHEME
|
||||
// themed background doesn't look well under XP so only draw it for Vista
|
||||
// and later
|
||||
if ( !UseBgCol() && wxGetWinVersion() >= wxWinVersion_Vista )
|
||||
{
|
||||
wxUxThemeEngine *theme = wxUxThemeEngine::GetIfActive();
|
||||
if ( theme )
|
||||
{
|
||||
wxUxThemeHandle hTheme(this, L"REBAR");
|
||||
|
||||
// Draw the whole background since the pattern may be position
|
||||
// sensitive; but clip it to the area of interest.
|
||||
RECT rcTotal;
|
||||
wxCopyRectToRECT(GetClientSize(), rcTotal);
|
||||
|
||||
RECT rcItem;
|
||||
if ( rectItem )
|
||||
wxCopyRectToRECT(*rectItem, rcItem);
|
||||
|
||||
HRESULT hr = theme->DrawThemeBackground
|
||||
(
|
||||
hTheme,
|
||||
GetHdcOf(dc),
|
||||
0, 0,
|
||||
&rcTotal,
|
||||
rectItem ? &rcItem : NULL
|
||||
);
|
||||
if ( hr == S_OK )
|
||||
return true;
|
||||
|
||||
// it can also return S_FALSE which seems to simply say that it
|
||||
// didn't draw anything but no error really occurred
|
||||
if ( FAILED(hr) )
|
||||
{
|
||||
wxLogApiError(wxT("DrawThemeBackground(toolbar)"), hr);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // wxUSE_UXTHEME
|
||||
|
||||
// this is a bit peculiar but we may simply do nothing here if no rectItem
|
||||
// is specified (and hence we need to erase everything) as this only
|
||||
// happens when we're called from OnEraseBackground() and in this case we
|
||||
// may simply return false to let the systems default background erasing to
|
||||
// take place
|
||||
if ( rectItem )
|
||||
dc.DrawRectangle(*rectItem);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam)
|
||||
{
|
||||
// erase any dummy separators which were used
|
||||
// for aligning the controls if any here
|
||||
// erase any dummy separators which were used only for reserving space in
|
||||
// the toolbar (either for a control or just for a stretchable space)
|
||||
|
||||
// first of all, are there any controls at all?
|
||||
wxToolBarToolsList::compatibility_iterator node;
|
||||
for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
|
||||
{
|
||||
if ( node->GetData()->IsControl() )
|
||||
wxToolBarToolBase * const tool = node->GetData();
|
||||
if ( tool->IsControl() || tool->IsStretchableSpace() )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !node )
|
||||
{
|
||||
// no controls, nothing to erase
|
||||
return false;
|
||||
|
||||
wxSize clientSize = GetClientSize();
|
||||
int majorVersion, minorVersion;
|
||||
wxGetOsVersion(& majorVersion, & minorVersion);
|
||||
}
|
||||
|
||||
// prepare the DC on which we'll be drawing
|
||||
wxClientDC dc(this);
|
||||
dc.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID));
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
|
||||
RECT r;
|
||||
if ( !::GetUpdateRect(GetHwnd(), &r, FALSE) )
|
||||
RECT rcUpdate;
|
||||
if ( !::GetUpdateRect(GetHwnd(), &rcUpdate, FALSE) )
|
||||
{
|
||||
// nothing to redraw anyhow
|
||||
return false;
|
||||
}
|
||||
|
||||
wxRect rectUpdate;
|
||||
wxCopyRECTToRect(r, rectUpdate);
|
||||
|
||||
const wxRect rectUpdate = wxRectFromRECT(rcUpdate);
|
||||
dc.SetClippingRegion(rectUpdate);
|
||||
|
||||
// draw the toolbar tools, separators &c normally
|
||||
@@ -1749,7 +1856,8 @@ bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam)
|
||||
// NB: this is really the only way to do it as we don't know if a separator
|
||||
// corresponds to a control (i.e. is a dummy one) or a real one
|
||||
// otherwise
|
||||
for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
|
||||
int toolIndex = 0;
|
||||
for ( node = m_tools.GetFirst(); node; node = node->GetNext(), toolIndex++ )
|
||||
{
|
||||
wxToolBarTool *tool = (wxToolBarTool*)node->GetData();
|
||||
if ( tool->IsControl() )
|
||||
@@ -1758,13 +1866,16 @@ bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam)
|
||||
wxControl *control = tool->GetControl();
|
||||
wxStaticText *staticText = tool->GetStaticText();
|
||||
wxRect rectCtrl = control->GetRect();
|
||||
wxRect rectStaticText(0,0,0,0);
|
||||
wxRect rectStaticText;
|
||||
if ( staticText )
|
||||
{
|
||||
rectStaticText = staticText->GetRect();
|
||||
}
|
||||
|
||||
// iterate over all buttons
|
||||
if ( !rectCtrl.Intersects(rectUpdate) &&
|
||||
(!staticText || !rectStaticText.Intersects(rectUpdate)) )
|
||||
continue;
|
||||
|
||||
// iterate over all buttons to find all separators intersecting
|
||||
// this control
|
||||
TBBUTTON tbb;
|
||||
int count = ::SendMessage(GetHwnd(), TB_BUTTONCOUNT, 0, 0);
|
||||
for ( int n = 0; n < count; n++ )
|
||||
@@ -1786,62 +1897,33 @@ bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam)
|
||||
if ( !r.right )
|
||||
continue;
|
||||
|
||||
// does it intersect the control?
|
||||
wxRect rectItem;
|
||||
wxCopyRECTToRect(r, rectItem);
|
||||
if ( rectCtrl.Intersects(rectItem) || (staticText && rectStaticText.Intersects(rectItem)))
|
||||
{
|
||||
// yes, do erase it!
|
||||
const wxRect rectItem = wxRectFromRECT(r);
|
||||
|
||||
bool haveRefreshed = false;
|
||||
|
||||
#if wxUSE_UXTHEME
|
||||
if ( !UseBgCol() && !GetParent()->UseBgCol() )
|
||||
{
|
||||
// Don't use DrawThemeBackground
|
||||
}
|
||||
else if ( !UseBgCol() && majorVersion >= 6 )
|
||||
{
|
||||
wxUxThemeEngine *theme = wxUxThemeEngine::GetIfActive();
|
||||
if ( theme )
|
||||
{
|
||||
wxUxThemeHandle hTheme(this, L"REBAR");
|
||||
|
||||
RECT clipRect = r;
|
||||
|
||||
// Draw the whole background since the pattern may be position sensitive;
|
||||
// but clip it to the area of interest.
|
||||
r.left = 0;
|
||||
r.right = clientSize.x;
|
||||
r.top = 0;
|
||||
r.bottom = clientSize.y;
|
||||
|
||||
wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
|
||||
HRESULT hr = theme->DrawThemeBackground(hTheme, GetHdcOf(*impl), 0, 0, & r, & clipRect);
|
||||
if ( hr == S_OK )
|
||||
haveRefreshed = true;
|
||||
}
|
||||
}
|
||||
#endif // wxUSE_UXTHEME
|
||||
|
||||
if (!haveRefreshed)
|
||||
dc.DrawRectangle(rectItem);
|
||||
}
|
||||
// does it intersect the update region at all?
|
||||
if ( !rectUpdate.Intersects(rectItem) )
|
||||
continue;
|
||||
|
||||
// does it intersect the control itself or its label?
|
||||
//
|
||||
// if it does, refresh it so it's redrawn on top of the
|
||||
// background
|
||||
if ( rectCtrl.Intersects(rectItem) )
|
||||
{
|
||||
// Necessary in case we use a no-paint-on-size
|
||||
// style in the parent: the controls can disappear
|
||||
control->Refresh(false);
|
||||
}
|
||||
|
||||
if ( staticText && rectStaticText.Intersects(rectItem) )
|
||||
{
|
||||
// Necessary in case we use a no-paint-on-size
|
||||
// style in the parent: the controls can disappear
|
||||
else if ( staticText && rectStaticText.Intersects(rectItem) )
|
||||
staticText->Refresh(false);
|
||||
else
|
||||
continue;
|
||||
|
||||
MSWEraseRect(dc, &rectItem);
|
||||
}
|
||||
}
|
||||
else if ( tool->IsStretchableSpace() )
|
||||
{
|
||||
const wxRect
|
||||
rectItem = wxRectFromRECT(wxGetTBItemRect(GetHwnd(), toolIndex));
|
||||
|
||||
if ( rectUpdate.Intersects(rectItem) )
|
||||
MSWEraseRect(dc, &rectItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -960,16 +960,21 @@ bool wxToolBar::Realize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxCFStringRef cfidentifier;
|
||||
const NSString *nsItemId;
|
||||
if (tool->GetStyle() == wxTOOL_STYLE_SEPARATOR)
|
||||
[refTB insertItemWithItemIdentifier:NSToolbarSeparatorItemIdentifier atIndex:currentPosition];
|
||||
{
|
||||
nsItemId = tool->IsStretchable() ? NSToolbarFlexibleSpaceItemIdentifier
|
||||
: NSToolbarSeparatorItemIdentifier;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
wxString identifier = wxString::Format( wxT("%ld"), (long) tool );
|
||||
wxCFStringRef cfidentifier(identifier);
|
||||
|
||||
[refTB insertItemWithItemIdentifier:cfidentifier.AsNSString() atIndex:currentPosition];
|
||||
cfidentifier = wxCFStringRef(wxString::Format("%ld", (long)tool));
|
||||
nsItemId = cfidentifier.AsNSString();
|
||||
}
|
||||
|
||||
[refTB insertItemWithItemIdentifier:nsItemId atIndex:currentPosition];
|
||||
tool->SetIndex( currentPosition );
|
||||
}
|
||||
|
||||
@@ -1220,7 +1225,10 @@ bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase)
|
||||
#if wxOSX_USE_NATIVE_TOOLBAR
|
||||
if (m_macToolbar != NULL)
|
||||
{
|
||||
NSToolbarItem* item = [[NSToolbarItem alloc] initWithItemIdentifier:NSToolbarSeparatorItemIdentifier];
|
||||
const NSString * const
|
||||
nsItemId = tool->IsStretchable() ? NSToolbarFlexibleSpaceItemIdentifier
|
||||
: NSToolbarSeparatorItemIdentifier;
|
||||
NSToolbarItem* item = [[NSToolbarItem alloc] initWithItemIdentifier:nsItemId];
|
||||
tool->SetToolbarItemRef( item );
|
||||
}
|
||||
#endif // wxOSX_USE_NATIVE_TOOLBAR
|
||||
|
Reference in New Issue
Block a user