window.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,123 行 · 第 1/5 页
CPP
2,123 行
// get the current size and position...
int currentX, currentY;
int currentW, currentH;
GetPosition(¤tX, ¤tY);
GetSize(¤tW, ¤tH);
// ... and don't do anything (avoiding flicker) if it's already ok unless
// we're forced to resize the window
if ( x == currentX && y == currentY &&
width == currentW && height == currentH &&
!(sizeFlags & wxSIZE_FORCE) )
{
return;
}
if ( x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
x = currentX;
if ( y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
y = currentY;
AdjustForParentClientOrigin(x, y, sizeFlags);
wxSize size = wxDefaultSize;
if ( width == wxDefaultCoord )
{
if ( sizeFlags & wxSIZE_AUTO_WIDTH )
{
size = DoGetBestSize();
width = size.x;
}
else
{
// just take the current one
width = currentW;
}
}
if ( height == wxDefaultCoord )
{
if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
{
if ( size.x == wxDefaultCoord )
{
size = DoGetBestSize();
}
//else: already called DoGetBestSize() above
height = size.y;
}
else
{
// just take the current one
height = currentH;
}
}
DoMoveWindow(x, y, width, height);
}
void wxWindowMSW::DoSetClientSize(int width, int height)
{
// setting the client size is less obvious than it it could have been
// because in the result of changing the total size the window scrollbar
// may [dis]appear and/or its menubar may [un]wrap and so the client size
// will not be correct as the difference between the total and client size
// changes - so we keep changing it until we get it right
//
// normally this loop shouldn't take more than 3 iterations (usually 1 but
// if scrollbars [dis]appear as the result of the first call, then 2 and it
// may become 3 if the window had 0 size originally and so we didn't
// calculate the scrollbar correction correctly during the first iteration)
// but just to be on the safe side we check for it instead of making it an
// "infinite" loop (i.e. leaving break inside as the only way to get out)
for ( int i = 0; i < 4; i++ )
{
RECT rectClient;
::GetClientRect(GetHwnd(), &rectClient);
// if the size is already ok, stop here (NB: rectClient.left = top = 0)
if ( (rectClient.right == width || width == wxDefaultCoord) &&
(rectClient.bottom == height || height == wxDefaultCoord) )
{
break;
}
// 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
RECT rectWin;
::GetWindowRect(GetHwnd(), &rectWin);
const int widthWin = rectWin.right - rectWin.left,
heightWin = rectWin.bottom - rectWin.top;
// MoveWindow positions the child windows relative to the parent, so
// adjust if necessary
if ( !IsTopLevel() )
{
wxWindow *parent = GetParent();
if ( parent )
{
::ScreenToClient(GetHwndOf(parent), (POINT *)&rectWin);
}
}
// don't call DoMoveWindow() because we want to move window immediately
// and not defer it here
if ( !::MoveWindow(GetHwnd(),
rectWin.left,
rectWin.top,
width + widthWin - rectClient.right,
height + heightWin - rectClient.bottom,
TRUE) )
{
wxLogLastError(_T("MoveWindow"));
}
}
}
// ---------------------------------------------------------------------------
// text metrics
// ---------------------------------------------------------------------------
int wxWindowMSW::GetCharHeight() const
{
return wxGetTextMetrics(this).tmHeight;
}
int wxWindowMSW::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 wxWindowMSW::GetTextExtent(const wxString& string,
int *x, int *y,
int *descent, int *externalLeading,
const wxFont *theFont) const
{
wxASSERT_MSG( !theFont || theFont->Ok(),
_T("invalid font in GetTextExtent()") );
wxFont fontToUse;
if (theFont)
fontToUse = *theFont;
else
fontToUse = GetFont();
WindowHDC hdc(GetHwnd());
SelectInHDC selectFont(hdc, GetHfontOf(fontToUse));
SIZE sizeRect;
TEXTMETRIC tm;
::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect);
GetTextMetrics(hdc, &tm);
if ( x )
*x = sizeRect.cx;
if ( y )
*y = sizeRect.cy;
if ( descent )
*descent = tm.tmDescent;
if ( externalLeading )
*externalLeading = tm.tmExternalLeading;
}
// ---------------------------------------------------------------------------
// popup menu
// ---------------------------------------------------------------------------
#if wxUSE_MENUS_NATIVE
// yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue
// immediately, without waiting for the next event loop iteration
//
// NB: this function should probably be made public later as it can almost
// surely replace wxYield() elsewhere as well
static void wxYieldForCommandsOnly()
{
// peek all WM_COMMANDs (it will always return WM_QUIT too but we don't
// want to process it here)
MSG msg;
while ( ::PeekMessage(&msg, (HWND)0, WM_COMMAND, WM_COMMAND, PM_REMOVE) )
{
if ( msg.message == WM_QUIT )
{
// if we retrieved a WM_QUIT, insert back into the message queue.
::PostQuitMessage(0);
break;
}
// luckily (as we don't have access to wxEventLoopImpl method from here
// anyhow...) we don't need to pre process WM_COMMANDs so dispatch it
// immediately
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
{
menu->SetInvokingWindow(this);
menu->UpdateUI();
if ( x == wxDefaultCoord && y == wxDefaultCoord )
{
wxPoint mouse = ScreenToClient(wxGetMousePosition());
x = mouse.x; y = mouse.y;
}
HWND hWnd = GetHwnd();
HMENU hMenu = GetHmenuOf(menu);
POINT point;
point.x = x;
point.y = y;
::ClientToScreen(hWnd, &point);
wxCurrentPopupMenu = menu;
#if defined(__WXWINCE__)
UINT flags = 0;
#else
UINT flags = TPM_RIGHTBUTTON;
#endif
::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL);
// we need to do it righ now as otherwise the events are never going to be
// sent to wxCurrentPopupMenu from HandleCommand()
//
// note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't
// help and we'd still need wxYieldForCommandsOnly() as the menu may be
// destroyed as soon as we return (it can be a local variable in the caller
// for example) and so we do need to process the event immediately
wxYieldForCommandsOnly();
wxCurrentPopupMenu = NULL;
menu->SetInvokingWindow(NULL);
return true;
}
#endif // wxUSE_MENUS_NATIVE
// ===========================================================================
// pre/post message processing
// ===========================================================================
WXLRESULT wxWindowMSW::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 wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
{
// wxUniversal implements tab traversal itself
#ifndef __WXUNIVERSAL__
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 ( msg->message == WM_KEYDOWN )
{
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);
// surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
// DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
// it, of course, implies them
if ( lDlgCode & DLGC_WANTALLKEYS )
{
lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
}
}
bool bForward = true,
bWindowChange = false,
bFromTab = false;
// should we process this message specially?
bool bProcess = true;
switch ( msg->wParam )
{
case VK_TAB:
if ( lDlgCode & DLGC_WANTTAB ) {
bProcess = false;
}
else {
// Ctrl-Tab cycles thru notebook pages
bWindowChange = bCtrlDown;
bForward = !bShiftDown;
bFromTab = true;
}
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;
}
// currently active button should get enter press even
// if there is a default button elsewhere
if ( lDlgCode & DLGC_DEFPUSHBUTTON )
{
// 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 // not a button itself
{
#if wxUSE_BUTTON
wxButton *btn = wxDynamicCast(GetDefaultItem(),
wxButton);
if ( btn && btn->IsEnabled() )
{
// if we do have a default button, do press it
btn->MSWCommand(BN_CLICKED, 0 /* unused */);
return true;
}
else // no default button
#endif // wxUSE_BUTTON
{
// this is a quick and dirty test for a text
// control
if ( !(lDlgCode & DLGC_HASSETSEL) )
{
// don't process Enter, the control might
// need it for itself and don't let
// ::IsDialogMessage() have it as it can
// eat the Enter events sometimes
return false;
}
else if (!IsTopLevel())
{
// if not a top level window, let parent
// handle it
return false;
}
//else: treat Enter as TAB: pass to the next
// control as this is the best thing to do
// if the text doesn't handle Enter itself
}
}
}
break;
default:
bProcess = false;
}
if ( bProcess )
{
wxNavigationKeyEvent event;
event.SetDirection(bForward);
event.SetWindowChange(bWindowChange);
event.SetFromTab(bFromTab);
event.SetEventObject(this);
if ( GetEventHandler()->ProcessEvent(event) )
{
// as we don't call IsDialogMessage(), which would take of
// this by default, we need to manually send this message
// so that controls could change their appearance
// appropriately
MSWUpdateUIState();
return true;
}
}
}
// don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
// message even when there is no cancel button and when the message is
// needed by the control itself: in particular, it prevents the tree
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?