From: Vadim Zeitlin Date: Fri, 11 Feb 2000 02:41:07 +0000 (+0000) Subject: 1. exchanged binary ROPs wxSET/wxCLEAR meaning for wxMSW to match wxGTK X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/4aff28fc9b124fe1dcb9cb0870eef05cbd326767 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 --- 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} + + + +\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); +}