/////////////////////////////////////////////////////////////////////////////
// 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;
}
↑ V522 There might be dereferencing of a potential null pointer 'm_ptr'.
↑ V821 Decreased performance. The 'modalData' variable can be constructed in a lower level scope.