This keyword is not expanded by Git which means it's not replaced with the correct revision value in the releases made using git-based scripts and it's confusing to have lines with unexpanded "$Id$" in the released files. As expanding them with Git is not that simple (it could be done with git archive and export-subst attribute) and there are not many benefits in having them in the first place, just remove all these lines. If nothing else, this will make an eventual transition to Git simpler. Closes #14487. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1495 lines
41 KiB
C++
1495 lines
41 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/univ/winuniv.cpp
|
|
// Purpose: implementation of extra wxWindow methods for wxUniv port
|
|
// Author: Vadim Zeitlin
|
|
// Modified by:
|
|
// Created: 06.08.00
|
|
// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
|
|
// Licence: wxWindows licence
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ===========================================================================
|
|
// declarations
|
|
// ===========================================================================
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// headers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#include "wx/window.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/app.h"
|
|
#include "wx/dcclient.h"
|
|
#include "wx/dcmemory.h"
|
|
#include "wx/event.h"
|
|
#include "wx/scrolbar.h"
|
|
#include "wx/menu.h"
|
|
#include "wx/frame.h"
|
|
#include "wx/log.h"
|
|
#include "wx/button.h"
|
|
#endif // WX_PRECOMP
|
|
|
|
#include "wx/univ/colschem.h"
|
|
#include "wx/univ/renderer.h"
|
|
#include "wx/univ/theme.h"
|
|
|
|
|
|
#if wxUSE_CARET
|
|
#include "wx/caret.h"
|
|
#endif // wxUSE_CARET
|
|
|
|
#if wxDEBUG_LEVEL >= 2
|
|
// turn Refresh() debugging on/off
|
|
#define WXDEBUG_REFRESH
|
|
#endif
|
|
|
|
#if defined(WXDEBUG_REFRESH) && defined(__WXMSW__) && !defined(__WXMICROWIN__)
|
|
#include "wx/msw/private.h"
|
|
#endif
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// scrollbars class
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// This is scrollbar class used to implement wxWindow's "built-in" scrollbars;
|
|
// unlike the standard wxScrollBar class, this one is positioned outside of its
|
|
// parent's client area
|
|
class wxWindowScrollBar : public wxScrollBar
|
|
{
|
|
public:
|
|
wxWindowScrollBar(wxWindow *parent,
|
|
wxWindowID id,
|
|
const wxPoint& pos = wxDefaultPosition,
|
|
const wxSize& size = wxDefaultSize,
|
|
long style = wxSB_HORIZONTAL)
|
|
: wxScrollBar(parent, id, pos, size, style)
|
|
{
|
|
}
|
|
|
|
virtual bool CanBeOutsideClientArea() const { return true; }
|
|
};
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// event tables
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// we can't use wxWindowNative here as it won't be expanded inside the macro
|
|
#if defined(__WXMSW__)
|
|
IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowMSW)
|
|
#elif defined(__WXGTK__)
|
|
IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowGTK)
|
|
#elif defined(__WXOSX_OR_COCOA__)
|
|
IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowMac)
|
|
#elif defined(__WXDFB__)
|
|
IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowDFB)
|
|
#elif defined(__WXX11__)
|
|
IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowX11)
|
|
#elif defined(__WXPM__)
|
|
IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowOS2)
|
|
#endif
|
|
|
|
BEGIN_EVENT_TABLE(wxWindow, wxWindowNative)
|
|
EVT_SIZE(wxWindow::OnSize)
|
|
|
|
#if wxUSE_ACCEL || wxUSE_MENUS
|
|
EVT_KEY_DOWN(wxWindow::OnKeyDown)
|
|
#endif // wxUSE_ACCEL
|
|
|
|
#if wxUSE_MENUS
|
|
EVT_CHAR(wxWindow::OnChar)
|
|
EVT_KEY_UP(wxWindow::OnKeyUp)
|
|
#endif // wxUSE_MENUS
|
|
|
|
EVT_PAINT(wxWindow::OnPaint)
|
|
EVT_NC_PAINT(wxWindow::OnNcPaint)
|
|
EVT_ERASE_BACKGROUND(wxWindow::OnErase)
|
|
END_EVENT_TABLE()
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// creation
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void wxWindow::Init()
|
|
{
|
|
#if wxUSE_SCROLLBAR
|
|
m_scrollbarVert =
|
|
m_scrollbarHorz = NULL;
|
|
#endif // wxUSE_SCROLLBAR
|
|
|
|
m_isCurrent = false;
|
|
|
|
m_renderer = wxTheme::Get()->GetRenderer();
|
|
|
|
m_oldSize.x = wxDefaultCoord;
|
|
m_oldSize.y = wxDefaultCoord;
|
|
}
|
|
|
|
bool wxWindow::Create(wxWindow *parent,
|
|
wxWindowID id,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxString& name)
|
|
{
|
|
// Get default border
|
|
wxBorder border = GetBorder(style);
|
|
style &= ~wxBORDER_MASK;
|
|
style |= border;
|
|
|
|
long actualStyle = style;
|
|
|
|
// we add wxCLIP_CHILDREN to get the same ("natural") behaviour under MSW
|
|
// as under the other platforms
|
|
actualStyle |= wxCLIP_CHILDREN;
|
|
|
|
actualStyle &= ~wxVSCROLL;
|
|
actualStyle &= ~wxHSCROLL;
|
|
|
|
#ifdef __WXMSW__
|
|
// without this, borders (non-client areas in general) are not repainted
|
|
// correctly when resizing; apparently, native NC areas are fully repainted
|
|
// even without this style by MSW, but wxUniv implements client area
|
|
// itself, so it doesn't work correctly for us
|
|
//
|
|
// FIXME: this is very expensive, we need to fix the (commented-out) code
|
|
// in OnSize() instead
|
|
actualStyle |= wxFULL_REPAINT_ON_RESIZE;
|
|
#endif
|
|
|
|
if ( !wxWindowNative::Create(parent, id, pos, size, actualStyle, name) )
|
|
return false;
|
|
|
|
// Set full style again, including those we didn't want present
|
|
// when calling the base window Create().
|
|
wxWindowBase::SetWindowStyleFlag(style);
|
|
|
|
// if we allow or should always have a vertical scrollbar, make it
|
|
if ( style & wxVSCROLL || style & wxALWAYS_SHOW_SB )
|
|
{
|
|
#if wxUSE_TWO_WINDOWS
|
|
SetInsertIntoMain( true );
|
|
#endif
|
|
#if wxUSE_SCROLLBAR
|
|
m_scrollbarVert = new wxWindowScrollBar(this, wxID_ANY,
|
|
wxDefaultPosition, wxDefaultSize,
|
|
wxSB_VERTICAL);
|
|
#endif // wxUSE_SCROLLBAR
|
|
#if wxUSE_TWO_WINDOWS
|
|
SetInsertIntoMain( false );
|
|
#endif
|
|
}
|
|
|
|
// if we should allow a horizontal scrollbar, make it
|
|
if ( style & wxHSCROLL )
|
|
{
|
|
#if wxUSE_TWO_WINDOWS
|
|
SetInsertIntoMain( true );
|
|
#endif
|
|
#if wxUSE_SCROLLBAR
|
|
m_scrollbarHorz = new wxWindowScrollBar(this, wxID_ANY,
|
|
wxDefaultPosition, wxDefaultSize,
|
|
wxSB_HORIZONTAL);
|
|
#endif // wxUSE_SCROLLBAR
|
|
#if wxUSE_TWO_WINDOWS
|
|
SetInsertIntoMain( false );
|
|
#endif
|
|
}
|
|
|
|
#if wxUSE_SCROLLBAR
|
|
if (m_scrollbarHorz || m_scrollbarVert)
|
|
{
|
|
// position it/them
|
|
PositionScrollbars();
|
|
}
|
|
#endif // wxUSE_SCROLLBAR
|
|
|
|
return true;
|
|
}
|
|
|
|
wxWindow::~wxWindow()
|
|
{
|
|
SendDestroyEvent();
|
|
|
|
#if wxUSE_SCROLLBAR
|
|
// clear pointers to scrollbar before deleting the children: they are
|
|
// children and so will be deleted by DestroyChildren() call below and if
|
|
// any code using the scrollbars would be called in the process or from
|
|
// ~wxWindowBase, the app would crash:
|
|
m_scrollbarVert = m_scrollbarHorz = NULL;
|
|
#endif
|
|
|
|
// we have to destroy our children before we're destroyed because our
|
|
// children suppose that we're of type wxWindow, not just wxWindowNative,
|
|
// and so bad things may happen if they're deleted from the base class dtor
|
|
// as by then we're not a wxWindow any longer and wxUniv-specific virtual
|
|
// functions can't be called
|
|
DestroyChildren();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// background pixmap
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void wxWindow::SetBackground(const wxBitmap& bitmap,
|
|
int alignment,
|
|
wxStretch stretch)
|
|
{
|
|
m_bitmapBg = bitmap;
|
|
m_alignBgBitmap = alignment;
|
|
m_stretchBgBitmap = stretch;
|
|
}
|
|
|
|
const wxBitmap& wxWindow::GetBackgroundBitmap(int *alignment,
|
|
wxStretch *stretch) const
|
|
{
|
|
if ( m_bitmapBg.IsOk() )
|
|
{
|
|
if ( alignment )
|
|
*alignment = m_alignBgBitmap;
|
|
if ( stretch )
|
|
*stretch = m_stretchBgBitmap;
|
|
}
|
|
|
|
return m_bitmapBg;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// painting
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// the event handlers executed when the window must be repainted
|
|
void wxWindow::OnNcPaint(wxNcPaintEvent& WXUNUSED(event))
|
|
{
|
|
if ( m_renderer )
|
|
{
|
|
// get the window rect
|
|
wxRect rect(GetSize());
|
|
|
|
#if wxUSE_SCROLLBAR
|
|
// if the scrollbars are outside the border, we must adjust the rect to
|
|
// exclude them
|
|
if ( !m_renderer->AreScrollbarsInsideBorder() )
|
|
{
|
|
wxScrollBar *scrollbar = GetScrollbar(wxVERTICAL);
|
|
if ( scrollbar )
|
|
rect.width -= scrollbar->GetSize().x;
|
|
|
|
scrollbar = GetScrollbar(wxHORIZONTAL);
|
|
if ( scrollbar )
|
|
rect.height -= scrollbar->GetSize().y;
|
|
}
|
|
#endif // wxUSE_SCROLLBAR
|
|
|
|
// get the DC and draw the border on it
|
|
wxWindowDC dc(this);
|
|
DoDrawBorder(dc, rect);
|
|
}
|
|
}
|
|
|
|
void wxWindow::OnPaint(wxPaintEvent& event)
|
|
{
|
|
if ( !m_renderer )
|
|
{
|
|
// it is a native control which paints itself
|
|
event.Skip();
|
|
}
|
|
else
|
|
{
|
|
// get the DC to use and create renderer on it
|
|
wxPaintDC dc(this);
|
|
wxControlRenderer renderer(this, dc, m_renderer);
|
|
|
|
// draw the control
|
|
DoDraw(&renderer);
|
|
}
|
|
}
|
|
|
|
// the event handler executed when the window background must be painted
|
|
void wxWindow::OnErase(wxEraseEvent& event)
|
|
{
|
|
if ( !m_renderer )
|
|
{
|
|
event.Skip();
|
|
|
|
return;
|
|
}
|
|
|
|
DoDrawBackground(*event.GetDC());
|
|
|
|
#if wxUSE_SCROLLBAR
|
|
// if we have both scrollbars, we also have a square in the corner between
|
|
// them which we must paint
|
|
if ( m_scrollbarVert && m_scrollbarHorz )
|
|
{
|
|
wxSize size = GetSize();
|
|
wxRect rectClient = GetClientRect(),
|
|
rectBorder = m_renderer->GetBorderDimensions(GetBorder());
|
|
|
|
wxRect rectCorner;
|
|
rectCorner.x = rectClient.GetRight() + 1;
|
|
rectCorner.y = rectClient.GetBottom() + 1;
|
|
rectCorner.SetRight(size.x - rectBorder.width);
|
|
rectCorner.SetBottom(size.y - rectBorder.height);
|
|
|
|
if ( GetUpdateRegion().Contains(rectCorner) )
|
|
{
|
|
m_renderer->DrawScrollCorner(*event.GetDC(), rectCorner);
|
|
}
|
|
}
|
|
#endif // wxUSE_SCROLLBAR
|
|
}
|
|
|
|
bool wxWindow::DoDrawBackground(wxDC& dc)
|
|
{
|
|
wxRect rect;
|
|
|
|
wxSize size = GetSize(); // Why not GetClientSize() ?
|
|
rect.x = 0;
|
|
rect.y = 0;
|
|
rect.width = size.x;
|
|
rect.height = size.y;
|
|
|
|
wxWindow * const parent = GetParent();
|
|
if ( HasTransparentBackground() && !UseBgCol() && parent )
|
|
{
|
|
// DirectFB paints the parent first, then its child windows, so by
|
|
// the time this code is called, parent's background was already
|
|
// drawn and there's no point in (imperfectly!) duplicating the work
|
|
// here:
|
|
#ifndef __WXDFB__
|
|
wxASSERT( !IsTopLevel() );
|
|
|
|
wxPoint pos = GetPosition();
|
|
|
|
AdjustForParentClientOrigin( pos.x, pos.y, 0 );
|
|
|
|
// Adjust DC logical origin
|
|
wxCoord org_x, org_y, x, y;
|
|
dc.GetLogicalOrigin( &org_x, &org_y );
|
|
x = org_x + pos.x;
|
|
y = org_y + pos.y;
|
|
dc.SetLogicalOrigin( x, y );
|
|
|
|
// Adjust draw rect
|
|
rect.x = pos.x;
|
|
rect.y = pos.y;
|
|
|
|
// Let parent draw the background
|
|
parent->EraseBackground( dc, rect );
|
|
|
|
// Restore DC logical origin
|
|
dc.SetLogicalOrigin( org_x, org_y );
|
|
#endif // !__WXDFB__
|
|
}
|
|
else
|
|
{
|
|
// Draw background ourselves
|
|
EraseBackground( dc, rect );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void wxWindow::EraseBackground(wxDC& dc, const wxRect& rect)
|
|
{
|
|
if ( GetBackgroundBitmap().IsOk() )
|
|
{
|
|
// Get the bitmap and the flags
|
|
int alignment;
|
|
wxStretch stretch;
|
|
wxBitmap bmp = GetBackgroundBitmap(&alignment, &stretch);
|
|
wxControlRenderer::DrawBitmap(dc, bmp, rect, alignment, stretch);
|
|
}
|
|
else
|
|
{
|
|
// Just fill it with bg colour if no bitmap
|
|
|
|
m_renderer->DrawBackground(dc, wxTHEME_BG_COLOUR(this),
|
|
rect, GetStateFlags());
|
|
}
|
|
}
|
|
|
|
void wxWindow::DoDrawBorder(wxDC& dc, const wxRect& rect)
|
|
{
|
|
// draw outline unless the update region is enitrely inside it in which
|
|
// case we don't need to do it
|
|
#if 0 // doesn't seem to work, why?
|
|
if ( wxRegion(rect).Contains(GetUpdateRegion().GetBox()) != wxInRegion )
|
|
#endif
|
|
{
|
|
m_renderer->DrawBorder(dc, GetBorder(), rect, GetStateFlags());
|
|
}
|
|
}
|
|
|
|
void wxWindow::DoDraw(wxControlRenderer * WXUNUSED(renderer))
|
|
{
|
|
}
|
|
|
|
void wxWindow::Refresh(bool eraseBackground, const wxRect *rect)
|
|
{
|
|
wxRect rectClient; // the same rectangle in client coordinates
|
|
wxPoint origin = GetClientAreaOrigin();
|
|
|
|
wxSize size = GetClientSize();
|
|
|
|
if ( rect )
|
|
{
|
|
// the rectangle passed as argument is in client coordinates
|
|
rectClient = *rect;
|
|
|
|
// don't refresh anything beyond the client area (scrollbars for
|
|
// example)
|
|
if ( rectClient.GetRight() > size.x )
|
|
rectClient.SetRight(size.x);
|
|
if ( rectClient.GetBottom() > size.y )
|
|
rectClient.SetBottom(size.y);
|
|
|
|
}
|
|
else // refresh the entire client area
|
|
{
|
|
// x,y is already set to 0 by default
|
|
rectClient.SetSize(size);
|
|
}
|
|
|
|
// convert refresh rectangle to window coordinates:
|
|
wxRect rectWin(rectClient);
|
|
rectWin.Offset(origin);
|
|
|
|
// debugging helper
|
|
#ifdef WXDEBUG_REFRESH
|
|
static bool s_refreshDebug = false;
|
|
if ( s_refreshDebug )
|
|
{
|
|
wxWindowDC dc(this);
|
|
dc.SetBrush(*wxCYAN_BRUSH);
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
|
dc.DrawRectangle(rectWin);
|
|
|
|
// under Unix we use "--sync" X option for this
|
|
#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
|
|
::GdiFlush();
|
|
::Sleep(200);
|
|
#endif // __WXMSW__
|
|
}
|
|
#endif // WXDEBUG_REFRESH
|
|
|
|
wxWindowNative::Refresh(eraseBackground, &rectWin);
|
|
|
|
// Refresh all sub controls if any.
|
|
wxWindowList& children = GetChildren();
|
|
for ( wxWindowList::iterator i = children.begin(); i != children.end(); ++i )
|
|
{
|
|
wxWindow *child = *i;
|
|
// only refresh subcontrols if they are visible:
|
|
if ( child->IsTopLevel() || !child->IsShown() || child->IsFrozen() )
|
|
continue;
|
|
|
|
// ...and when the subcontrols are in the update region:
|
|
wxRect childrect(child->GetRect());
|
|
childrect.Intersect(rectClient);
|
|
if ( childrect.IsEmpty() )
|
|
continue;
|
|
|
|
// refresh the subcontrol now:
|
|
childrect.Offset(-child->GetPosition());
|
|
// NB: We must call wxWindowNative version because we need to refresh
|
|
// the entire control, not just its client area, and this is why we
|
|
// don't account for child client area origin here neither. Also
|
|
// note that we don't pass eraseBackground to the child, but use
|
|
// true instead: this is because we can't be sure that
|
|
// eraseBackground=false is safe for children as well and not only
|
|
// for the parent.
|
|
child->wxWindowNative::Refresh(eraseBackground, &childrect);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// state flags
|
|
// ----------------------------------------------------------------------------
|
|
|
|
bool wxWindow::Enable(bool enable)
|
|
{
|
|
if ( !wxWindowNative::Enable(enable) )
|
|
return false;
|
|
|
|
// disabled window can't keep focus
|
|
if ( FindFocus() == this && GetParent() != NULL )
|
|
{
|
|
GetParent()->SetFocus();
|
|
}
|
|
|
|
if ( m_renderer )
|
|
{
|
|
// a window with renderer is drawn by ourselves and it has to be
|
|
// refreshed to reflect its new status
|
|
Refresh();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxWindow::IsFocused() const
|
|
{
|
|
return FindFocus() == this;
|
|
}
|
|
|
|
bool wxWindow::IsPressed() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool wxWindow::IsDefault() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool wxWindow::IsCurrent() const
|
|
{
|
|
return m_isCurrent;
|
|
}
|
|
|
|
bool wxWindow::SetCurrent(bool doit)
|
|
{
|
|
if ( doit == m_isCurrent )
|
|
return false;
|
|
|
|
m_isCurrent = doit;
|
|
|
|
if ( CanBeHighlighted() )
|
|
Refresh();
|
|
|
|
return true;
|
|
}
|
|
|
|
int wxWindow::GetStateFlags() const
|
|
{
|
|
int flags = 0;
|
|
if ( !IsEnabled() )
|
|
flags |= wxCONTROL_DISABLED;
|
|
|
|
// the following states are only possible if our application is active - if
|
|
// it is not, even our default/focused controls shouldn't appear as such
|
|
if ( wxTheApp->IsActive() )
|
|
{
|
|
if ( IsCurrent() )
|
|
flags |= wxCONTROL_CURRENT;
|
|
if ( IsFocused() )
|
|
flags |= wxCONTROL_FOCUSED;
|
|
if ( IsPressed() )
|
|
flags |= wxCONTROL_PRESSED;
|
|
if ( IsDefault() )
|
|
flags |= wxCONTROL_ISDEFAULT;
|
|
}
|
|
|
|
return flags;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// size
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void wxWindow::OnSize(wxSizeEvent& event)
|
|
{
|
|
event.Skip();
|
|
|
|
#if wxUSE_SCROLLBAR
|
|
if ( m_scrollbarVert || m_scrollbarHorz )
|
|
{
|
|
PositionScrollbars();
|
|
}
|
|
#endif // wxUSE_SCROLLBAR
|
|
|
|
#if 0 // ndef __WXMSW__
|
|
// Refresh the area (strip) previously occupied by the border
|
|
|
|
if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) && IsShown() )
|
|
{
|
|
// This code assumes that wxSizeEvent.GetSize() returns
|
|
// the area of the entire window, not just the client
|
|
// area.
|
|
wxSize newSize = event.GetSize();
|
|
|
|
if (m_oldSize.x == wxDefaultCoord && m_oldSize.y == wxDefaultCoord)
|
|
{
|
|
m_oldSize = newSize;
|
|
return;
|
|
}
|
|
|
|
if (HasFlag( wxSIMPLE_BORDER ))
|
|
{
|
|
if (newSize.y > m_oldSize.y)
|
|
{
|
|
wxRect rect;
|
|
rect.x = 0;
|
|
rect.width = m_oldSize.x;
|
|
rect.y = m_oldSize.y-2;
|
|
rect.height = 1;
|
|
Refresh( true, &rect );
|
|
}
|
|
else if (newSize.y < m_oldSize.y)
|
|
{
|
|
wxRect rect;
|
|
rect.y = newSize.y;
|
|
rect.x = 0;
|
|
rect.height = 1;
|
|
rect.width = newSize.x;
|
|
wxWindowNative::Refresh( true, &rect );
|
|
}
|
|
|
|
if (newSize.x > m_oldSize.x)
|
|
{
|
|
wxRect rect;
|
|
rect.y = 0;
|
|
rect.height = m_oldSize.y;
|
|
rect.x = m_oldSize.x-2;
|
|
rect.width = 1;
|
|
Refresh( true, &rect );
|
|
}
|
|
else if (newSize.x < m_oldSize.x)
|
|
{
|
|
wxRect rect;
|
|
rect.x = newSize.x;
|
|
rect.y = 0;
|
|
rect.width = 1;
|
|
rect.height = newSize.y;
|
|
wxWindowNative::Refresh( true, &rect );
|
|
}
|
|
}
|
|
else
|
|
if (HasFlag( wxSUNKEN_BORDER ) || HasFlag( wxRAISED_BORDER ) || HasFlag( wxBORDER_THEME ))
|
|
{
|
|
if (newSize.y > m_oldSize.y)
|
|
{
|
|
wxRect rect;
|
|
rect.x = 0;
|
|
rect.width = m_oldSize.x;
|
|
rect.y = m_oldSize.y-4;
|
|
rect.height = 2;
|
|
Refresh( true, &rect );
|
|
}
|
|
else if (newSize.y < m_oldSize.y)
|
|
{
|
|
wxRect rect;
|
|
rect.y = newSize.y;
|
|
rect.x = 0;
|
|
rect.height = 2;
|
|
rect.width = newSize.x;
|
|
wxWindowNative::Refresh( true, &rect );
|
|
}
|
|
|
|
if (newSize.x > m_oldSize.x)
|
|
{
|
|
wxRect rect;
|
|
rect.y = 0;
|
|
rect.height = m_oldSize.y;
|
|
rect.x = m_oldSize.x-4;
|
|
rect.width = 2;
|
|
Refresh( true, &rect );
|
|
}
|
|
else if (newSize.x < m_oldSize.x)
|
|
{
|
|
wxRect rect;
|
|
rect.x = newSize.x;
|
|
rect.y = 0;
|
|
rect.width = 2;
|
|
rect.height = newSize.y;
|
|
wxWindowNative::Refresh( true, &rect );
|
|
}
|
|
}
|
|
|
|
m_oldSize = newSize;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
wxSize wxWindow::DoGetBorderSize() const
|
|
{
|
|
return AdjustSize(wxSize(0, 0));
|
|
}
|
|
|
|
wxSize wxWindow::AdjustSize(const wxSize& size) const
|
|
{
|
|
wxSize sz = size;
|
|
if ( m_renderer )
|
|
m_renderer->AdjustSize(&sz, this);
|
|
return sz;
|
|
}
|
|
|
|
wxPoint wxWindow::GetClientAreaOrigin() const
|
|
{
|
|
wxPoint pt = wxWindowBase::GetClientAreaOrigin();
|
|
|
|
#if wxUSE_TWO_WINDOWS
|
|
#else
|
|
if ( m_renderer )
|
|
pt += m_renderer->GetBorderDimensions(GetBorder()).GetPosition();
|
|
#endif
|
|
|
|
return pt;
|
|
}
|
|
|
|
void wxWindow::DoGetClientSize(int *width, int *height) const
|
|
{
|
|
// if it is a native window, we assume it handles the scrollbars itself
|
|
// too - and if it doesn't, there is not much we can do
|
|
if ( !m_renderer )
|
|
{
|
|
wxWindowNative::DoGetClientSize(width, height);
|
|
|
|
return;
|
|
}
|
|
|
|
int w, h;
|
|
wxWindowNative::DoGetClientSize(&w, &h);
|
|
|
|
// we assume that the scrollbars are positioned correctly (by a previous
|
|
// call to PositionScrollbars()) here
|
|
|
|
wxRect rectBorder;
|
|
if ( m_renderer )
|
|
rectBorder = m_renderer->GetBorderDimensions(GetBorder());
|
|
|
|
if ( width )
|
|
{
|
|
#if wxUSE_SCROLLBAR
|
|
// in any case, take account of the scrollbar
|
|
if ( m_scrollbarVert )
|
|
w -= m_scrollbarVert->GetSize().x;
|
|
#endif // wxUSE_SCROLLBAR
|
|
|
|
// account for the left and right borders
|
|
*width = w - rectBorder.x - rectBorder.width;
|
|
|
|
// we shouldn't return invalid width
|
|
if ( *width < 0 )
|
|
*width = 0;
|
|
}
|
|
|
|
if ( height )
|
|
{
|
|
#if wxUSE_SCROLLBAR
|
|
if ( m_scrollbarHorz )
|
|
h -= m_scrollbarHorz->GetSize().y;
|
|
#endif // wxUSE_SCROLLBAR
|
|
|
|
*height = h - rectBorder.y - rectBorder.height;
|
|
|
|
// we shouldn't return invalid height
|
|
if ( *height < 0 )
|
|
*height = 0;
|
|
}
|
|
}
|
|
|
|
void wxWindow::DoSetClientSize(int width, int height)
|
|
{
|
|
// take into account the borders
|
|
wxRect rectBorder = m_renderer->GetBorderDimensions(GetBorder());
|
|
width += rectBorder.x;
|
|
height += rectBorder.y;
|
|
|
|
// and the scrollbars (as they may be offset into the border, use the
|
|
// scrollbar position, not size - this supposes that PositionScrollbars()
|
|
// had been called before)
|
|
wxSize size = GetSize();
|
|
#if wxUSE_SCROLLBAR
|
|
if ( m_scrollbarVert )
|
|
width += size.x - m_scrollbarVert->GetPosition().x;
|
|
#endif // wxUSE_SCROLLBAR
|
|
width += rectBorder.width;
|
|
|
|
#if wxUSE_SCROLLBAR
|
|
if ( m_scrollbarHorz )
|
|
height += size.y - m_scrollbarHorz->GetPosition().y;
|
|
#endif // wxUSE_SCROLLBAR
|
|
height += rectBorder.height;
|
|
|
|
wxWindowNative::DoSetClientSize(width, height);
|
|
}
|
|
|
|
wxHitTest wxWindow::DoHitTest(wxCoord x, wxCoord y) const
|
|
{
|
|
wxHitTest ht = wxWindowNative::DoHitTest(x, y);
|
|
|
|
#if wxUSE_SCROLLBAR
|
|
if ( ht == wxHT_WINDOW_INSIDE )
|
|
{
|
|
if ( m_scrollbarVert && x >= m_scrollbarVert->GetPosition().x )
|
|
{
|
|
// it can still be changed below because it may also be the corner
|
|
ht = wxHT_WINDOW_VERT_SCROLLBAR;
|
|
}
|
|
|
|
if ( m_scrollbarHorz && y >= m_scrollbarHorz->GetPosition().y )
|
|
{
|
|
ht = ht == wxHT_WINDOW_VERT_SCROLLBAR ? wxHT_WINDOW_CORNER
|
|
: wxHT_WINDOW_HORZ_SCROLLBAR;
|
|
}
|
|
}
|
|
#endif // wxUSE_SCROLLBAR
|
|
|
|
return ht;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// scrolling: we implement it entirely ourselves except for ScrollWindow()
|
|
// function which is supposed to be (efficiently) implemented by the native
|
|
// window class
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void wxWindow::RefreshScrollbars()
|
|
{
|
|
#if wxUSE_SCROLLBAR
|
|
if ( m_scrollbarHorz )
|
|
m_scrollbarHorz->Refresh();
|
|
|
|
if ( m_scrollbarVert )
|
|
m_scrollbarVert->Refresh();
|
|
#endif // wxUSE_SCROLLBAR
|
|
}
|
|
|
|
void wxWindow::PositionScrollbars()
|
|
{
|
|
#if wxUSE_SCROLLBAR
|
|
// do not use GetClientSize/Rect as it relies on the scrollbars being
|
|
// correctly positioned
|
|
|
|
wxSize size = GetSize();
|
|
wxBorder border = GetBorder();
|
|
wxRect rectBorder = m_renderer->GetBorderDimensions(border);
|
|
bool inside = m_renderer->AreScrollbarsInsideBorder();
|
|
|
|
int height = m_scrollbarHorz ? m_scrollbarHorz->GetSize().y : 0;
|
|
int width = m_scrollbarVert ? m_scrollbarVert->GetSize().x : 0;
|
|
|
|
wxRect rectBar;
|
|
if ( m_scrollbarVert )
|
|
{
|
|
rectBar.x = size.x - width;
|
|
if ( inside )
|
|
rectBar.x -= rectBorder.width;
|
|
rectBar.width = width;
|
|
rectBar.y = 0;
|
|
if ( inside )
|
|
rectBar.y += rectBorder.y;
|
|
rectBar.height = size.y - height;
|
|
if ( inside )
|
|
rectBar.height -= rectBorder.y + rectBorder.height;
|
|
|
|
m_scrollbarVert->SetSize(rectBar, wxSIZE_NO_ADJUSTMENTS);
|
|
}
|
|
|
|
if ( m_scrollbarHorz )
|
|
{
|
|
rectBar.y = size.y - height;
|
|
if ( inside )
|
|
rectBar.y -= rectBorder.height;
|
|
rectBar.height = height;
|
|
rectBar.x = 0;
|
|
if ( inside )
|
|
rectBar.x += rectBorder.x;
|
|
rectBar.width = size.x - width;
|
|
if ( inside )
|
|
rectBar.width -= rectBorder.x + rectBorder.width;
|
|
|
|
m_scrollbarHorz->SetSize(rectBar, wxSIZE_NO_ADJUSTMENTS);
|
|
}
|
|
|
|
RefreshScrollbars();
|
|
#endif // wxUSE_SCROLLBAR
|
|
}
|
|
|
|
void wxWindow::SetScrollbar(int orient,
|
|
int pos,
|
|
int pageSize,
|
|
int range,
|
|
bool refresh)
|
|
{
|
|
#if wxUSE_SCROLLBAR
|
|
wxASSERT_MSG( pageSize <= range,
|
|
wxT("page size can't be greater than range") );
|
|
|
|
bool hasClientSizeChanged = false;
|
|
wxScrollBar *scrollbar = GetScrollbar(orient);
|
|
if ( range && (pageSize < range) )
|
|
{
|
|
if ( !scrollbar )
|
|
{
|
|
// create it
|
|
#if wxUSE_TWO_WINDOWS
|
|
SetInsertIntoMain( true );
|
|
#endif
|
|
scrollbar = new wxWindowScrollBar(this, wxID_ANY,
|
|
wxDefaultPosition, wxDefaultSize,
|
|
orient & wxVERTICAL ? wxSB_VERTICAL
|
|
: wxSB_HORIZONTAL);
|
|
#if wxUSE_TWO_WINDOWS
|
|
SetInsertIntoMain( false );
|
|
#endif
|
|
if ( orient & wxVERTICAL )
|
|
m_scrollbarVert = scrollbar;
|
|
else
|
|
m_scrollbarHorz = scrollbar;
|
|
|
|
// the client area diminished as we created a scrollbar
|
|
hasClientSizeChanged = true;
|
|
|
|
PositionScrollbars();
|
|
}
|
|
else if ( GetWindowStyle() & wxALWAYS_SHOW_SB )
|
|
{
|
|
// we might have disabled it before
|
|
scrollbar->Enable();
|
|
}
|
|
|
|
scrollbar->SetScrollbar(pos, pageSize, range, pageSize, refresh);
|
|
}
|
|
else // no range means no scrollbar
|
|
{
|
|
if ( scrollbar )
|
|
{
|
|
// wxALWAYS_SHOW_SB only applies to the vertical scrollbar
|
|
if ( (orient & wxVERTICAL) && (GetWindowStyle() & wxALWAYS_SHOW_SB) )
|
|
{
|
|
// just disable the scrollbar
|
|
scrollbar->SetScrollbar(pos, pageSize, range, pageSize, refresh);
|
|
scrollbar->Disable();
|
|
}
|
|
else // really remove the scrollbar
|
|
{
|
|
delete scrollbar;
|
|
|
|
if ( orient & wxVERTICAL )
|
|
m_scrollbarVert = NULL;
|
|
else
|
|
m_scrollbarHorz = NULL;
|
|
|
|
// the client area increased as we removed a scrollbar
|
|
hasClientSizeChanged = true;
|
|
|
|
// the size of the remaining scrollbar must be adjusted
|
|
if ( m_scrollbarHorz || m_scrollbarVert )
|
|
{
|
|
PositionScrollbars();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// give the window a chance to relayout
|
|
if ( hasClientSizeChanged )
|
|
{
|
|
#if wxUSE_TWO_WINDOWS
|
|
wxWindowNative::SetSize( GetSize() );
|
|
#else
|
|
wxSizeEvent event(GetSize());
|
|
(void)GetEventHandler()->ProcessEvent(event);
|
|
#endif
|
|
}
|
|
#else
|
|
wxUnusedVar(orient);
|
|
wxUnusedVar(pos);
|
|
wxUnusedVar(pageSize);
|
|
wxUnusedVar(range);
|
|
wxUnusedVar(refresh);
|
|
#endif // wxUSE_SCROLLBAR
|
|
}
|
|
|
|
void wxWindow::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh))
|
|
{
|
|
#if wxUSE_SCROLLBAR
|
|
wxScrollBar *scrollbar = GetScrollbar(orient);
|
|
|
|
if (scrollbar)
|
|
scrollbar->SetThumbPosition(pos);
|
|
|
|
// VZ: I think we can safely ignore this as we always refresh it
|
|
// automatically whenever the value chanegs
|
|
#if 0
|
|
if ( refresh )
|
|
Refresh();
|
|
#endif
|
|
#else
|
|
wxUnusedVar(orient);
|
|
wxUnusedVar(pos);
|
|
#endif // wxUSE_SCROLLBAR
|
|
}
|
|
|
|
int wxWindow::GetScrollPos(int orient) const
|
|
{
|
|
#if wxUSE_SCROLLBAR
|
|
wxScrollBar *scrollbar = GetScrollbar(orient);
|
|
return scrollbar ? scrollbar->GetThumbPosition() : 0;
|
|
#else
|
|
wxUnusedVar(orient);
|
|
return 0;
|
|
#endif // wxUSE_SCROLLBAR
|
|
}
|
|
|
|
int wxWindow::GetScrollThumb(int orient) const
|
|
{
|
|
#if wxUSE_SCROLLBAR
|
|
wxScrollBar *scrollbar = GetScrollbar(orient);
|
|
return scrollbar ? scrollbar->GetThumbSize() : 0;
|
|
#else
|
|
wxUnusedVar(orient);
|
|
return 0;
|
|
#endif // wxUSE_SCROLLBAR
|
|
}
|
|
|
|
int wxWindow::GetScrollRange(int orient) const
|
|
{
|
|
#if wxUSE_SCROLLBAR
|
|
wxScrollBar *scrollbar = GetScrollbar(orient);
|
|
return scrollbar ? scrollbar->GetRange() : 0;
|
|
#else
|
|
wxUnusedVar(orient);
|
|
return 0;
|
|
#endif // wxUSE_SCROLLBAR
|
|
}
|
|
|
|
void wxWindow::ScrollWindow(int dx, int dy, const wxRect *rect)
|
|
{
|
|
// use native scrolling when available and do it in generic way
|
|
// otherwise:
|
|
#ifdef __WXX11__
|
|
|
|
wxWindowNative::ScrollWindow(dx, dy, rect);
|
|
|
|
#else // !wxX11
|
|
|
|
// before scrolling it, ensure that we don't have any unpainted areas
|
|
Update();
|
|
|
|
wxRect r;
|
|
|
|
if ( dx )
|
|
{
|
|
r = ScrollNoRefresh(dx, 0, rect);
|
|
Refresh(true /* erase bkgnd */, &r);
|
|
}
|
|
|
|
if ( dy )
|
|
{
|
|
r = ScrollNoRefresh(0, dy, rect);
|
|
Refresh(true /* erase bkgnd */, &r);
|
|
}
|
|
|
|
// scroll children accordingly:
|
|
wxPoint offset(dx, dy);
|
|
|
|
for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
|
|
node; node = node->GetNext())
|
|
{
|
|
wxWindow *child = node->GetData();
|
|
#if wxUSE_SCROLLBAR
|
|
if ( child == m_scrollbarVert || child == m_scrollbarHorz )
|
|
continue;
|
|
#endif // wxUSE_SCROLLBAR
|
|
|
|
// VS: Scrolling children has non-trivial semantics. If rect=NULL then
|
|
// it is easy: we scroll all children. Otherwise it gets
|
|
// complicated:
|
|
// 1. if scrolling in one direction only, scroll only
|
|
// those children that intersect shaft defined by the rectangle
|
|
// and scrolling direction
|
|
// 2. if scrolling in both axes, scroll all children
|
|
|
|
bool shouldMove = false;
|
|
|
|
if ( rect && (dx * dy == 0 /* moving in only one of x, y axis */) )
|
|
{
|
|
wxRect childRect = child->GetRect();
|
|
if ( dx == 0 && (childRect.GetLeft() <= rect->GetRight() ||
|
|
childRect.GetRight() >= rect->GetLeft()) )
|
|
{
|
|
shouldMove = true;
|
|
}
|
|
else if ( dy == 0 && (childRect.GetTop() <= rect->GetBottom() ||
|
|
childRect.GetBottom() >= rect->GetTop()) )
|
|
{
|
|
shouldMove = true;
|
|
}
|
|
// else: child outside of scrolling shaft, don't move
|
|
}
|
|
else // scrolling in both axes or rect=NULL
|
|
{
|
|
shouldMove = true;
|
|
}
|
|
|
|
if ( shouldMove )
|
|
child->Move(child->GetPosition() + offset, wxSIZE_ALLOW_MINUS_ONE);
|
|
}
|
|
#endif // wxX11/!wxX11
|
|
}
|
|
|
|
wxRect wxWindow::ScrollNoRefresh(int dx, int dy, const wxRect *rectTotal)
|
|
{
|
|
wxASSERT_MSG( !dx || !dy, wxT("can't be used for diag scrolling") );
|
|
|
|
// the rect to refresh (which we will calculate)
|
|
wxRect rect;
|
|
|
|
if ( !dx && !dy )
|
|
{
|
|
// nothing to do
|
|
return rect;
|
|
}
|
|
|
|
// calculate the part of the window which we can just redraw in the new
|
|
// location
|
|
wxSize sizeTotal = rectTotal ? rectTotal->GetSize() : GetClientSize();
|
|
|
|
wxLogTrace(wxT("scroll"), wxT("rect is %dx%d, scroll by %d, %d"),
|
|
sizeTotal.x, sizeTotal.y, dx, dy);
|
|
|
|
// the initial and end point of the region we move in client coords
|
|
wxPoint ptSource, ptDest;
|
|
if ( rectTotal )
|
|
{
|
|
ptSource = rectTotal->GetPosition();
|
|
ptDest = rectTotal->GetPosition();
|
|
}
|
|
|
|
// the size of this region
|
|
wxSize size;
|
|
size.x = sizeTotal.x - abs(dx);
|
|
size.y = sizeTotal.y - abs(dy);
|
|
if ( size.x <= 0 || size.y <= 0 )
|
|
{
|
|
// just redraw everything as nothing of the displayed image will stay
|
|
wxLogTrace(wxT("scroll"), wxT("refreshing everything"));
|
|
|
|
rect = rectTotal ? *rectTotal : wxRect(0, 0, sizeTotal.x, sizeTotal.y);
|
|
}
|
|
else // move the part which doesn't change to the new location
|
|
{
|
|
// note that when we scroll the canvas in some direction we move the
|
|
// block which doesn't need to be refreshed in the opposite direction
|
|
|
|
if ( dx < 0 )
|
|
{
|
|
// scroll to the right, move to the left
|
|
ptSource.x -= dx;
|
|
}
|
|
else
|
|
{
|
|
// scroll to the left, move to the right
|
|
ptDest.x += dx;
|
|
}
|
|
|
|
if ( dy < 0 )
|
|
{
|
|
// scroll down, move up
|
|
ptSource.y -= dy;
|
|
}
|
|
else
|
|
{
|
|
// scroll up, move down
|
|
ptDest.y += dy;
|
|
}
|
|
|
|
#if wxUSE_CARET
|
|
// we need to hide the caret before moving or it will erase itself at
|
|
// the wrong (old) location
|
|
wxCaret *caret = GetCaret();
|
|
if ( caret )
|
|
caret->Hide();
|
|
#endif // wxUSE_CARET
|
|
|
|
// do move
|
|
wxClientDC dc(this);
|
|
wxBitmap bmp(size.x, size.y);
|
|
wxMemoryDC dcMem;
|
|
dcMem.SelectObject(bmp);
|
|
|
|
dcMem.Blit(wxPoint(0,0), size, &dc, ptSource
|
|
#if defined(__WXGTK__) && !defined(wxHAS_WORKING_GTK_DC_BLIT)
|
|
+ GetClientAreaOrigin()
|
|
#endif // broken wxGTK wxDC::Blit
|
|
);
|
|
dc.Blit(ptDest, size, &dcMem, wxPoint(0,0));
|
|
|
|
wxLogTrace(wxT("scroll"),
|
|
wxT("Blit: (%d, %d) of size %dx%d -> (%d, %d)"),
|
|
ptSource.x, ptSource.y,
|
|
size.x, size.y,
|
|
ptDest.x, ptDest.y);
|
|
|
|
// and now repaint the uncovered area
|
|
|
|
// FIXME: We repaint the intersection of these rectangles twice - is
|
|
// it bad? I don't think so as it is rare to scroll the window
|
|
// diagonally anyhow and so adding extra logic to compute
|
|
// rectangle intersection is probably not worth the effort
|
|
|
|
rect.x = ptSource.x;
|
|
rect.y = ptSource.y;
|
|
|
|
if ( dx )
|
|
{
|
|
if ( dx < 0 )
|
|
{
|
|
// refresh the area along the right border
|
|
rect.x += size.x + dx;
|
|
rect.width = -dx;
|
|
}
|
|
else
|
|
{
|
|
// refresh the area along the left border
|
|
rect.width = dx;
|
|
}
|
|
|
|
rect.height = sizeTotal.y;
|
|
|
|
wxLogTrace(wxT("scroll"), wxT("refreshing (%d, %d)-(%d, %d)"),
|
|
rect.x, rect.y,
|
|
rect.GetRight() + 1, rect.GetBottom() + 1);
|
|
}
|
|
|
|
if ( dy )
|
|
{
|
|
if ( dy < 0 )
|
|
{
|
|
// refresh the area along the bottom border
|
|
rect.y += size.y + dy;
|
|
rect.height = -dy;
|
|
}
|
|
else
|
|
{
|
|
// refresh the area along the top border
|
|
rect.height = dy;
|
|
}
|
|
|
|
rect.width = sizeTotal.x;
|
|
|
|
wxLogTrace(wxT("scroll"), wxT("refreshing (%d, %d)-(%d, %d)"),
|
|
rect.x, rect.y,
|
|
rect.GetRight() + 1, rect.GetBottom() + 1);
|
|
}
|
|
|
|
#if wxUSE_CARET
|
|
if ( caret )
|
|
caret->Show();
|
|
#endif // wxUSE_CARET
|
|
}
|
|
|
|
return rect;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// accelerators and menu hot keys
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#if wxUSE_MENUS
|
|
// the last window over which Alt was pressed (used by OnKeyUp)
|
|
wxWindow *wxWindow::ms_winLastAltPress = NULL;
|
|
#endif // wxUSE_MENUS
|
|
|
|
#if wxUSE_ACCEL || wxUSE_MENUS
|
|
|
|
void wxWindow::OnKeyDown(wxKeyEvent& event)
|
|
{
|
|
#if wxUSE_MENUS
|
|
int key = event.GetKeyCode();
|
|
if ( !event.ControlDown() && (key == WXK_ALT || key == WXK_F10) )
|
|
{
|
|
ms_winLastAltPress = this;
|
|
|
|
// it can't be an accel anyhow
|
|
return;
|
|
}
|
|
|
|
ms_winLastAltPress = NULL;
|
|
#endif // wxUSE_MENUS
|
|
|
|
#if wxUSE_ACCEL
|
|
for ( wxWindow *win = this; win; win = win->GetParent() )
|
|
{
|
|
int command = win->GetAcceleratorTable()->GetCommand(event);
|
|
if ( command != -1 )
|
|
{
|
|
wxCommandEvent eventCmd(wxEVT_MENU, command);
|
|
if ( win->GetEventHandler()->ProcessEvent(eventCmd) )
|
|
{
|
|
// skip "event.Skip()" below
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( win->IsTopLevel() )
|
|
{
|
|
// try the frame menu bar
|
|
#if wxUSE_MENUS
|
|
wxFrame *frame = wxDynamicCast(win, wxFrame);
|
|
if ( frame )
|
|
{
|
|
wxMenuBar *menubar = frame->GetMenuBar();
|
|
if ( menubar && menubar->ProcessAccelEvent(event) )
|
|
{
|
|
// skip "event.Skip()" below
|
|
return;
|
|
}
|
|
}
|
|
#endif // wxUSE_MENUS
|
|
|
|
#if wxUSE_BUTTON
|
|
// if it wasn't in a menu, try to find a button
|
|
if ( command != -1 )
|
|
{
|
|
wxWindow* child = win->FindWindow(command);
|
|
if ( child && wxDynamicCast(child, wxButton) )
|
|
{
|
|
wxCommandEvent eventCmd(wxEVT_BUTTON, command);
|
|
eventCmd.SetEventObject(child);
|
|
if ( child->GetEventHandler()->ProcessEvent(eventCmd) )
|
|
{
|
|
// skip "event.Skip()" below
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#endif // wxUSE_BUTTON
|
|
|
|
// don't propagate accels from the child frame to the parent one
|
|
break;
|
|
}
|
|
}
|
|
#endif // wxUSE_ACCEL
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
#endif // wxUSE_ACCEL
|
|
|
|
#if wxUSE_MENUS
|
|
|
|
wxMenuBar *wxWindow::GetParentFrameMenuBar() const
|
|
{
|
|
for ( const wxWindow *win = this; win; win = win->GetParent() )
|
|
{
|
|
if ( win->IsTopLevel() )
|
|
{
|
|
wxFrame *frame = wxDynamicCast(win, wxFrame);
|
|
if ( frame )
|
|
{
|
|
return frame->GetMenuBar();
|
|
}
|
|
|
|
// don't look further - we don't want to return the menubar of the
|
|
// parent frame
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void wxWindow::OnChar(wxKeyEvent& event)
|
|
{
|
|
if ( event.AltDown() && !event.ControlDown() )
|
|
{
|
|
int key = event.GetKeyCode();
|
|
|
|
wxMenuBar *menubar = GetParentFrameMenuBar();
|
|
if ( menubar )
|
|
{
|
|
int item = menubar->FindNextItemForAccel(-1, key);
|
|
if ( item != -1 )
|
|
{
|
|
menubar->PopupMenu((size_t)item);
|
|
|
|
// skip "event.Skip()" below
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if Return was pressed, see if there's a default button to activate
|
|
if ( !event.HasModifiers() && event.GetKeyCode() == WXK_RETURN )
|
|
{
|
|
wxTopLevelWindow *
|
|
tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
|
|
if ( tlw )
|
|
{
|
|
wxButton *btn = wxDynamicCast(tlw->GetDefaultItem(), wxButton);
|
|
if ( btn )
|
|
{
|
|
wxCommandEvent evt(wxEVT_BUTTON, btn->GetId());
|
|
evt.SetEventObject(btn);
|
|
btn->Command(evt);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
void wxWindow::OnKeyUp(wxKeyEvent& event)
|
|
{
|
|
int key = event.GetKeyCode();
|
|
if ( !event.HasModifiers() && (key == WXK_ALT || key == WXK_F10) )
|
|
{
|
|
// only process Alt release specially if there were no other key
|
|
// presses since Alt had been pressed and if both events happened in
|
|
// the same window
|
|
if ( ms_winLastAltPress == this )
|
|
{
|
|
wxMenuBar *menubar = GetParentFrameMenuBar();
|
|
if ( menubar && this != menubar )
|
|
{
|
|
menubar->SelectMenu(0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
event.Skip();
|
|
}
|
|
|
|
// in any case reset it
|
|
ms_winLastAltPress = NULL;
|
|
}
|
|
|
|
#endif // wxUSE_MENUS
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// MSW-specific section
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#ifdef __WXMSW__
|
|
|
|
#include "wx/msw/private.h"
|
|
|
|
WXLRESULT wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
|
|
{
|
|
if ( message == WM_NCHITTEST )
|
|
{
|
|
// the windows which contain the other windows should let the mouse
|
|
// events through, otherwise a window inside a static box would
|
|
// never get any events at all
|
|
if ( IsStaticBox() )
|
|
{
|
|
return HTTRANSPARENT;
|
|
}
|
|
}
|
|
|
|
return wxWindowNative::MSWWindowProc(message, wParam, lParam);
|
|
}
|
|
|
|
#endif // __WXMSW__
|