+// New function that will replace some of the above.
+void wxWindow::SetScrollbar(int orient, int pos, int thumbVisible,
+ int range, bool refresh)
+{
+#if defined(__WIN95__)
+ int oldRange = range - thumbVisible;
+
+ int range1 = oldRange;
+
+ // Try to adjust the range to cope with page size > 1
+ // - a Windows API quirk
+ int pageSize = thumbVisible;
+ if ( pageSize > 1 && range > 0)
+ {
+ range1 += (pageSize - 1);
+ }
+
+ SCROLLINFO info;
+ int dir;
+
+ if ( orient == wxHORIZONTAL ) {
+ dir = SB_HORZ;
+ } else {
+ dir = SB_VERT;
+ }
+
+ info.cbSize = sizeof(SCROLLINFO);
+ info.nPage = pageSize; // Have to set this, or scrollbar goes awry
+ info.nMin = 0;
+ info.nMax = range1;
+ info.nPos = pos;
+ info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
+
+ HWND hWnd = GetHwnd();
+ if ( hWnd )
+ ::SetScrollInfo(hWnd, dir, &info, refresh);
+#else
+ int wOrient;
+ if ( orient == wxHORIZONTAL )
+ wOrient = SB_HORZ;
+ else
+ wOrient = SB_VERT;
+
+ HWND hWnd = GetHwnd();
+ if ( hWnd )
+ {
+ ::SetScrollRange(hWnd, wOrient, 0, range, FALSE);
+ ::SetScrollPos(hWnd, wOrient, pos, refresh);
+ }
+#endif
+ if ( orient == wxHORIZONTAL ) {
+ m_xThumbSize = thumbVisible;
+ } else {
+ m_yThumbSize = thumbVisible;
+ }
+}
+
+void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect)
+{
+ RECT rect2;
+ if ( rect )
+ {
+ rect2.left = rect->x;
+ rect2.top = rect->y;
+ rect2.right = rect->x + rect->width;
+ rect2.bottom = rect->y + rect->height;
+ }
+
+ if ( rect )
+ ::ScrollWindow(GetHwnd(), dx, dy, &rect2, NULL);
+ else
+ ::ScrollWindow(GetHwnd(), dx, dy, NULL, NULL);
+}
+
+// ---------------------------------------------------------------------------
+// subclassing
+// ---------------------------------------------------------------------------
+
+void wxWindow::SubclassWin(WXHWND hWnd)
+{
+ wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") );
+
+ HWND hwnd = (HWND)hWnd;
+ wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") );
+
+ wxAssociateWinWithHandle(hwnd, this);
+
+ m_oldWndProc = (WXFARPROC) GetWindowLong(hwnd, GWL_WNDPROC);
+ SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc);
+}
+
+void wxWindow::UnsubclassWin()
+{
+ wxRemoveHandleAssociation(this);
+
+ // Restore old Window proc
+ HWND hwnd = GetHwnd();
+ if ( hwnd )
+ {
+ m_hWnd = 0;
+
+ wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") );
+
+ FARPROC farProc = (FARPROC) GetWindowLong(hwnd, GWL_WNDPROC);
+ if ( (m_oldWndProc != 0) && (farProc != (FARPROC) m_oldWndProc) )
+ {
+ SetWindowLong(hwnd, GWL_WNDPROC, (LONG) m_oldWndProc);
+ m_oldWndProc = 0;
+ }
+ }
+}
+
+// Make a Windows extended style from the given wxWindows window style
+WXDWORD wxWindow::MakeExtendedStyle(long style, bool eliminateBorders)
+{
+ WXDWORD exStyle = 0;
+ if ( style & wxTRANSPARENT_WINDOW )
+ exStyle |= WS_EX_TRANSPARENT;
+
+ if ( !eliminateBorders )
+ {
+ if ( style & wxSUNKEN_BORDER )
+ exStyle |= WS_EX_CLIENTEDGE;
+ if ( style & wxDOUBLE_BORDER )
+ exStyle |= WS_EX_DLGMODALFRAME;
+#if defined(__WIN95__)
+ if ( style & wxRAISED_BORDER )
+ // It seems that WS_EX_WINDOWEDGE doesn't work, but WS_EX_DLGMODALFRAME does
+ exStyle |= WS_EX_DLGMODALFRAME; /* WS_EX_WINDOWEDGE */;
+ if ( style & wxSTATIC_BORDER )
+ exStyle |= WS_EX_STATICEDGE;
+#endif
+ }
+ return exStyle;
+}
+
+// Determines whether native 3D effects or CTL3D should be used,
+// applying a default border style if required, and returning an extended
+// style to pass to CreateWindowEx.
+WXDWORD wxWindow::Determine3DEffects(WXDWORD defaultBorderStyle,
+ bool *want3D) const
+{
+ // If matches certain criteria, then assume no 3D effects
+ // unless specifically requested (dealt with in MakeExtendedStyle)
+ if ( !GetParent() || !IsKindOf(CLASSINFO(wxControl)) || (m_windowStyle & wxNO_BORDER) )
+ {
+ *want3D = FALSE;
+ return MakeExtendedStyle(m_windowStyle, FALSE);
+ }
+
+ // Determine whether we should be using 3D effects or not.
+ bool nativeBorder = FALSE; // by default, we don't want a Win95 effect
+
+ // 1) App can specify global 3D effects
+ *want3D = wxTheApp->GetAuto3D();
+
+ // 2) If the parent is being drawn with user colours, or simple border specified,
+ // switch effects off. TODO: replace wxUSER_COLOURS with wxNO_3D
+ if ( GetParent() && (GetParent()->GetWindowStyleFlag() & wxUSER_COLOURS) || (m_windowStyle & wxSIMPLE_BORDER) )
+ *want3D = FALSE;
+
+ // 3) Control can override this global setting by defining
+ // a border style, e.g. wxSUNKEN_BORDER
+ if ( m_windowStyle & wxSUNKEN_BORDER )
+ *want3D = TRUE;
+
+ // 4) If it's a special border, CTL3D can't cope so we want a native border
+ if ( (m_windowStyle & wxDOUBLE_BORDER) || (m_windowStyle & wxRAISED_BORDER) ||
+ (m_windowStyle & wxSTATIC_BORDER) )
+ {
+ *want3D = TRUE;
+ nativeBorder = TRUE;
+ }
+
+ // 5) If this isn't a Win95 app, and we are using CTL3D, remove border
+ // effects from extended style
+#if wxUSE_CTL3D
+ if ( *want3D )
+ nativeBorder = FALSE;
+#endif
+
+ DWORD exStyle = MakeExtendedStyle(m_windowStyle, !nativeBorder);
+
+ // If we want 3D, but haven't specified a border here,
+ // apply the default border style specified.
+ // TODO what about non-Win95 WIN32? Does it have borders?
+#if defined(__WIN95__) && !wxUSE_CTL3D
+ if ( defaultBorderStyle && (*want3D) && ! ((m_windowStyle & wxDOUBLE_BORDER) || (m_windowStyle & wxRAISED_BORDER ) ||
+ (m_windowStyle & wxSTATIC_BORDER) || (m_windowStyle & wxSIMPLE_BORDER) ))
+ exStyle |= defaultBorderStyle; // WS_EX_CLIENTEDGE;
+#endif
+
+ return exStyle;
+}
+
+#if WXWIN_COMPATIBILITY
+// If nothing defined for this, try the parent.
+// E.g. we may be a button loaded from a resource, with no callback function
+// defined.
+void wxWindow::OnCommand(wxWindow& win, wxCommandEvent& event)
+{
+ if ( GetEventHandler()->ProcessEvent(event) )
+ return;
+ if ( m_parent )
+ m_parent->GetEventHandler()->OnCommand(win, event);
+}
+#endif // WXWIN_COMPATIBILITY_2
+
+#if WXWIN_COMPATIBILITY
+wxObject* wxWindow::GetChild(int number) const
+{
+ // Return a pointer to the Nth object in the Panel
+ wxNode *node = GetChildren().First();
+ int n = number;
+ while (node && n--)
+ node = node->Next();
+ if ( node )
+ {
+ wxObject *obj = (wxObject *)node->Data();
+ return(obj);
+ }
+ else
+ return NULL;
+}
+#endif // WXWIN_COMPATIBILITY
+
+// Setup background and foreground colours correctly
+void wxWindow::SetupColours()
+{
+ if ( GetParent() )
+ SetBackgroundColour(GetParent()->GetBackgroundColour());
+}
+
+void wxWindow::OnIdle(wxIdleEvent& WXUNUSED(event))
+{
+ // Check if we need to send a LEAVE event
+ if ( m_mouseInWindow )
+ {
+ POINT pt;
+ ::GetCursorPos(&pt);
+ if ( ::WindowFromPoint(pt) != GetHwnd() )
+ {
+ // Generate a LEAVE event
+ m_mouseInWindow = FALSE;
+
+ // Unfortunately the mouse button and keyboard state may have changed
+ // by the time the OnIdle function is called, so 'state' may be
+ // meaningless.
+ int state = 0;
+ if ( wxIsShiftDown() )
+ state |= MK_SHIFT;
+ if ( wxIsCtrlDown() )
+ state |= MK_CONTROL;
+ if ( GetKeyState( VK_LBUTTON ) )
+ state |= MK_LBUTTON;
+ if ( GetKeyState( VK_MBUTTON ) )
+ state |= MK_MBUTTON;
+ if ( GetKeyState( VK_RBUTTON ) )
+ state |= MK_RBUTTON;
+
+ wxMouseEvent event(wxEVT_LEAVE_WINDOW);
+ InitMouseEvent(event, pt.x, pt.y, state);
+
+ (void)GetEventHandler()->ProcessEvent(event);
+ }
+ }
+
+ UpdateWindowUI();
+}
+
+// Set this window to be the child of 'parent'.
+bool wxWindow::Reparent(wxWindowBase *parent)
+{
+ if ( !wxWindowBase::Reparent(parent) )
+ return FALSE;
+
+ HWND hWndChild = GetHwnd();
+ HWND hWndParent = GetParent() ? GetWinHwnd(GetParent()) : (HWND)0;
+
+ ::SetParent(hWndChild, hWndParent);
+
+ return TRUE;
+}
+
+void wxWindow::Clear()
+{
+ wxClientDC dc(this);
+ wxBrush brush(GetBackgroundColour(), wxSOLID);
+ dc.SetBackground(brush);
+ dc.Clear();
+}
+
+void wxWindow::Refresh(bool eraseBack, const wxRect *rect)
+{
+ HWND hWnd = GetHwnd();
+ if ( hWnd )
+ {
+ if ( rect )
+ {
+ RECT mswRect;
+ mswRect.left = rect->x;
+ mswRect.top = rect->y;
+ mswRect.right = rect->x + rect->width;
+ mswRect.bottom = rect->y + rect->height;
+
+ ::InvalidateRect(hWnd, &mswRect, eraseBack);
+ }
+ else
+ ::InvalidateRect(hWnd, NULL, eraseBack);
+ }
+}
+
+// ---------------------------------------------------------------------------
+// drag and drop
+// ---------------------------------------------------------------------------
+
+#if wxUSE_DRAG_AND_DROP
+
+void wxWindow::SetDropTarget(wxDropTarget *pDropTarget)
+{
+ if ( m_dropTarget != 0 ) {
+ m_dropTarget->Revoke(m_hWnd);
+ delete m_dropTarget;
+ }
+
+ m_dropTarget = pDropTarget;
+ if ( m_dropTarget != 0 )
+ m_dropTarget->Register(m_hWnd);
+}
+
+#endif // wxUSE_DRAG_AND_DROP
+
+// old style file-manager drag&drop support: we retain the old-style
+// DragAcceptFiles in parallel with SetDropTarget.
+void wxWindow::DragAcceptFiles(bool accept)
+{
+ HWND hWnd = GetHwnd();
+ if ( hWnd )
+ ::DragAcceptFiles(hWnd, (BOOL)accept);
+}
+
+// ----------------------------------------------------------------------------
+// tooltips
+// ----------------------------------------------------------------------------
+
+#if wxUSE_TOOLTIPS
+
+void wxWindow::DoSetToolTip(wxToolTip *tooltip)
+{
+ wxWindowBase::DoSetToolTip(tooltip);
+
+ if ( m_tooltip )
+ m_tooltip->SetWindow(this);
+}
+
+#endif // wxUSE_TOOLTIPS
+
+// ---------------------------------------------------------------------------
+// moving and resizing
+// ---------------------------------------------------------------------------
+
+// Get total size
+void wxWindow::DoGetSize(int *x, int *y) const
+{
+ HWND hWnd = GetHwnd();
+ RECT rect;
+#ifdef __WIN16__
+ ::GetWindowRect(hWnd, &rect);
+#else
+ if ( !::GetWindowRect(hWnd, &rect) )
+ {
+ wxLogLastError(_T("GetWindowRect"));
+ }
+#endif
+ if ( x )
+ *x = rect.right - rect.left;
+ if ( y )
+ *y = rect.bottom - rect.top;
+}
+
+void wxWindow::DoGetPosition(int *x, int *y) const
+{
+ HWND hWnd = GetHwnd();
+
+ RECT rect;
+ GetWindowRect(hWnd, &rect);
+
+ POINT point;
+ point.x = rect.left;
+ point.y = rect.top;
+
+ // we do the adjustments with respect to the parent only for the "real"
+ // children, not for the dialogs/frames
+ if ( !IsTopLevel() )
+ {
+ HWND hParentWnd = 0;
+ wxWindow *parent = GetParent();
+ if ( parent )
+ hParentWnd = GetWinHwnd(parent);
+
+ // Since we now have the absolute screen coords, if there's a parent we
+ // must subtract its top left corner
+ if ( hParentWnd )
+ {
+ ::ScreenToClient(hParentWnd, &point);
+ }
+
+ if ( parent )
+ {
+ // We may be faking the client origin. So a window that's really at (0,
+ // 30) may appear (to wxWin apps) to be at (0, 0).
+ wxPoint pt(parent->GetClientAreaOrigin());
+ point.x -= pt.x;
+ point.y -= pt.y;
+ }
+ }
+
+ if ( x )
+ *x = point.x;
+ if ( y )
+ *y = point.y;
+}
+
+void wxWindow::DoScreenToClient(int *x, int *y) const
+{
+ POINT pt;
+ if ( x )
+ pt.x = *x;
+ if ( y )
+ pt.y = *y;
+
+ HWND hWnd = GetHwnd();
+ ::ScreenToClient(hWnd, &pt);
+
+ if ( x )
+ *x = pt.x;
+ if ( y )
+ *y = pt.y;
+}
+
+void wxWindow::DoClientToScreen(int *x, int *y) const
+{
+ POINT pt;
+ if ( x )
+ pt.x = *x;
+ if ( y )
+ pt.y = *y;
+
+ HWND hWnd = GetHwnd();
+ ::ClientToScreen(hWnd, &pt);
+
+ if ( x )
+ *x = pt.x;
+ if ( y )
+ *y = pt.y;
+}
+
+// Get size *available for subwindows* i.e. excluding menu bar etc.
+void wxWindow::DoGetClientSize(int *x, int *y) const
+{
+ HWND hWnd = GetHwnd();
+ RECT rect;
+ ::GetClientRect(hWnd, &rect);
+ if ( x )
+ *x = rect.right;
+ if ( y )
+ *y = rect.bottom;
+}
+
+void wxWindow::DoMoveWindow(int x, int y, int width, int height)
+{
+ if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) )
+ {
+ wxLogLastError(wxT("MoveWindow"));
+ }
+}
+
+// set the size of the window: if the dimensions are positive, just use them,
+// but if any of them is equal to -1, it means that we must find the value for
+// it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
+// which case -1 is a valid value for x and y)
+//
+// If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
+// the width/height to best suit our contents, otherwise we reuse the current
+// width/height
+void wxWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags)
+{
+ // get the current size and position...
+ int currentX, currentY;
+ GetPosition(¤tX, ¤tY);
+ int currentW,currentH;
+ GetSize(¤tW, ¤tH);
+
+ // ... and don't do anything (avoiding flicker) if it's already ok
+ if ( x == currentX && y == currentY &&
+ width == currentW && height == currentH )
+ {
+ return;
+ }
+
+ if ( x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
+ x = currentX;
+ if ( y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
+ y = currentY;
+
+ AdjustForParentClientOrigin(x, y, sizeFlags);
+
+ wxSize size(-1, -1);
+ if ( width == -1 )
+ {
+ if ( sizeFlags & wxSIZE_AUTO_WIDTH )
+ {
+ size = DoGetBestSize();
+ width = size.x;
+ }
+ else
+ {
+ // just take the current one
+ width = currentW;
+ }
+ }
+
+ if ( height == -1 )
+ {
+ if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
+ {
+ if ( size.x == -1 )
+ {
+ size = DoGetBestSize();
+ }
+ //else: already called DoGetBestSize() above
+
+ height = size.y;
+ }
+ else
+ {
+ // just take the current one
+ height = currentH;
+ }
+ }
+
+ DoMoveWindow(x, y, width, height);
+}
+
+void wxWindow::DoSetClientSize(int width, int height)
+{
+ wxWindow *parent = GetParent();
+ HWND hWnd = GetHwnd();
+ HWND hParentWnd = (HWND) 0;
+ if ( parent )
+ hParentWnd = (HWND) parent->GetHWND();
+
+ RECT rect;
+ ::GetClientRect(hWnd, &rect);
+
+ RECT rect2;
+ GetWindowRect(hWnd, &rect2);
+
+ // Find the difference between the entire window (title bar and all)
+ // and the client area; add this to the new client size to move the
+ // window
+ int actual_width = rect2.right - rect2.left - rect.right + width;
+ int actual_height = rect2.bottom - rect2.top - rect.bottom + height;
+
+ // If there's a parent, must subtract the parent's top left corner
+ // since MoveWindow moves relative to the parent
+
+ POINT point;
+ point.x = rect2.left;
+ point.y = rect2.top;
+ if ( parent )
+ {
+ ::ScreenToClient(hParentWnd, &point);
+ }
+
+ DoMoveWindow(point.x, point.y, actual_width, actual_height);
+
+ wxSizeEvent event(wxSize(width, height), m_windowId);
+ event.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(event);
+}
+
+// For implementation purposes - sometimes decorations make the client area
+// smaller
+wxPoint wxWindow::GetClientAreaOrigin() const
+{
+ return wxPoint(0, 0);
+}
+
+// Makes an adjustment to the window position (for example, a frame that has
+// a toolbar that it manages itself).
+void wxWindow::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags)
+{
+ // don't do it for the dialogs/frames - they float independently of their
+ // parent
+ if ( !IsTopLevel() )
+ {
+ wxWindow *parent = GetParent();
+ if ( !(sizeFlags & wxSIZE_NO_ADJUSTMENTS) && parent )
+ {
+ wxPoint pt(parent->GetClientAreaOrigin());
+ x += pt.x; y += pt.y;
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// text metrics
+// ---------------------------------------------------------------------------
+
+int wxWindow::GetCharHeight() const
+{
+ return wxGetTextMetrics(this).tmHeight;
+}
+
+int wxWindow::GetCharWidth() const
+{
+ // +1 is needed because Windows apparently adds it when calculating the
+ // dialog units size in pixels
+#if wxDIALOG_UNIT_COMPATIBILITY
+ return wxGetTextMetrics(this).tmAveCharWidth ;
+#else
+ return wxGetTextMetrics(this).tmAveCharWidth + 1;
+#endif
+}
+
+void wxWindow::GetTextExtent(const wxString& string,
+ int *x, int *y,
+ int *descent, int *externalLeading,
+ const wxFont *theFont) const
+{
+ const wxFont *fontToUse = theFont;
+ if ( !fontToUse )
+ fontToUse = &m_font;
+
+ HWND hWnd = GetHwnd();
+ HDC dc = ::GetDC(hWnd);
+
+ HFONT fnt = 0;
+ HFONT hfontOld = 0;
+ if ( fontToUse && fontToUse->Ok() )
+ {
+ fnt = (HFONT)((wxFont *)fontToUse)->GetResourceHandle(); // const_cast
+ if ( fnt )
+ hfontOld = (HFONT)SelectObject(dc,fnt);
+ }
+
+ SIZE sizeRect;
+ TEXTMETRIC tm;
+ GetTextExtentPoint(dc, string, (int)string.Length(), &sizeRect);
+ GetTextMetrics(dc, &tm);
+
+ if ( fontToUse && fnt && hfontOld )
+ SelectObject(dc, hfontOld);
+
+ ReleaseDC(hWnd, dc);
+
+ if ( x )
+ *x = sizeRect.cx;
+ if ( y )
+ *y = sizeRect.cy;
+ if ( descent )
+ *descent = tm.tmDescent;
+ if ( externalLeading )
+ *externalLeading = tm.tmExternalLeading;
+}
+
+#if wxUSE_CARET && WXWIN_COMPATIBILITY
+// ---------------------------------------------------------------------------
+// Caret manipulation
+// ---------------------------------------------------------------------------
+
+void wxWindow::CreateCaret(int w, int h)
+{
+ SetCaret(new wxCaret(this, w, h));
+}
+
+void wxWindow::CreateCaret(const wxBitmap *WXUNUSED(bitmap))
+{
+ wxFAIL_MSG("not implemented");
+}
+
+void wxWindow::ShowCaret(bool show)
+{
+ wxCHECK_RET( m_caret, "no caret to show" );
+
+ m_caret->Show(show);
+}
+
+void wxWindow::DestroyCaret()
+{
+ SetCaret(NULL);
+}
+
+void wxWindow::SetCaretPos(int x, int y)
+{
+ wxCHECK_RET( m_caret, "no caret to move" );
+
+ m_caret->Move(x, y);
+}
+
+void wxWindow::GetCaretPos(int *x, int *y) const
+{
+ wxCHECK_RET( m_caret, "no caret to get position of" );
+
+ m_caret->GetPosition(x, y);
+}
+#endif // wxUSE_CARET
+
+// ---------------------------------------------------------------------------
+// popup menu
+// ---------------------------------------------------------------------------
+
+bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
+{
+ menu->SetInvokingWindow(this);
+ menu->UpdateUI();
+
+ HWND hWnd = GetHwnd();
+ HMENU hMenu = GetHmenuOf(menu);
+ POINT point;
+ point.x = x;
+ point.y = y;
+ ::ClientToScreen(hWnd, &point);
+ wxCurrentPopupMenu = menu;
+ ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL);
+ wxYieldIfNeeded();
+ wxCurrentPopupMenu = NULL;
+
+ menu->SetInvokingWindow(NULL);
+
+ return TRUE;
+}
+
+// ===========================================================================
+// pre/post message processing
+// ===========================================================================
+
+long wxWindow::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
+{
+ if ( m_oldWndProc )
+ return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
+ else
+ return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
+}
+
+bool wxWindow::MSWProcessMessage(WXMSG* pMsg)
+{
+ if ( m_hWnd != 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL) )
+ {
+ // intercept dialog navigation keys
+ MSG *msg = (MSG *)pMsg;
+
+ // here we try to do all the job which ::IsDialogMessage() usually does
+ // internally
+#if 1
+ bool bProcess = TRUE;
+ if ( msg->message != WM_KEYDOWN )
+ bProcess = FALSE;
+
+ if ( bProcess && (HIWORD(msg->lParam) & KF_ALTDOWN) == KF_ALTDOWN )
+ bProcess = FALSE;
+
+ if ( bProcess )
+ {
+ bool bCtrlDown = wxIsCtrlDown();
+ bool bShiftDown = wxIsShiftDown();
+
+ // WM_GETDLGCODE: ask the control if it wants the key for itself,
+ // don't process it if it's the case (except for Ctrl-Tab/Enter
+ // combinations which are always processed)
+ LONG lDlgCode = 0;
+ if ( !bCtrlDown )
+ {
+ lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
+ }
+
+ bool bForward = TRUE,
+ bWindowChange = FALSE;
+
+ switch ( msg->wParam )
+ {
+ case VK_TAB:
+ // assume that nobody wants Shift-TAB for himself - if we
+ // don't do it there is no easy way for a control to grab
+ // TABs but still let Shift-TAB work as navugation key
+ if ( (lDlgCode & DLGC_WANTTAB) && !bShiftDown ) {
+ bProcess = FALSE;
+ }
+ else {
+ // Ctrl-Tab cycles thru notebook pages
+ bWindowChange = bCtrlDown;
+ bForward = !bShiftDown;
+ }
+ break;
+
+ case VK_UP:
+ case VK_LEFT:
+ if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
+ bProcess = FALSE;
+ else
+ bForward = FALSE;
+ break;
+
+ case VK_DOWN:
+ case VK_RIGHT:
+ if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
+ bProcess = FALSE;
+ break;
+
+ case VK_RETURN:
+ {
+ if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown )
+ {
+ // control wants to process Enter itself, don't
+ // call IsDialogMessage() which would interpret
+ // it
+ return FALSE;
+ }
+ else if ( lDlgCode & DLGC_BUTTON )
+ {
+ // let IsDialogMessage() handle this for all
+ // buttons except the owner-drawn ones which it
+ // just seems to ignore
+ long style = ::GetWindowLong(msg->hwnd, GWL_STYLE);
+ if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW )
+ {
+ // emulate the button click
+ wxWindow *btn = wxFindWinFromHandle((WXHWND)msg->hwnd);
+ if ( btn )
+ btn->MSWCommand(BN_CLICKED, 0 /* unused */);
+ }
+
+ bProcess = FALSE;
+ }
+ else
+ {
+ wxPanel *panel = wxDynamicThisCast(this, wxPanel);
+ wxButton *btn = NULL;
+ if ( panel )
+ {
+ // panel may have a default button which should
+ // be activated by Enter
+ btn = panel->GetDefaultItem();
+ }
+
+ if ( btn && btn->IsEnabled() )
+ {
+ // if we do have a default button, do press it
+ btn->MSWCommand(BN_CLICKED, 0 /* unused */);
+
+ return TRUE;
+ }
+ // else: but if it does not it makes sense to make
+ // it work like a TAB - and that's what we do.
+ // Note that Ctrl-Enter always works this way.
+ }
+ }
+ break;
+
+ default:
+ bProcess = FALSE;
+ }
+
+ if ( bProcess )
+ {
+ wxNavigationKeyEvent event;
+ event.SetDirection(bForward);
+ event.SetWindowChange(bWindowChange);
+ event.SetEventObject(this);
+
+ if ( GetEventHandler()->ProcessEvent(event) )
+ {
+ wxButton *btn = wxDynamicCast(FindFocus(), wxButton);
+ if ( btn )
+ {
+ // the button which has focus should be default
+ btn->SetDefault();
+ }
+
+ return TRUE;
+ }
+ }
+ }
+#else
+ // let ::IsDialogMessage() do almost everything and handle just the
+ // things it doesn't here: Ctrl-TAB for switching notebook pages
+ if ( msg->message == WM_KEYDOWN )
+ {
+ // don't process system keys here
+ if ( !(HIWORD(msg->lParam) & KF_ALTDOWN) )
+ {
+ if ( (msg->wParam == VK_TAB) && wxIsCtrlDown() )
+ {
+ // find the first notebook parent and change its page
+ wxWindow *win = this;
+ wxNotebook *nbook = NULL;
+ while ( win && !nbook )
+ {
+ nbook = wxDynamicCast(win, wxNotebook);
+ win = win->GetParent();
+ }
+
+ if ( nbook )
+ {
+ bool forward = !wxIsShiftDown();
+
+ nbook->AdvanceSelection(forward);
+ }
+ }
+ }
+ }
+#endif // 0
+
+ if ( ::IsDialogMessage(GetHwnd(), msg) )
+ {
+ // IsDialogMessage() did something...
+ return TRUE;
+ }
+ }
+
+#if wxUSE_TOOLTIPS
+ if ( m_tooltip )