1 /////////////////////////////////////////////////////////////////////////////// 2 // Name: wx/compositewin.h 3 // Purpose: wxCompositeWindow<> declaration 4 // Author: Vadim Zeitlin 5 // Created: 2011-01-02 6 // Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org> 7 // Licence: wxWindows licence 8 /////////////////////////////////////////////////////////////////////////////// 9 10 #ifndef _WX_COMPOSITEWIN_H_ 11 #define _WX_COMPOSITEWIN_H_ 12 13 #include "wx/window.h" 14 #include "wx/containr.h" 15 16 class WXDLLIMPEXP_FWD_CORE wxToolTip; 17 18 // NB: This is an experimental and, as for now, undocumented class used only by 19 // wxWidgets itself internally. Don't use it in your code until its API is 20 // officially stabilized unless you are ready to change it with the next 21 // wxWidgets release. 22 23 // ---------------------------------------------------------------------------- 24 // wxCompositeWindow is a helper for implementing composite windows: to define 25 // a class using subwindows, simply inherit from it specialized with the real 26 // base class name and implement GetCompositeWindowParts() pure virtual method. 27 // ---------------------------------------------------------------------------- 28 29 // This is the base class of wxCompositeWindow which takes care of propagating 30 // colours, fonts etc changes to all the children, but doesn't bother with 31 // handling their events or focus. There should be rarely any need to use it 32 // rather than the full wxCompositeWindow. 33 34 // The template parameter W must be a wxWindow-derived class. 35 template <class W> 36 class wxCompositeWindowSettersOnly : public W 37 { 38 public: 39 typedef W BaseWindowClass; 40 41 // Override all wxWindow methods which must be forwarded to the composite 42 // window parts. 43 44 // Attribute setters group. 45 // 46 // NB: Unfortunately we can't factor out the call for the setter itself 47 // into DoSetForAllParts() because we can't call the function passed to 48 // it non-virtually and we need to do this to avoid infinite recursion, 49 // so we work around this by calling the method of this object itself 50 // manually in each function. SetForegroundColour(const wxColour & colour)51 virtual bool SetForegroundColour(const wxColour& colour) wxOVERRIDE 52 { 53 if ( !BaseWindowClass::SetForegroundColour(colour) ) 54 return false; 55 56 SetForAllParts(&wxWindowBase::SetForegroundColour, colour); 57 58 return true; 59 } 60 SetBackgroundColour(const wxColour & colour)61 virtual bool SetBackgroundColour(const wxColour& colour) wxOVERRIDE 62 { 63 if ( !BaseWindowClass::SetBackgroundColour(colour) ) 64 return false; 65 66 SetForAllParts(&wxWindowBase::SetBackgroundColour, colour); 67 68 return true; 69 } 70 SetFont(const wxFont & font)71 virtual bool SetFont(const wxFont& font) wxOVERRIDE 72 { 73 if ( !BaseWindowClass::SetFont(font) ) 74 return false; 75 76 SetForAllParts(&wxWindowBase::SetFont, font); 77 78 return true; 79 } 80 SetCursor(const wxCursor & cursor)81 virtual bool SetCursor(const wxCursor& cursor) wxOVERRIDE 82 { 83 if ( !BaseWindowClass::SetCursor(cursor) ) 84 return false; 85 86 SetForAllParts(&wxWindowBase::SetCursor, cursor); 87 88 return true; 89 } 90 SetLayoutDirection(wxLayoutDirection dir)91 virtual void SetLayoutDirection(wxLayoutDirection dir) wxOVERRIDE 92 { 93 BaseWindowClass::SetLayoutDirection(dir); 94 95 SetForAllParts(&wxWindowBase::SetLayoutDirection, dir); 96 97 // The child layout almost invariably depends on the layout direction, 98 // so redo it when it changes. 99 // 100 // However avoid doing it when we're called from wxWindow::Create() in 101 // wxGTK as the derived window is not fully created yet and calling its 102 // SetSize() may be unexpected. This does mean that any future calls to 103 // SetLayoutDirection(wxLayout_Default) wouldn't result in a re-layout 104 // neither, but then we're not supposed to be called with it at all. 105 if ( dir != wxLayout_Default ) 106 this->SetSize(-1, -1, -1, -1, wxSIZE_FORCE); 107 } 108 109 #if wxUSE_TOOLTIPS DoSetToolTipText(const wxString & tip)110 virtual void DoSetToolTipText(const wxString &tip) wxOVERRIDE 111 { 112 BaseWindowClass::DoSetToolTipText(tip); 113 114 // Use a variable to disambiguate between SetToolTip() overloads. 115 void (wxWindowBase::*func)(const wxString&) = &wxWindowBase::SetToolTip; 116 117 SetForAllParts(func, tip); 118 } 119 DoSetToolTip(wxToolTip * tip)120 virtual void DoSetToolTip(wxToolTip *tip) wxOVERRIDE 121 { 122 BaseWindowClass::DoSetToolTip(tip); 123 124 SetForAllParts(&wxWindowBase::CopyToolTip, tip); 125 } 126 #endif // wxUSE_TOOLTIPS 127 128 protected: 129 // Trivial but necessary default ctor. wxCompositeWindowSettersOnly()130 wxCompositeWindowSettersOnly() 131 { 132 } 133 134 private: 135 // Must be implemented by the derived class to return all children to which 136 // the public methods we override should forward to. 137 virtual wxWindowList GetCompositeWindowParts() const = 0; 138 139 template <class T, class TArg, class R> SetForAllParts(R (wxWindowBase::* func)(TArg),T arg)140 void SetForAllParts(R (wxWindowBase::*func)(TArg), T arg) 141 { 142 // Simply call the setters for all parts of this composite window. 143 const wxWindowList parts = GetCompositeWindowParts(); 144 for ( wxWindowList::const_iterator i = parts.begin(); 145 i != parts.end(); 146 ++i ) 147 { 148 wxWindow * const child = *i; 149 150 // Allow NULL elements in the list, this makes the code of derived 151 // composite controls which may have optionally shown children 152 // simpler and it doesn't cost us much here. 153 if ( child ) 154 (child->*func)(arg); 155 } 156 } 157 158 wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxCompositeWindowSettersOnly, W); 159 }; 160 161 // The real wxCompositeWindow itself, inheriting all the setters defined above. 162 template <class W> 163 class wxCompositeWindow : public wxCompositeWindowSettersOnly<W> 164 { 165 public: SetFocus()166 virtual void SetFocus() wxOVERRIDE 167 { 168 wxSetFocusToChild(this, NULL); 169 } 170 171 protected: 172 // Default ctor sets things up for handling children events correctly. wxCompositeWindow()173 wxCompositeWindow() 174 { 175 this->Bind(wxEVT_CREATE, &wxCompositeWindow::OnWindowCreate, this); 176 } 177 178 private: OnWindowCreate(wxWindowCreateEvent & event)179 void OnWindowCreate(wxWindowCreateEvent& event) 180 { 181 event.Skip(); 182 183 // Attach a few event handlers to all parts of the composite window. 184 // This makes the composite window behave more like a simple control 185 // and allows other code (such as wxDataViewCtrl's inline editing 186 // support) to hook into its event processing. 187 188 wxWindow *child = event.GetWindow(); 189 190 // Check that it's one of our children: it could also be this window 191 // itself (for which we don't need to handle focus at all) or one of 192 // its grandchildren and we don't want to bind to those as child 193 // controls are supposed to be well-behaved and get their own focus 194 // event if any of their children get focus anyhow, so binding to them 195 // would only result in duplicate events. 196 // 197 // Notice that we can't use GetCompositeWindowParts() here because the 198 // member variables that are typically used in its implementation in 199 // the derived classes would typically not be initialized yet, as this 200 // event is generated by "m_child = new wxChildControl(this, ...)" code 201 // before "m_child" is assigned. 202 if ( child->GetParent() != this ) 203 return; 204 205 child->Bind(wxEVT_SET_FOCUS, &wxCompositeWindow::OnSetFocus, this); 206 207 child->Bind(wxEVT_KILL_FOCUS, &wxCompositeWindow::OnKillFocus, this); 208 209 // Some events should be only handled for non-toplevel children. For 210 // example, we want to close the control in wxDataViewCtrl when Enter 211 // is pressed in the inline editor, but not when it's pressed in a 212 // popup dialog it opens. 213 wxWindow *win = child; 214 while ( win && win != this ) 215 { 216 if ( win->IsTopLevel() ) 217 return; 218 win = win->GetParent(); 219 } 220 221 child->Bind(wxEVT_CHAR, &wxCompositeWindow::OnChar, this); 222 } 223 OnChar(wxKeyEvent & event)224 void OnChar(wxKeyEvent& event) 225 { 226 if ( !this->ProcessWindowEvent(event) ) 227 event.Skip(); 228 } 229 OnSetFocus(wxFocusEvent & event)230 void OnSetFocus(wxFocusEvent& event) 231 { 232 event.Skip(); 233 234 // When a child of a composite window gains focus, the entire composite 235 // focus gains focus as well -- unless it had it already. 236 // 237 // We suppose that we hadn't had focus if the event doesn't carry the 238 // previously focused window as it normally means that it comes from 239 // outside of this program. 240 wxWindow* const oldFocus = event.GetWindow(); 241 if ( !oldFocus || oldFocus->GetMainWindowOfCompositeControl() != this ) 242 { 243 wxFocusEvent eventThis(wxEVT_SET_FOCUS, this->GetId()); 244 eventThis.SetEventObject(this); 245 eventThis.SetWindow(event.GetWindow()); 246 247 this->ProcessWindowEvent(eventThis); 248 } 249 } 250 OnKillFocus(wxFocusEvent & event)251 void OnKillFocus(wxFocusEvent& event) 252 { 253 // Ignore focus changes within the composite control: 254 wxWindow *win = event.GetWindow(); 255 while ( win ) 256 { 257 if ( win == this ) 258 { 259 event.Skip(); 260 return; 261 } 262 263 // Note that we don't use IsTopLevel() check here, because we do 264 // want to ignore focus changes going to toplevel window that have 265 // the composite control as its parent; these would typically be 266 // some kind of control's popup window. 267 win = win->GetParent(); 268 } 269 270 // The event shouldn't be ignored, forward it to the main control: 271 if ( !this->ProcessWindowEvent(event) ) 272 event.Skip(); 273 } 274 275 wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxCompositeWindow, W); 276 }; 277 278 #endif // _WX_COMPOSITEWIN_H_ 279