]> git.saurik.com Git - wxWidgets.git/commitdiff
add wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK and semi-automatic header resizing support
authorVadim Zeitlin <vadim@wxwidgets.org>
Mon, 8 Dec 2008 12:15:17 +0000 (12:15 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Mon, 8 Dec 2008 12:15:17 +0000 (12:15 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57186 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/generic/headerctrlg.h
include/wx/headerctrl.h
include/wx/msw/headerctrl.h
interface/wx/headerctrl.h
src/common/headerctrlcmn.cpp
src/generic/datavgen.cpp
src/generic/headerctrlg.cpp
src/msw/headerctrl.cpp

index 2bbe5efc8f62cfe28cfbf93b26c94976eaf4a538..7c86e97730d2a9c50790789e56b5621bd6320a32 100644 (file)
@@ -68,9 +68,12 @@ private:
     // return the horizontal start position of the given column
     int GetColStart(unsigned int idx) const;
 
-    // refresh the given column [only]
+    // refresh the given column [only]; idx must be valid
     void RefreshCol(unsigned int idx);
 
+    // refresh the given column if idx is valid
+    void RefreshColIfNotNone(unsigned int idx);
+
     // refresh all the controls starting from (and including) the given one
     void RefreshColsAfter(unsigned int idx);
 
index 170cf641db58ad5d46dceebce90aa163c752a245..f7f8dda827e3432cfd1a0ba1399f06da78a1d07a 100644 (file)
@@ -20,6 +20,7 @@
 // notice that the classes in this header are defined in the core library even
 // although currently they're only used by wxGrid which is in wxAdv because we
 // plan to use it in wxListCtrl which is in core too in the future
+class WXDLLIMPEXP_FWD_CORE wxHeaderCtrlEvent;
 
 // ----------------------------------------------------------------------------
 // constants
@@ -101,6 +102,15 @@ protected:
     // information for the given column
     virtual wxHeaderColumnBase& GetColumn(unsigned int idx) = 0;
 
+    // this method is called from the default EVT_HEADER_SEPARATOR_DCLICK
+    // handler to update the fitting column width of the given column, it
+    // should return true if the width was really updated
+    virtual bool UpdateColumnWidthToFit(unsigned int WXUNUSED(idx),
+                                        int WXUNUSED(widthTitle))
+    {
+        return false;
+    }
+
 private:
     // methods implementing our public API and defined in platform-specific
     // implementations
@@ -112,6 +122,11 @@ private:
 
     // this window doesn't look nice with the border so don't use it by default
     virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; }
+
+    // event handlers
+    void OnSeparatorDClick(wxHeaderCtrlEvent& event);
+
+    DECLARE_EVENT_TABLE()
 };
 
 // ----------------------------------------------------------------------------
@@ -276,6 +291,8 @@ extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_HEADER_DCLICK;
 extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_HEADER_RIGHT_DCLICK;
 extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_DCLICK;
 
+extern WXDLLIMPEXP_CORE const wxEventType wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK;
+
 typedef void (wxEvtHandler::*wxHeaderCtrlEventFunction)(wxHeaderCtrlEvent&);
 
 #define wxHeaderCtrlEventHandler(func) \
@@ -293,4 +310,6 @@ typedef void (wxEvtHandler::*wxHeaderCtrlEventFunction)(wxHeaderCtrlEvent&);
 #define EVT_HEADER_RIGHT_DCLICK(id, fn) wx__DECLARE_HEADER_EVT(RIGHT_DCLICK, id, fn)
 #define EVT_HEADER_MIDDLE_DCLICK(id, fn) wx__DECLARE_HEADER_EVT(MIDDLE_DCLICK, id, fn)
 
+#define EVT_HEADER_SEPARATOR_DCLICK(id, fn) wx__DECLARE_HEADER_EVT(SEPARATOR_DCLICK, id, fn)
+
 #endif // _WX_HEADERCTRL_H_
index 9eb0b24b942384fc170bd2c96567f3e919c25b44..8a48ef0d56661d1d4ebc678a94ce9fc973a6dc8e 100644 (file)
@@ -71,9 +71,13 @@ private:
     enum Operation { Set, Insert };
     void DoSetOrInsertItem(Operation oper, unsigned int idx);
 
+    // send an event of the given type for the given column, return true if it
+    // was processed
+    bool SendEvent(wxEventType evtType, unsigned int idx);
+
     // send a click or double click event (depending on dblclk value) for the
     // click with the given button on the given item
-    bool SendClickEvent(bool dblclk, unsigned int idx, int button);
+    bool SendClickEvent(bool dblclk, int button, unsigned int idx);
 
 
     // the image list: initially NULL, created on demand
index 9dd66fec193ffbc30a51fbc0827421b1dd990647..c7e5114da65e38e12dfd1138bfcaaf43657fc639 100644 (file)
             A column heading was right double clicked.
         @event{EVT_HEADER_MIDDLE_DCLICK(id, func)}
             A column heading was double clicked with the middle mouse button.
+
+        @event{EVT_HEADER_SEPARATOR_DCLICK(id, func)}
+            Separator to the right of the specified column was double clicked
+            (this action is commonly used to resize the column to fit its
+            contents width and the control provides UpdateColumnWidthToFit() method
+            to make implementing this easier).
     @endEventTable
 
     @library{wxcore}
@@ -170,6 +176,61 @@ protected:
             SetColumnCount().
      */
     virtual wxHeaderColumnBase& GetColumn(unsigned int idx) = 0;
+
+    /**
+        Method which may be implemented by the derived classes to allow double
+        clicking the column separator to resize the column to fit its contents.
+
+        When a separator is double clicked, the default handler of
+        EVT_HEADER_SEPARATOR_DCLICK event calls this function and refreshes the
+        column if it returns @true so to implement the resizing of the column
+        to fit its width on header double click you need to implement this
+        method using logic similar to this example:
+        @code
+            class MyHeaderCtrl : public wxHeaderColumnBase
+            {
+            public:
+                ...
+
+                void SetWidth(int width) { m_width = width; }
+                virtual int GetWidth() const { return m_width; }
+
+            private:
+                int m_width;
+            };
+
+            class MyHeaderCtrl : public wxHeaderCtrl
+            {
+            public:
+            protected:
+                virtual wxHeaderColumnBase& GetColumn(unsigned int idx)
+                {
+                    return m_cols[idx];
+                }
+
+                virtual bool UpdateColumnWidthToFit(unsigned int idx, int widthTitle)
+                {
+                    int widthContents = ... compute minimal width for column idx ...
+                    m_cols[idx].SetWidth(wxMax(widthContents, widthTitle));
+                    return true;
+                }
+
+                wxVector<MyHeaderColumn> m_cols;
+            };
+        @endcode
+
+        Base class version simply returns @false.
+
+        @param width
+            Contains minimal width needed to display the column header itself
+            and will usually be used as a starting point for the fitting width
+            calculation.
+        @return
+            @true to indicate that the column was resized, i.e. GetColumn() now
+            returns the new width value, and so must be refreshed or @false
+            meaning that the control didn't reach to the separator double click.
+     */
+    virtual bool UpdateColumnWidthToFit(unsigned int idx, int widthTitle);
 };
 
 
index 718a9d6fff6baaa79cb49a5a7ae01a8a58498f19..fa9766ab815e2b9a370c82b70b4b6b2136638a92 100644 (file)
@@ -45,6 +45,10 @@ const unsigned int wxNO_COLUMN = static_cast<unsigned>(-1);
 
 extern WXDLLIMPEXP_DATA_CORE(const char) wxHeaderCtrlNameStr[] = "wxHeaderCtrl";
 
+BEGIN_EVENT_TABLE(wxHeaderCtrlBase, wxControl)
+    EVT_HEADER_SEPARATOR_DCLICK(wxID_ANY, wxHeaderCtrlBase::OnSeparatorDClick)
+END_EVENT_TABLE()
+
 void wxHeaderCtrlBase::ScrollWindow(int dx,
                                     int WXUNUSED_UNLESS_DEBUG(dy),
                                     const wxRect * WXUNUSED_UNLESS_DEBUG(rect))
@@ -60,6 +64,19 @@ void wxHeaderCtrlBase::ScrollWindow(int dx,
     DoScrollHorz(dx);
 }
 
+void wxHeaderCtrlBase::OnSeparatorDClick(wxHeaderCtrlEvent& event)
+{
+    const unsigned col = event.GetColumn();
+
+    int w = wxWindowBase::GetTextExtent(GetColumn(col).GetTitle()).x;
+    w += 2*GetCharWidth(); // add some arbitrary margins around text
+
+    if ( !UpdateColumnWidthToFit(col, w) )
+        event.Skip();
+    else
+        UpdateColumn(col);
+}
+
 // ============================================================================
 // wxHeaderCtrlSimple implementation
 // ============================================================================
@@ -145,3 +162,5 @@ const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_CLICK = wxNewEventType();
 const wxEventType wxEVT_COMMAND_HEADER_DCLICK = wxNewEventType();
 const wxEventType wxEVT_COMMAND_HEADER_RIGHT_DCLICK = wxNewEventType();
 const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_DCLICK = wxNewEventType();
+
+const wxEventType wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK = wxNewEventType();
index ca912681712915b58ac26dc1160ed1f69e2e2cfb..0fbcc1510c6f2e9656ff62c625ad984b4ac0766e 100644 (file)
@@ -88,12 +88,25 @@ public:
     wxDataViewCtrl *GetOwner() const
         { return static_cast<wxDataViewCtrl *>(GetParent()); }
 
-private:
+protected:
+    // implement/override wxHeaderCtrl functions by forwarding them to the main
+    // control
     virtual wxHeaderColumnBase& GetColumn(unsigned int idx)
     {
         return *(GetOwner()->GetColumn(idx));
     }
 
+    virtual bool UpdateColumnWidthToFit(unsigned int idx, int widthTitle)
+    {
+        wxDataViewCtrl * const owner = GetOwner();
+
+        int widthContents = owner->GetBestColumnWidth(idx);
+        owner->GetColumn(idx)->SetWidth(wxMax(widthTitle, widthContents));
+
+        return true;
+    }
+
+private:
     bool SendEvent(wxEventType type, unsigned int n)
     {
         wxDataViewCtrl * const owner = GetOwner();
index 54d7cace41a92aa44e0b3514f158c390c6f37a84..8d8adc9fc42c2a9bdae0ccdc98f82d47274c471a 100644 (file)
@@ -213,7 +213,7 @@ void wxHeaderCtrl::RefreshColsAfter(unsigned int idx)
 // wxHeaderCtrl event handlers
 // ----------------------------------------------------------------------------
 
-BEGIN_EVENT_TABLE(wxHeaderCtrl, wxControl)
+BEGIN_EVENT_TABLE(wxHeaderCtrl, wxHeaderCtrlBase)
     EVT_PAINT(wxHeaderCtrl::OnPaint)
 
     EVT_MOUSE_EVENTS(wxHeaderCtrl::OnMouse)
@@ -330,15 +330,24 @@ void wxHeaderCtrl::OnMouse(wxMouseEvent& mevent)
     }
 
     // determine the type of header event corresponding to this mouse event
-    wxEventType evtType;
-    const bool click = mevent.ButtonUp();
-    if ( click || mevent.ButtonDClick() )
+    wxEventType evtType = wxEVT_NULL;
+    const bool click = mevent.ButtonUp(),
+               dblclk = mevent.ButtonDClick();
+    if ( click || dblclk )
     {
         switch ( mevent.GetButton() )
         {
             case wxMOUSE_BTN_LEFT:
-                evtType = click ? wxEVT_COMMAND_HEADER_CLICK
-                                : wxEVT_COMMAND_HEADER_DCLICK;
+                // treat left double clicks on separator specially
+                if ( onSeparator && dblclk )
+                {
+                    evtType = wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK;
+                }
+                else // not double click on separator
+                {
+                    evtType = click ? wxEVT_COMMAND_HEADER_CLICK
+                                    : wxEVT_COMMAND_HEADER_DCLICK;
+                }
                 break;
 
             case wxMOUSE_BTN_RIGHT:
@@ -353,16 +362,19 @@ void wxHeaderCtrl::OnMouse(wxMouseEvent& mevent)
 
             default:
                 // ignore clicks from other mouse buttons
-                return;
+                ;
         }
+    }
+
+    if ( evtType == wxEVT_NULL )
+        return;
 
-        wxHeaderCtrlEvent event(evtType, GetId());
-        event.SetEventObject(this);
-        event.SetColumn(col);
+    wxHeaderCtrlEvent event(evtType, GetId());
+    event.SetEventObject(this);
+    event.SetColumn(col);
 
-        if ( GetEventHandler()->ProcessEvent(event) )
-            mevent.Skip(false);
-    }
+    if ( GetEventHandler()->ProcessEvent(event) )
+        mevent.Skip(false);
 }
 
 #endif // wxHAS_GENERIC_HEADERCTRL
index 601cb236f85997f0542f41b4555d1ce0c174d8c0..8df0e8286cc0dac891205cfcb858bfd3d103a667 100644 (file)
@@ -28,6 +28,9 @@
 #endif // WX_PRECOMP
 
 #include "wx/headerctrl.h"
+
+#ifndef wxHAS_GENERIC_HEADERCTRL
+
 #include "wx/imaglist.h"
 
 #include "wx/msw/wrapcctl.h"
@@ -257,7 +260,16 @@ void wxHeaderCtrl::DoSetOrInsertItem(Operation oper, unsigned int idx)
 // wxHeaderCtrl events
 // ----------------------------------------------------------------------------
 
-bool wxHeaderCtrl::SendClickEvent(bool dblclk, unsigned int idx, int button)
+bool wxHeaderCtrl::SendEvent(wxEventType evtType, unsigned int idx)
+{
+    wxHeaderCtrlEvent event(evtType, GetId());
+    event.SetEventObject(this);
+    event.SetColumn(idx);
+
+    return GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxHeaderCtrl::SendClickEvent(bool dblclk, int button, unsigned int idx)
 {
     wxEventType evtType;
     switch ( button )
@@ -282,24 +294,19 @@ bool wxHeaderCtrl::SendClickEvent(bool dblclk, unsigned int idx, int button)
             return false;
     }
 
-    wxHeaderCtrlEvent event(evtType, GetId());
-    event.SetEventObject(this);
-    event.SetColumn(idx);
-
-    return GetEventHandler()->ProcessEvent(event);
+    return SendEvent(evtType, idx);
 }
 
 bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 {
     NMHEADER * const nmhdr = (NMHEADER *)lParam;
 
-    switch ( nmhdr->hdr.code )
+    const int idx = nmhdr->iItem;
+    switch ( const UINT code = nmhdr->hdr.code )
     {
         case HDN_ITEMCLICK:
         case HDN_ITEMDBLCLICK:
-            if ( SendClickEvent(nmhdr->hdr.code == HDN_ITEMDBLCLICK,
-                                nmhdr->iItem,
-                                nmhdr->iButton) )
+            if ( SendClickEvent(code == HDN_ITEMDBLCLICK, nmhdr->iButton, idx) )
                 return true;
             break;
 
@@ -313,13 +320,20 @@ bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 const int col = wxMSWGetColumnClicked(&nmhdr->hdr, &pt);
                 if ( col != wxNOT_FOUND )
                 {
-                    if ( SendClickEvent(nmhdr->hdr.code == NM_RDBLCLK, col, 1) )
+                    if ( SendClickEvent(code == NM_RDBLCLK, 1, col) )
                         return true;
                 }
                 //else: ignore clicks outside any column
             }
             break;
+
+        case HDN_DIVIDERDBLCLICK:
+            if ( SendEvent(wxEVT_COMMAND_HEADER_SEPARATOR_DCLICK, idx) )
+                return true;
+            break;
     }
 
     return wxHeaderCtrlBase::MSWOnNotify(idCtrl, lParam, result);
 }
+
+#endif // wxHAS_GENERIC_HEADERCTRL