Files
wxWidgets/src/msw/dialog.cpp
Vadim Zeitlin 3518f1a7d8 Use a single wxTopLevelWindow::m_showCmd flag in wxMSW
This single field replaces m_iconized and m_maximizeOnShow which were
not really independent and will make it simpler to schedule either
maximizing or maximizing the window later, when it can't be done
immediately because the window is hidden, in the following commit.
2018-06-22 03:23:31 +02:00

361 lines
11 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/msw/dialog.cpp
// Purpose: wxDialog class
// Author: Julian Smart
// Modified by:
// Created: 01/02/97
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "wx/dialog.h"
#include "wx/modalhook.h"
#ifndef WX_PRECOMP
#include "wx/msw/wrapcdlg.h"
#include "wx/utils.h"
#include "wx/frame.h"
#include "wx/app.h"
#include "wx/button.h"
#include "wx/settings.h"
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/toolbar.h"
#endif
#include "wx/msw/private.h"
#include "wx/evtloop.h"
#include "wx/scopedptr.h"
// ----------------------------------------------------------------------------
// wxWin macros
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// wxDialogModalData
// ----------------------------------------------------------------------------
// this is simply a container for any data we need to implement modality which
// allows us to avoid changing wxDialog each time the implementation changes
class wxDialogModalData
{
public:
wxDialogModalData(wxDialog *dialog) : m_evtLoop(dialog) { }
void RunLoop()
{
m_evtLoop.Run();
}
void ExitLoop()
{
m_evtLoop.Exit();
}
private:
wxModalEventLoop m_evtLoop;
};
wxDEFINE_TIED_SCOPED_PTR_TYPE(wxDialogModalData)
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxDialog construction
// ----------------------------------------------------------------------------
void wxDialog::Init()
{
m_isShown = false;
m_modalData = NULL;
m_hGripper = 0;
}
bool wxDialog::Create(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
{
SetExtraStyle(GetExtraStyle() | wxTOPLEVEL_EX_DIALOG);
// All dialogs should really have this style
style |= wxTAB_TRAVERSAL;
if ( !wxTopLevelWindow::Create(parent, id, title, pos, size, style, name) )
return false;
if ( !m_hasFont )
SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
if ( HasFlag(wxRESIZE_BORDER) )
{
CreateGripper();
Bind(wxEVT_CREATE, &wxDialog::OnWindowCreate, this);
}
return true;
}
wxDialog::~wxDialog()
{
// this will also reenable all the other windows for a modal dialog
Show(false);
DestroyGripper();
}
// ----------------------------------------------------------------------------
// showing the dialogs
// ----------------------------------------------------------------------------
bool wxDialog::Show(bool show)
{
if ( show == IsShown() )
return false;
if ( !show && m_modalData )
{
// we need to do this before calling wxDialogBase version because if we
// had disabled other app windows, they must be reenabled right now as
// if they stay disabled Windows will activate another window (one
// which is enabled, anyhow) when we're hidden in the base class Show()
// and we will lose activation
m_modalData->ExitLoop();
}
if ( show )
{
if (CanDoLayoutAdaptation())
DoLayoutAdaptation();
// this usually will result in TransferDataToWindow() being called
// which will change the controls values so do it before showing as
// otherwise we could have some flicker
InitDialog();
}
wxDialogBase::Show(show);
if ( show )
{
// dialogs don't get WM_SIZE message from ::ShowWindow() for some
// reason so generate it ourselves for consistency with frames and
// dialogs in other ports
//
// NB: normally we should call it just the first time but doing it
// every time is simpler than keeping a flag
const wxSize size = GetClientSize();
::SendMessage(GetHwnd(), WM_SIZE,
SIZE_RESTORED, MAKELPARAM(size.x, size.y));
}
return true;
}
// show dialog modally
int wxDialog::ShowModal()
{
WX_HOOK_MODAL_DIALOG();
wxASSERT_MSG( !IsModal(), wxT("ShowModal() can't be called twice") );
wxDialogModalDataTiedPtr modalData(&m_modalData,
new wxDialogModalData(this));
Show();
// EndModal may have been called from InitDialog handler (called from
// inside Show()) and hidden the dialog back again
if ( IsShown() )
modalData->RunLoop();
else
m_modalData->ExitLoop();
return GetReturnCode();
}
void wxDialog::EndModal(int retCode)
{
wxASSERT_MSG( IsModal(), wxT("EndModal() called for non modal dialog") );
SetReturnCode(retCode);
Hide();
}
// ----------------------------------------------------------------------------
// wxDialog gripper handling
// ----------------------------------------------------------------------------
void wxDialog::SetWindowStyleFlag(long style)
{
wxDialogBase::SetWindowStyleFlag(style);
if ( HasFlag(wxRESIZE_BORDER) )
CreateGripper();
else
DestroyGripper();
}
void wxDialog::CreateGripper()
{
if ( !m_hGripper )
{
// just create it here, it will be positioned and shown later
m_hGripper = (WXHWND)::CreateWindow
(
wxT("SCROLLBAR"),
wxT(""),
WS_CHILD |
WS_CLIPSIBLINGS |
SBS_SIZEGRIP |
SBS_SIZEBOX |
SBS_SIZEBOXBOTTOMRIGHTALIGN,
0, 0, 0, 0,
GetHwnd(),
0,
wxGetInstance(),
NULL
);
}
}
void wxDialog::DestroyGripper()
{
if ( m_hGripper )
{
// we used to have trouble with gripper appearing on top (and hence
// overdrawing) the other, real, dialog children -- check that this
// isn't the case automatically (but notice that this could be false if
// we're not shown at all as in this case ResizeGripper() might not
// have been called yet)
wxASSERT_MSG( !IsShown() ||
::GetWindow((HWND)m_hGripper, GW_HWNDNEXT) == 0,
wxT("Bug in wxWidgets: gripper should be at the bottom of Z-order") );
::DestroyWindow((HWND) m_hGripper);
m_hGripper = 0;
}
}
void wxDialog::ShowGripper(bool show)
{
wxASSERT_MSG( m_hGripper, wxT("shouldn't be called if we have no gripper") );
if ( show )
ResizeGripper();
::ShowWindow((HWND)m_hGripper, show ? SW_SHOW : SW_HIDE);
}
void wxDialog::ResizeGripper()
{
wxASSERT_MSG( m_hGripper, wxT("shouldn't be called if we have no gripper") );
HWND hwndGripper = (HWND)m_hGripper;
const wxRect rectGripper = wxRectFromRECT(wxGetWindowRect(hwndGripper));
const wxSize size = GetClientSize() - rectGripper.GetSize();
::SetWindowPos(hwndGripper, HWND_BOTTOM,
size.x, size.y,
rectGripper.width, rectGripper.height,
SWP_NOACTIVATE);
}
void wxDialog::OnWindowCreate(wxWindowCreateEvent& event)
{
if ( m_hGripper && IsShown() &&
event.GetWindow() && event.GetWindow()->GetParent() == this )
{
// Put gripper below the newly created child window
::SetWindowPos((HWND)m_hGripper, HWND_BOTTOM, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
}
event.Skip();
}
// ----------------------------------------------------------------------------
// wxWin event handlers
// ----------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// dialog Windows messages processing
// ---------------------------------------------------------------------------
WXLRESULT wxDialog::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
{
WXLRESULT rc = 0;
bool processed = false;
switch ( message )
{
case WM_CLOSE:
// if we can't close, tell the system that we processed the
// message - otherwise it would close us
processed = !Close();
break;
case WM_SIZE:
switch ( wParam )
{
case SIZE_MINIMIZED:
m_showCmd = SW_MINIMIZE;
break;
case SIZE_MAXIMIZED:
wxFALLTHROUGH;
case SIZE_RESTORED:
if ( m_hGripper )
ShowGripper( wParam == SIZE_RESTORED );
if ( m_showCmd == SW_MINIMIZE )
(void)SendIconizeEvent(false);
m_showCmd = SW_RESTORE;
break;
}
// the Windows dialogs unfortunately are not meant to be resizable
// at all and their standard class doesn't include CS_[VH]REDRAW
// styles which means that the window is not refreshed properly
// after the resize and no amount of WS_CLIPCHILDREN/SIBLINGS can
// help with it - so we have to refresh it manually which certainly
// creates flicker but at least doesn't show garbage on the screen
rc = wxWindow::MSWWindowProc(message, wParam, lParam);
processed = true;
if ( HasFlag(wxFULL_REPAINT_ON_RESIZE) )
{
::InvalidateRect(GetHwnd(), NULL, false /* erase bg */);
}
break;
}
if ( !processed )
rc = wxDialogBase::MSWWindowProc(message, wParam, lParam);
return rc;
}