From 4aff28fc9b124fe1dcb9cb0870eef05cbd326767 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Fri, 11 Feb 2000 02:41:07 +0000
Subject: [PATCH] 1. exchanged binary ROPs wxSET/wxCLEAR meaning for wxMSW to
 match wxGTK 2. bug with multiline messages in wxLogGui fixed 3. wxLogGui
 visual enhancements (for MSW, don't know how it looks elsewhere) 4. fixed 2
 nice (i.e. BIG) memory leaks in wxImage::Rotate() 5. modified the text sample
 to show the mouse events too 6. documented strange behaviour of LEAVE_WINDOW
 mouse event under MSW

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@5958 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/function.tex | 20 ++++++++-
 docs/latex/wx/mouseevt.tex |  6 +++
 samples/text/text.cpp      | 69 +++++++++++++++++++++++++++++-
 src/common/image.cpp       |  3 ++
 src/generic/logg.cpp       | 37 ++++++++++++++--
 src/msw/dc.cpp             | 86 +++++++++++---------------------------
 src/msw/window.cpp         | 58 ++++++++++++++++++-------
 7 files changed, 195 insertions(+), 84 deletions(-)

diff --git a/docs/latex/wx/function.tex b/docs/latex/wx/function.tex
index 3d488829d7..b50303abae 100644
--- a/docs/latex/wx/function.tex
+++ b/docs/latex/wx/function.tex
@@ -36,7 +36,7 @@ void MyThread::Foo(void)
 
     // Call GUI here:
     my_window->DrawSomething();
-    
+
     wxMutexGuiLeave();
 }
 \end{verbatim}
@@ -571,6 +571,24 @@ if (s)
 
 \membersection{::wxGetNumberFromUser}\label{wxgetnumberfromuser}
 
+\func{wxColour}{wxGetColourFromUser}{\param{wxWindow *}{parent}, \parent{const wxColour\& }{colInit}}
+
+Shows the colour selection dialog and returns the colour selected by user or
+invalid colour (use \helpref{wxColour::Ok}{wxcolourok} to test whether a colour
+is valid) if the dialog was cancelled.
+
+\wxheading{Parameters}
+
+\docparam{parent}{The parent window for the colour selection dialog}
+
+\docparam{colInit}{If given, this will be the colour initially selected in the dialog.}
+
+\wxheading{Include files}
+
+<wx/colordlg.h>
+
+\membersection{::wxGetNumberFromUser}\label{wxgetnumberfromuser}
+
 \func{long}{wxGetNumberFromUser}{
  \param{const wxString\& }{message},
  \param{const wxString\& }{prompt},
diff --git a/docs/latex/wx/mouseevt.tex b/docs/latex/wx/mouseevt.tex
index 0c112ef708..04345f2192 100644
--- a/docs/latex/wx/mouseevt.tex
+++ b/docs/latex/wx/mouseevt.tex
@@ -3,6 +3,12 @@
 This event class contains information about mouse events.
 See \helpref{wxWindow::OnMouseEvent}{wxwindowonmouseevent}.
 
+{\bf NB: } Note that under Windows mouse enter and leave events are not natively supported
+by the system but are generated by wxWindows itself. This has several
+drawbacks: the LEAVE\_WINDOW event might be received some time after the mouse
+left the window and the state variables for it may have changed during this
+time.
+
 \wxheading{Derived from}
 
 \helpref{wxEvent}{wxevent}
diff --git a/samples/text/text.cpp b/samples/text/text.cpp
index f534553804..ba3478c97e 100644
--- a/samples/text/text.cpp
+++ b/samples/text/text.cpp
@@ -1,10 +1,10 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        controls.cpp
+// Name:        text.cpp
 // Purpose:     TextCtrl wxWindows sample
 // Author:      Robert Roebling
 // Modified by:
 // RCS-ID:      $Id$
-// Copyright:   (c) Robert Roebling, Julian Smart
+// Copyright:   (c) Robert Roebling, Julian Smart, Vadim Zeitlin
 // Licence:     wxWindows license
 /////////////////////////////////////////////////////////////////////////////
 
@@ -67,6 +67,7 @@ public:
     void OnKeyUp(wxKeyEvent& event);
     void OnChar(wxKeyEvent& event);
     void OnText(wxCommandEvent& event);
+    void OnMouseEvent(wxMouseEvent& event);
 
     bool  m_hasCapture;
 
@@ -241,6 +242,7 @@ BEGIN_EVENT_TABLE(MyTextCtrl, wxTextCtrl)
     EVT_KEY_UP(MyTextCtrl::OnKeyUp)
     EVT_CHAR(MyTextCtrl::OnChar)
     EVT_TEXT(-1, MyTextCtrl::OnText)
+    EVT_MOUSE_EVENTS(MyTextCtrl::OnMouseEvent)
 END_EVENT_TABLE()
 
 void MyTextCtrl::LogEvent(const wxChar *name, wxKeyEvent& event) const
@@ -372,6 +374,69 @@ void MyTextCtrl::LogEvent(const wxChar *name, wxKeyEvent& event) const
 
 }
 
+void MyTextCtrl::OnMouseEvent(wxMouseEvent& ev)
+{
+    if ( !ev.Moving() )
+    {
+        wxString msg;
+        if ( ev.Entering() )
+        {
+            msg = _T("Mouse entered the window");
+        }
+        else if ( ev.Leaving() )
+        {
+            msg = _T("Mouse left the window");
+        }
+        else
+        {
+            // click event
+            wxString button;
+            bool dbl, up;
+            if ( ev.LeftDown() || ev.LeftUp() || ev.LeftDClick() )
+            {
+                button = _T("Left");
+                dbl = ev.LeftDClick();
+                up = ev.LeftUp();
+            }
+            else if ( ev.MiddleDown() || ev.MiddleUp() || ev.MiddleDClick() )
+            {
+                button = _T("Middle");
+                dbl = ev.MiddleDClick();
+                up = ev.MiddleUp();
+            }
+            else if ( ev.RightDown() || ev.RightUp() || ev.RightDClick() )
+            {
+                button = _T("Right");
+                dbl = ev.RightDClick();
+                up = ev.RightUp();
+            }
+            else
+            {
+                wxLogStatus(_T("Unknown mouse event"));
+                return;
+            }
+
+            msg.Printf(_T("%s mouse button %s"),
+                        button.c_str(),
+                        dbl ? _T("double clicked")
+                            : up ? _T("released") : _T("clicked"));
+        }
+
+        msg << _T(" at (") << ev.GetX() << _T(", ") << ev.GetY() << _T(") ")
+            << _T("Flags: ")
+            << GetChar( ev.LeftDown(), _T('1') )
+            << GetChar( ev.MiddleDown(), _T('2') )
+            << GetChar( ev.RightDown(), _T('3') )
+            << GetChar( ev.ControlDown(), _T('C') )
+            << GetChar( ev.AltDown(), _T('A') )
+            << GetChar( ev.ShiftDown(), _T('S') )
+            << GetChar( ev.MetaDown(), _T('M') );
+
+        wxLogMessage(msg);
+    }
+    //else: we're not interested in mouse move events
+}
+
 void MyTextCtrl::OnText(wxCommandEvent& event)
 {
     MyTextCtrl *win = (MyTextCtrl *)event.GetEventObject();
diff --git a/src/common/image.cpp b/src/common/image.cpp
index f4191dc9e3..b8069768a8 100644
--- a/src/common/image.cpp
+++ b/src/common/image.cpp
@@ -2884,6 +2884,9 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
         }
     }
 
+    delete [] data;
+    delete [] result_data;
+
     return rotated;
 }
 
diff --git a/src/generic/logg.cpp b/src/generic/logg.cpp
index 01f50833e2..9ca1c086c1 100644
--- a/src/generic/logg.cpp
+++ b/src/generic/logg.cpp
@@ -84,6 +84,7 @@ public:
     // event handlers
     void OnOk(wxCommandEvent& event);
     void OnDetails(wxCommandEvent& event);
+    void OnListSelect(wxListEvent& event);
 
 private:
     // the data for the listctrl
@@ -104,6 +105,7 @@ private:
 BEGIN_EVENT_TABLE(wxLogDialog, wxDialog)
     EVT_BUTTON(wxID_OK,     wxLogDialog::OnOk)
     EVT_BUTTON(wxID_MORE,   wxLogDialog::OnDetails)
+    EVT_LIST_ITEM_SELECTED(-1, wxLogDialog::OnListSelect)
 END_EVENT_TABLE()
 
 #endif // wxUSE_LOG_DIALOG
@@ -642,9 +644,27 @@ wxLogDialog::wxLogDialog(wxWindow *parent,
                          const wxArrayLong& times,
                          const wxString& caption,
                          long style)
-           : wxDialog(parent, -1, caption ),
-             m_messages(messages), m_severity(severity), m_times(times)
+           : wxDialog(parent, -1, caption )
 {
+    size_t count = messages.GetCount();
+    m_messages.Alloc(count);
+    m_severity.Alloc(count);
+    m_times.Alloc(count);
+
+    for ( size_t n = 0; n < count; n++ )
+    {
+        wxString msg = messages[n];
+        do
+        {
+            m_messages.Add(msg.BeforeFirst(_T('\n')));
+            msg = msg.AfterFirst(_T('\n'));
+
+            m_severity.Add(severity[n]);
+            m_times.Add(times[n]);
+        }
+        while ( !!msg );
+    }
+
     m_showingDetails = FALSE; // not initially
     m_listctrl = (wxListCtrl *)NULL;
 
@@ -676,7 +696,7 @@ wxLogDialog::wxLogDialog(wxWindow *parent,
 
     btnOk->SetFocus();
 
-    if ( m_messages.GetCount() == 1 )
+    if ( count == 1 )
     {
         // no details... it's easier to disable a button than to change the
         // dialog layout depending on whether we have details or not
@@ -686,6 +706,14 @@ wxLogDialog::wxLogDialog(wxWindow *parent,
     Centre();
 }
 
+void wxLogDialog::OnListSelect(wxListEvent& event)
+{
+    // we can't just disable the control because this looks ugly under Windows
+    // (wrong bg colour, no scrolling...), but we still want to disable
+    // selecting items - it makes no sense here
+    m_listctrl->SetItemState(event.GetItem(), 0, wxLIST_STATE_SELECTED);
+}
+
 void wxLogDialog::OnOk(wxCommandEvent& WXUNUSED(event))
 {
     EndModal(wxID_OK);
@@ -712,7 +740,8 @@ void wxLogDialog::OnDetails(wxCommandEvent& WXUNUSED(event))
                                         wxDefaultPosition, wxDefaultSize,
                                         wxSUNKEN_BORDER |
                                         wxLC_REPORT |
-                                        wxLC_NO_HEADER );
+                                        wxLC_NO_HEADER |
+                                        wxLC_SINGLE_SEL);
             m_listctrl->InsertColumn(0, _("Message"));
             m_listctrl->InsertColumn(1, _("Time"));
 
diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp
index 72de5d6db8..e952121916 100644
--- a/src/msw/dc.cpp
+++ b/src/msw/dc.cpp
@@ -74,6 +74,10 @@ static const int MM_METRIC = 10;
     static const double M_PI = 3.14159265358979323846;
 #endif // M_PI
 
+// ROPs which don't have standard names (see "Ternary Raster Operations" in the
+// MSDN docs for how this and other numbers in wxDC::Blit() are obtained)
+#define DSTCOPY 0x00AA0029      // a.k.a. NOP operation
+
 // ---------------------------------------------------------------------------
 // private functions
 // ---------------------------------------------------------------------------
@@ -679,30 +683,19 @@ void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask
         HDC hdcMem = ::CreateCompatibleDC(GetHdc());
         ::SelectObject(hdcMem, GetHbitmapOf(bmp));
 
-        // this will only work if the transparent part of our bitmap is black
-        // because it is combined with the destination rectangle using OR, so
-        // it won't be really transparent otherwise - I don't know what to do
-        // about it, may be use MAKEROP4(SRCCOPY, DSTINVERT) twice? Or create a
-        // copy of the bitmap with the transparent part replaced with black
-        // pixels?
-
-        // GRG: now this works regardless of what the source bitmap
-        //      contains in the area which is to be transparent.
-        //
+        // use MaskBlt() with ROP which doesn't do anything to dst in the mask
+        // points
         bool ok = ::MaskBlt(GetHdc(), x, y, width, height,
                             hdcMem, 0, 0,
                             hbmpMask, 0, 0,
-                            MAKEROP4(SRCCOPY, 0x00AA0029)) != 0;
+                            MAKEROP4(SRCCOPY, DSTCOPY)) != 0;
         ::DeleteDC(hdcMem);
 
         if ( !ok )
 #endif // Win32
         {
-            // VZ: this is incorrect, Blit() doesn't (and can't) draw
-            //     transparently, but it's still better than nothing at all
-            // GRG: Blit() *should* draw transparently when there is a mask
-
-            // Rather than reproduce wxDC::Blit, let's do it at the wxWin API level
+            // Rather than reproduce wxDC::Blit, let's do it at the wxWin API
+            // level
             wxMemoryDC memDC;
             memDC.SelectObject(bmp);
 
@@ -1048,22 +1041,23 @@ void wxDC::SetRop(WXHDC dc)
 
     switch (m_logicalFunction)
     {
+        case wxCLEAR:        rop = R2_BLACK;         break;
         case wxXOR:          rop = R2_XORPEN;        break;
         case wxINVERT:       rop = R2_NOT;           break;
         case wxOR_REVERSE:   rop = R2_MERGEPENNOT;   break;
         case wxAND_REVERSE:  rop = R2_MASKPENNOT;    break;
-        case wxCLEAR:        rop = R2_WHITE;         break;
-        case wxSET:          rop = R2_BLACK;         break;
-        case wxOR_INVERT:    rop = R2_MERGENOTPEN;   break;
+        case wxCOPY:         rop = R2_COPYPEN;       break;
         case wxAND:          rop = R2_MASKPEN;       break;
-        case wxOR:           rop = R2_MERGEPEN;      break;
-        case wxEQUIV:        rop = R2_NOTXORPEN;     break;
-        case wxNAND:         rop = R2_NOTMASKPEN;    break;
         case wxAND_INVERT:   rop = R2_MASKNOTPEN;    break;
-        case wxCOPY:         rop = R2_COPYPEN;       break;
         case wxNO_OP:        rop = R2_NOP;           break;
-        case wxSRC_INVERT:   rop = R2_NOTCOPYPEN;    break;
         case wxNOR:          rop = R2_NOTMERGEPEN;   break;
+        case wxEQUIV:        rop = R2_NOTXORPEN;     break;
+        case wxSRC_INVERT:   rop = R2_NOTCOPYPEN;    break;
+        case wxOR_INVERT:    rop = R2_MERGENOTPEN;   break;
+        case wxNAND:         rop = R2_NOTMASKPEN;    break;
+        case wxOR:           rop = R2_MERGEPEN;      break;
+        case wxSET:          rop = R2_WHITE;         break;
+
         default:
            wxFAIL_MSG( wxT("unsupported logical function") );
            return;
@@ -1334,7 +1328,7 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest,
         case wxNAND:         dwRop = 0x007700E6;       break;
         case wxAND_INVERT:   dwRop = 0x00220326;       break;
         case wxCOPY:         dwRop = SRCCOPY;          break;
-        case wxNO_OP:        dwRop = 0x00AA0029;       break;
+        case wxNO_OP:        dwRop = DSTCOPY;          break;
         case wxSRC_INVERT:   dwRop = NOTSRCCOPY;       break;
         case wxNOR:          dwRop = NOTSRCCOPY;       break;
         default:
@@ -1347,46 +1341,14 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest,
     if (useMask)
     {
 #ifdef __WIN32__
-        // prepare the mask bitmap
-        HBITMAP hbmpMask = wxInvertMask((HBITMAP)mask->GetMaskBitmap());
-
-        // select the correct brush: the current one by default, background one
-        // if none
-        HBRUSH hbrNew;
-        if ( m_brush.Ok() )
-        {
-            hbrNew = (HBRUSH)m_brush.GetResourceHandle();
-        }
-        else if ( m_backgroundBrush.Ok() )
-        {
-            hbrNew = (HBRUSH)m_backgroundBrush.GetResourceHandle();
-        }
-        else
-        {
-            hbrNew = 0;
-        }
-
-        HGDIOBJ hbrOld = hbrNew ? ::SelectObject(GetHdc(), hbrNew) : 0;
-
         // we want the part of the image corresponding to the mask to be
-        // transparent, i.e. do PATCOPY there and apply dwRop elsewhere
-
-        // GRG: PATCOPY is not transparent, as can be seen when blitting
-        //      over a pattern: the 'transparent' area would be filled
-        //      with the selected colour. We should use NOP instead, or
-        //      do MaskBlt + BitBlt.
-        //
+        // transparent, so use "DSTCOPY" ROP for the mask points (the usual
+        // meaning of fg and bg is inverted which corresponds to wxWin notion
+        // of the mask which is also contrary to the Windows one)
         success = ::MaskBlt(GetHdc(), xdest, ydest, width, height,
                             GetHdcOf(*source), xsrc, ysrc,
-                            hbmpMask, 0, 0,
-                            MAKEROP4(0x00AA0029, dwRop)) != 0;
-
-        if ( hbrNew )
-        {
-            (void)::SelectObject(GetHdc(), hbrOld);
-        }
-
-        ::DeleteObject(hbmpMask);
+                            (HBITMAP)mask->GetMaskBitmap(), 0, 0,
+                            MAKEROP4(dwRop, DSTCOPY)) != 0;
 
         if ( !success )
 #endif // Win32
diff --git a/src/msw/window.cpp b/src/msw/window.cpp
index 87bc2b6ae5..0d3cf5a857 100644
--- a/src/msw/window.cpp
+++ b/src/msw/window.cpp
@@ -127,6 +127,10 @@ void wxRemoveHandleAssociation(wxWindow *win);
 void wxAssociateWinWithHandle(HWND hWnd, wxWindow *win);
 wxWindow *wxFindWinFromHandle(WXHWND hWnd);
 
+// this magical function is used to translate VK_APPS key presses to right
+// mouse clicks
+static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags);
+
 // ---------------------------------------------------------------------------
 // event tables
 // ---------------------------------------------------------------------------
@@ -1998,20 +2002,11 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
                 // click because both usually pop up a context menu
                 case VK_APPS:
                     {
-                        // construct the key mask
-                        WPARAM fwKeys = MK_RBUTTON;
-                        if ( (::GetKeyState(VK_CONTROL) & 0x100) != 0 )
-                            fwKeys |= MK_CONTROL;
-                        if ( (::GetKeyState(VK_SHIFT) & 0x100) != 0 )
-                            fwKeys |= MK_SHIFT;
-
-                        // simulate right mouse button click
-                        DWORD dwPos = ::GetMessagePos();
-                        int x = GET_X_LPARAM(dwPos),
-                            y = GET_Y_LPARAM(dwPos);
-
-                        ScreenToClient(&x, &y);
-                        processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, fwKeys);
+                        WPARAM flags;
+                        int x, y;
+
+                        TranslateKbdEventToMouse(this, &x, &y, &flags);
+                        processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags);
                     }
                     break;
 #endif // VK_APPS
@@ -2027,7 +2022,21 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
 
         case WM_SYSKEYUP:
         case WM_KEYUP:
-            processed = HandleKeyUp((WORD) wParam, lParam);
+#ifdef VK_APPS
+            // special case of VK_APPS: treat it the same as right mouse button
+            if ( wParam == VK_APPS )
+            {
+                WPARAM flags;
+                int x, y;
+
+                TranslateKbdEventToMouse(this, &x, &y, &flags);
+                processed = HandleMouseEvent(WM_RBUTTONUP, x, y, flags);
+            }
+            else
+#endif // VK_APPS
+            {
+                processed = HandleKeyUp((WORD) wParam, lParam);
+            }
             break;
 
         case WM_SYSCHAR:
@@ -4168,3 +4177,22 @@ const char *wxGetMessageName(int message)
     }
 }
 #endif //__WXDEBUG__
+
+static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags)
+{
+    // construct the key mask
+    WPARAM& fwKeys = *flags;
+
+    fwKeys = MK_RBUTTON;
+    if ( (::GetKeyState(VK_CONTROL) & 0x100) != 0 )
+        fwKeys |= MK_CONTROL;
+    if ( (::GetKeyState(VK_SHIFT) & 0x100) != 0 )
+        fwKeys |= MK_SHIFT;
+
+    // simulate right mouse button click
+    DWORD dwPos = ::GetMessagePos();
+    *x = GET_X_LPARAM(dwPos);
+    *y = GET_Y_LPARAM(dwPos);
+
+    win->ScreenToClient(x, y);
+}
-- 
2.50.0

