]> git.saurik.com Git - wxWidgets.git/commitdiff
implement click events in wxHeaderCtrl
authorVadim Zeitlin <vadim@wxwidgets.org>
Mon, 8 Dec 2008 00:57:53 +0000 (00:57 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Mon, 8 Dec 2008 00:57:53 +0000 (00:57 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57178 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 6b7f3e410d2675aa0a35eb979d978815f229e2a8..2bbe5efc8f62cfe28cfbf93b26c94976eaf4a538 100644 (file)
@@ -74,6 +74,14 @@ private:
     // refresh all the controls starting from (and including) the given one
     void RefreshColsAfter(unsigned int idx);
 
     // refresh all the controls starting from (and including) the given one
     void RefreshColsAfter(unsigned int idx);
 
+    // return the column at the given position or -1 if it is beyond the
+    // rightmost column and put true into onSeparator output parameter if the
+    // position is near the divider at the right end of this column (notice
+    // that this means that we return column 0 even if the position is over
+    // column 1 but close enough to the divider separating it from column 0)
+    int FindColumnAtPos(int x, bool& onSeparator) const;
+
+
     // number of columns in the control currently
     unsigned int m_numColumns;
 
     // number of columns in the control currently
     unsigned int m_numColumns;
 
index 50c897137adf4a51c6a98829c533fb801f6178cd..6264cfec0fb950781e023295797e54c275864d97 100644 (file)
@@ -120,7 +120,7 @@ private:
 //               control, see wxHeaderCtrlSimple for a standalone version
 // ----------------------------------------------------------------------------
 
 //               control, see wxHeaderCtrlSimple for a standalone version
 // ----------------------------------------------------------------------------
 
-#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
+#if 0// defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
     #include "wx/msw/headerctrl.h"
 #else
     #define wxHAS_GENERIC_HEADERCTRL
     #include "wx/msw/headerctrl.h"
 #else
     #define wxHAS_GENERIC_HEADERCTRL
@@ -236,4 +236,61 @@ private:
     DECLARE_NO_COPY_CLASS(wxHeaderCtrlSimple)
 };
 
     DECLARE_NO_COPY_CLASS(wxHeaderCtrlSimple)
 };
 
+// ----------------------------------------------------------------------------
+// wxHeaderCtrl events
+// ----------------------------------------------------------------------------
+
+class WXDLLIMPEXP_CORE wxHeaderCtrlEvent : public wxNotifyEvent
+{
+public:
+    wxHeaderCtrlEvent(wxEventType commandType = wxEVT_NULL, int winid = 0)
+        : wxNotifyEvent(commandType, winid)
+    {
+    }
+
+    wxHeaderCtrlEvent(const wxHeaderCtrlEvent& event)
+        : wxNotifyEvent(event),
+          m_col(event.m_col)
+    {
+    }
+
+    int GetColumn() const { return m_col; }
+    void SetColumn(int col) { m_col = col; }
+
+    virtual wxEvent *Clone() const { return new wxHeaderCtrlEvent(*this); }
+
+protected:
+    // the column affected by the event
+    int m_col;
+
+private:
+    DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxHeaderCtrlEvent)
+};
+
+
+extern WXDLLIMPEXP_ADV const wxEventType wxEVT_COMMAND_HEADER_CLICK;
+extern WXDLLIMPEXP_ADV const wxEventType wxEVT_COMMAND_HEADER_RIGHT_CLICK;
+extern WXDLLIMPEXP_ADV const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_CLICK;
+
+extern WXDLLIMPEXP_ADV const wxEventType wxEVT_COMMAND_HEADER_DCLICK;
+extern WXDLLIMPEXP_ADV const wxEventType wxEVT_COMMAND_HEADER_RIGHT_DCLICK;
+extern WXDLLIMPEXP_ADV const wxEventType wxEVT_COMMAND_HEADER_MIDDLE_DCLICK;
+
+typedef void (wxEvtHandler::*wxHeaderCtrlEventFunction)(wxHeaderCtrlEvent&);
+
+#define wxHeaderCtrlEventHandler(func) \
+    (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent( \
+            wxHeaderCtrlEventFunction, &func)
+
+#define wx__DECLARE_HEADER_EVT(evt, id, fn) \
+    wx__DECLARE_EVT1(wxEVT_COMMAND_HEADER_ ## evt, id, wxHeaderCtrlEventHandler(fn))
+
+#define EVT_HEADER_CLICK(id, fn) wx__DECLARE_HEADER_EVT(CLICK, id, fn)
+#define EVT_HEADER_RIGHT_CLICK(id, fn) wx__DECLARE_HEADER_EVT(RIGHT_CLICK, id, fn)
+#define EVT_HEADER_MIDDLE_CLICK(id, fn) wx__DECLARE_HEADER_EVT(MIDDLE_CLICK, id, fn)
+
+#define EVT_HEADER_DCLICK(id, fn) wx__DECLARE_HEADER_EVT(DCLICK, id, fn)
+#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)
+
 #endif // _WX_HEADERCTRL_H_
 #endif // _WX_HEADERCTRL_H_
index 74919ef11111ed0a7271397626fecd0c65a8b09f..9eb0b24b942384fc170bd2c96567f3e919c25b44 100644 (file)
@@ -60,6 +60,7 @@ private:
 
     // override MSW-specific methods needed for new control
     virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const;
 
     // override MSW-specific methods needed for new control
     virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const;
+    virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result);
 
     // common part of all ctors
     void Init();
 
     // common part of all ctors
     void Init();
@@ -70,6 +71,10 @@ private:
     enum Operation { Set, Insert };
     void DoSetOrInsertItem(Operation oper, unsigned int idx);
 
     enum Operation { Set, Insert };
     void DoSetOrInsertItem(Operation oper, 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);
+
 
     // the image list: initially NULL, created on demand
     wxImageList *m_imageList;
 
     // the image list: initially NULL, created on demand
     wxImageList *m_imageList;
index 76b76e746f97fdf76631eb0f184dcd1a9b77d517..9dd66fec193ffbc30a51fbc0827421b1dd990647 100644 (file)
             wxHD_DRAGDROP.
     @endStyleTable
 
             wxHD_DRAGDROP.
     @endStyleTable
 
-    @beginEventTable{wxHeaderEvent}
-    @event{EVT_HEADER_CLICK(id, func)}
-        A column heading was clicked.
+    @beginEventTable{wxHeaderCtrlEvent}
+        @event{EVT_HEADER_CLICK(id, func)}
+            A column heading was clicked.
+        @event{EVT_HEADER_RIGHT_CLICK(id, func)}
+            A column heading was right clicked.
+        @event{EVT_HEADER_MIDDLE_CLICK(id, func)}
+            A column heading was clicked with the middle mouse button.
+
+        @event{EVT_HEADER_DCLICK(id, func)}
+            A column heading was double clicked.
+        @event{EVT_HEADER_RIGHT_DCLICK(id, func)}
+            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.
     @endEventTable
 
     @library{wxcore}
     @endEventTable
 
     @library{wxcore}
@@ -285,3 +296,22 @@ public:
      */
     void RemoveSortIndicator(unsigned int idx);
 };
      */
     void RemoveSortIndicator(unsigned int idx);
 };
+
+/**
+    @class wxHeaderCtrlEvent
+
+    Event class representing the events generated by wxHeaderCtrl.
+
+    @library{wxcore}
+    @category{ctrl}
+
+    @see wxHeaderCtrl
+*/
+class wxHeaderCtrlEvent : public wxNotifyEvent
+{
+public:
+    /**
+        Return the index of the column affected by this event.
+     */
+    int GetColumn() const;
+};
index b91f3fc7d8ca0d059bd041a6691f98b1a0d43e8e..718a9d6fff6baaa79cb49a5a7ae01a8a58498f19 100644 (file)
@@ -132,3 +132,16 @@ void wxHeaderCtrlSimple::RemoveSortIndicator()
     }
 }
 
     }
 }
 
+// ============================================================================
+// wxHeaderCtrlEvent implementation
+// ============================================================================
+
+IMPLEMENT_DYNAMIC_CLASS(wxHeaderCtrlEvent, wxNotifyEvent)
+
+const wxEventType wxEVT_COMMAND_HEADER_CLICK = wxNewEventType();
+const wxEventType wxEVT_COMMAND_HEADER_RIGHT_CLICK = wxNewEventType();
+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();
index 339d49017455e74b2bee559e9ae129666f239777..ca912681712915b58ac26dc1160ed1f69e2e2cfb 100644 (file)
@@ -67,16 +67,16 @@ static const int EXPANDER_OFFSET = 4;
 static const int EXPANDER_OFFSET = 1;
 #endif
 
 static const int EXPANDER_OFFSET = 1;
 #endif
 
-//-----------------------------------------------------------------------------
-// wxDataViewHeaderWindow
-//-----------------------------------------------------------------------------
-
 //Below is the compare stuff
 //For the generic implements, both the leaf nodes and the nodes are sorted for fast search when needed
 static wxDataViewModel * g_model;
 static int g_column = -2;
 static bool g_asending = true;
 
 //Below is the compare stuff
 //For the generic implements, both the leaf nodes and the nodes are sorted for fast search when needed
 static wxDataViewModel * g_model;
 static int g_column = -2;
 static bool g_asending = true;
 
+//-----------------------------------------------------------------------------
+// wxDataViewHeaderWindow
+//-----------------------------------------------------------------------------
+
 class wxDataViewHeaderWindow : public wxHeaderCtrl
 {
 public:
 class wxDataViewHeaderWindow : public wxHeaderCtrl
 {
 public:
@@ -88,16 +88,50 @@ public:
     wxDataViewCtrl *GetOwner() const
         { return static_cast<wxDataViewCtrl *>(GetParent()); }
 
     wxDataViewCtrl *GetOwner() const
         { return static_cast<wxDataViewCtrl *>(GetParent()); }
 
-protected:
+private:
     virtual wxHeaderColumnBase& GetColumn(unsigned int idx)
     {
         return *(GetOwner()->GetColumn(idx));
     }
 
     virtual wxHeaderColumnBase& GetColumn(unsigned int idx)
     {
         return *(GetOwner()->GetColumn(idx));
     }
 
-private:
+    bool SendEvent(wxEventType type, unsigned int n)
+    {
+        wxDataViewCtrl * const owner = GetOwner();
+        wxDataViewEvent event(type, owner->GetId());
+
+        event.SetEventObject(owner);
+        event.SetColumn(n);
+        event.SetDataViewColumn(owner->GetColumn(n));
+        event.SetModel(owner->GetModel());
+
+        // for events created by wxDataViewHeaderWindow the
+        // row / value fields are not valid
+        return owner->GetEventHandler()->ProcessEvent(event);
+    }
+
+    void OnClick(wxHeaderCtrlEvent& event)
+    {
+        if ( !SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK,
+                        event.GetColumn()) )
+            event.Skip();
+    }
+
+    void OnRClick(wxHeaderCtrlEvent& event)
+    {
+        if ( !SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK,
+                        event.GetColumn()) )
+            event.Skip();
+    }
+
+    DECLARE_EVENT_TABLE()
     DECLARE_NO_COPY_CLASS(wxDataViewHeaderWindow)
 };
 
     DECLARE_NO_COPY_CLASS(wxDataViewHeaderWindow)
 };
 
+BEGIN_EVENT_TABLE(wxDataViewHeaderWindow, wxHeaderCtrl)
+    EVT_HEADER_CLICK(wxID_ANY, wxDataViewHeaderWindow::OnClick)
+    EVT_HEADER_RIGHT_CLICK(wxID_ANY, wxDataViewHeaderWindow::OnRClick)
+END_EVENT_TABLE()
+
 //-----------------------------------------------------------------------------
 // wxDataViewRenameTimer
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // wxDataViewRenameTimer
 //-----------------------------------------------------------------------------
index f55b7e1f6f4b9b2a53819389331cbd34580e98a7..823ea60aac8254025f8dbb4cefe74e27f4afa2d3 100644 (file)
@@ -145,6 +145,41 @@ int wxHeaderCtrl::GetColStart(unsigned int idx) const
     return pos;
 }
 
     return pos;
 }
 
+int wxHeaderCtrl::FindColumnAtPos(int x, bool& onSeparator) const
+{
+    wxHeaderCtrl * const self = const_cast<wxHeaderCtrl *>(this);
+
+    int pos = 0;
+    const unsigned count = GetColumnCount();
+    for ( unsigned n = 0; n < count; n++ )
+    {
+        const wxHeaderColumnBase& col = self->GetColumn(n);
+        if ( col.IsHidden() )
+            continue;
+
+        pos += col.GetWidth();
+
+        // if the column is resizeable, check if we're approximatively over the
+        // line separating it from the next column
+        //
+        // TODO: don't hardcode sensitivity
+        if ( col.IsResizeable() && abs(x - pos) < 8 )
+        {
+            onSeparator = true;
+            return n;
+        }
+
+        // inside this column?
+        if ( x < pos )
+        {
+            onSeparator = false;
+            return n;
+        }
+    }
+
+    return COL_NONE;
+}
+
 // ----------------------------------------------------------------------------
 // wxHeaderCtrl repainting
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // wxHeaderCtrl repainting
 // ----------------------------------------------------------------------------
@@ -242,9 +277,70 @@ void wxHeaderCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
     }
 }
 
     }
 }
 
-void wxHeaderCtrl::OnMouse(wxMouseEvent& event)
+void wxHeaderCtrl::OnMouse(wxMouseEvent& mevent)
 {
 {
-    event.Skip();
+    mevent.Skip();
+
+    // find if the event is over a column at all
+    bool onSeparator;
+    const unsigned col = FindColumnAtPos(mevent.GetX(), onSeparator);
+    if ( col == COL_NONE )
+        return;
+
+    // update mouse cursor as it moves around
+    if ( mevent.Moving() )
+    {
+        SetCursor(onSeparator ? wxCursor(wxCURSOR_SIZEWE) : wxNullCursor);
+        return;
+    }
+
+    if ( mevent.LeftDown() )
+    {
+        // TODO
+        if ( onSeparator )
+            // resize column
+            ;
+        else
+            // drag column
+            ;
+
+        return;
+    }
+
+    // determine the type of header event corresponding to this mouse event
+    wxEventType evtType;
+    const bool click = mevent.ButtonUp();
+    if ( click || mevent.ButtonDClick() )
+    {
+        switch ( mevent.GetButton() )
+        {
+            case wxMOUSE_BTN_LEFT:
+                evtType = click ? wxEVT_COMMAND_HEADER_CLICK
+                                : wxEVT_COMMAND_HEADER_DCLICK;
+                break;
+
+            case wxMOUSE_BTN_RIGHT:
+                evtType = click ? wxEVT_COMMAND_HEADER_RIGHT_CLICK
+                                : wxEVT_COMMAND_HEADER_RIGHT_DCLICK;
+                break;
+
+            case wxMOUSE_BTN_MIDDLE:
+                evtType = click ? wxEVT_COMMAND_HEADER_MIDDLE_CLICK
+                                : wxEVT_COMMAND_HEADER_MIDDLE_DCLICK;
+                break;
+
+            default:
+                // ignore clicks from other mouse buttons
+                return;
+        }
+
+        wxHeaderCtrlEvent event(evtType, GetId());
+        event.SetEventObject(this);
+        event.SetColumn(col);
+
+        if ( GetEventHandler()->ProcessEvent(event) )
+            mevent.Skip(false);
+    }
 }
 
 #endif // wxHAS_GENERIC_HEADERCTRL
 }
 
 #endif // wxHAS_GENERIC_HEADERCTRL
index f12c8c1f71ebb592dbf6ecbbb1afe984edbde665..601cb236f85997f0542f41b4555d1ce0c174d8c0 100644 (file)
@@ -33,6 +33,9 @@
 #include "wx/msw/wrapcctl.h"
 #include "wx/msw/private.h"
 
 #include "wx/msw/wrapcctl.h"
 #include "wx/msw/private.h"
 
+// from src/msw/listctrl.cpp
+extern int WXDLLIMPEXP_CORE wxMSWGetColumnClicked(NMHDR *nmhdr, POINT *ptClick);
+
 // ============================================================================
 // wxHeaderCtrl implementation
 // ============================================================================
 // ============================================================================
 // wxHeaderCtrl implementation
 // ============================================================================
@@ -250,3 +253,73 @@ void wxHeaderCtrl::DoSetOrInsertItem(Operation oper, unsigned int idx)
     }
 }
 
     }
 }
 
+// ----------------------------------------------------------------------------
+// wxHeaderCtrl events
+// ----------------------------------------------------------------------------
+
+bool wxHeaderCtrl::SendClickEvent(bool dblclk, unsigned int idx, int button)
+{
+    wxEventType evtType;
+    switch ( button )
+    {
+        case 0:
+            evtType = dblclk ? wxEVT_COMMAND_HEADER_DCLICK
+                             : wxEVT_COMMAND_HEADER_CLICK;
+            break;
+
+        case 1:
+            evtType = dblclk ? wxEVT_COMMAND_HEADER_RIGHT_DCLICK
+                             : wxEVT_COMMAND_HEADER_RIGHT_CLICK;
+            break;
+
+        case 2:
+            evtType = dblclk ? wxEVT_COMMAND_HEADER_MIDDLE_DCLICK
+                             : wxEVT_COMMAND_HEADER_MIDDLE_CLICK;
+            break;
+
+        default:
+            wxFAIL_MSG( wxS("unexpected event type") );
+            return false;
+    }
+
+    wxHeaderCtrlEvent event(evtType, GetId());
+    event.SetEventObject(this);
+    event.SetColumn(idx);
+
+    return GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxHeaderCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
+{
+    NMHEADER * const nmhdr = (NMHEADER *)lParam;
+
+    switch ( nmhdr->hdr.code )
+    {
+        case HDN_ITEMCLICK:
+        case HDN_ITEMDBLCLICK:
+            if ( SendClickEvent(nmhdr->hdr.code == HDN_ITEMDBLCLICK,
+                                nmhdr->iItem,
+                                nmhdr->iButton) )
+                return true;
+            break;
+
+            // although we should get the notifications about the right clicks
+            // via HDN_ITEM[DBL]CLICK too according to MSDN this simply doesn't
+            // happen in practice on any Windows system up to 2003
+        case NM_RCLICK:
+        case NM_RDBLCLK:
+            {
+                POINT pt;
+                const int col = wxMSWGetColumnClicked(&nmhdr->hdr, &pt);
+                if ( col != wxNOT_FOUND )
+                {
+                    if ( SendClickEvent(nmhdr->hdr.code == NM_RDBLCLK, col, 1) )
+                        return true;
+                }
+                //else: ignore clicks outside any column
+            }
+            break;
+    }
+
+    return wxHeaderCtrlBase::MSWOnNotify(idCtrl, lParam, result);
+}