DoCreate()s in derived classes and removed DoDestroy() entirely because there was really no advantage in having it (it can't be called fom base class dtor) also made XmDoCreateTLW() pure virtual which required changing IMPLEMENT_DYNAMIC_CLASS into IMPLEMENT_ABSTRACT_CLASS for wxTopLevelWindow in common code but this made sense anyhow because wxTLW should be an ABC anyhow git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@35508 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
460 lines
12 KiB
C++
460 lines
12 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: dialog.cpp
|
|
// Purpose: wxDialog class
|
|
// Author: Julian Smart
|
|
// Modified by:
|
|
// Created: 17/09/98
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) Julian Smart
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
|
|
#pragma implementation "dialog.h"
|
|
#endif
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __VMS
|
|
#define XtDisplay XTDISPLAY
|
|
#define XtWindow XTWINDOW
|
|
#define XtParent XTPARENT
|
|
#define XtScreen XTSCREEN
|
|
#endif
|
|
|
|
#include "wx/dialog.h"
|
|
#include "wx/utils.h"
|
|
#include "wx/app.h"
|
|
#include "wx/settings.h"
|
|
#include "wx/evtloop.h"
|
|
|
|
#ifdef __VMS__
|
|
#pragma message disable nosimpint
|
|
#endif
|
|
#include <Xm/Xm.h>
|
|
|
|
#include <X11/Shell.h>
|
|
#if XmVersion >= 1002
|
|
#include <Xm/XmAll.h>
|
|
#endif
|
|
#include <Xm/MwmUtil.h>
|
|
#include <Xm/Label.h>
|
|
#include <Xm/BulletinB.h>
|
|
#include <Xm/Frame.h>
|
|
#include <Xm/Text.h>
|
|
#include <Xm/DialogS.h>
|
|
#include <Xm/FileSB.h>
|
|
#include <Xm/RowColumn.h>
|
|
#include <Xm/LabelG.h>
|
|
#include <Xm/AtomMgr.h>
|
|
#if XmVersion > 1000
|
|
#include <Xm/Protocols.h>
|
|
#endif
|
|
#ifdef __VMS__
|
|
#pragma message enable nosimpint
|
|
#endif
|
|
|
|
#include "wx/motif/private.h"
|
|
|
|
// A stack of modal_showing flags, since we can't rely
|
|
// on accessing wxDialog::m_modalShowing within
|
|
// wxDialog::Show in case a callback has deleted the wxDialog.
|
|
// static wxList wxModalShowingStack;
|
|
|
|
// Lists to keep track of windows, so we can disable/enable them
|
|
// for modal dialogs
|
|
wxList wxModalDialogs;
|
|
extern wxList wxModelessWindows; // Frames and modeless dialogs
|
|
extern wxList wxPendingDelete;
|
|
|
|
#define wxUSE_INVISIBLE_RESIZE 1
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxDialog, wxTopLevelWindow)
|
|
|
|
BEGIN_EVENT_TABLE(wxDialog, wxTopLevelWindow)
|
|
EVT_BUTTON(wxID_OK, wxDialog::OnOK)
|
|
EVT_BUTTON(wxID_APPLY, wxDialog::OnApply)
|
|
EVT_BUTTON(wxID_CANCEL, wxDialog::OnCancel)
|
|
EVT_CHAR_HOOK(wxDialog::OnCharHook)
|
|
EVT_SYS_COLOUR_CHANGED(wxDialog::OnSysColourChanged)
|
|
EVT_CLOSE(wxDialog::OnCloseWindow)
|
|
END_EVENT_TABLE()
|
|
|
|
|
|
wxDialog::wxDialog()
|
|
{
|
|
m_modalShowing = false;
|
|
m_eventLoop = NULL;
|
|
m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
|
|
}
|
|
|
|
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);
|
|
|
|
if( !wxTopLevelWindow::Create( parent, id, title, pos, size, style,
|
|
name ) )
|
|
return false;
|
|
|
|
m_modalShowing = false;
|
|
m_eventLoop = NULL;
|
|
|
|
m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
|
|
m_foregroundColour = *wxBLACK;
|
|
|
|
Widget dialogShell = (Widget) m_mainWidget;
|
|
Widget shell = XtParent(dialogShell) ;
|
|
|
|
SetTitle( title );
|
|
|
|
m_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
|
ChangeFont(false);
|
|
|
|
// Can't remember what this was about... but I think it's necessary.
|
|
if (wxUSE_INVISIBLE_RESIZE)
|
|
{
|
|
if (pos.x > -1)
|
|
XtVaSetValues(dialogShell, XmNx, pos.x,
|
|
NULL);
|
|
if (pos.y > -1)
|
|
XtVaSetValues(dialogShell, XmNy, pos.y,
|
|
NULL);
|
|
|
|
if (size.x > -1)
|
|
XtVaSetValues(dialogShell, XmNwidth, size.x, NULL);
|
|
if (size.y > -1)
|
|
XtVaSetValues(dialogShell, XmNheight, size.y, NULL);
|
|
}
|
|
|
|
// Positioning of the dialog doesn't work properly unless the dialog
|
|
// is managed, so we manage without mapping to the screen.
|
|
// To show, we map the shell (actually it's parent).
|
|
if (!wxUSE_INVISIBLE_RESIZE)
|
|
XtVaSetValues(shell, XmNmappedWhenManaged, False, NULL);
|
|
|
|
if (!wxUSE_INVISIBLE_RESIZE)
|
|
{
|
|
XtManageChild(dialogShell);
|
|
SetSize(pos.x, pos.y, size.x, size.y);
|
|
}
|
|
XtAddEventHandler(dialogShell,ExposureMask,False,
|
|
wxUniversalRepaintProc, (XtPointer) this);
|
|
|
|
ChangeBackgroundColour();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxDialog::XmDoCreateTLW(wxWindow* parent,
|
|
wxWindowID id,
|
|
const wxString& title,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxString& name)
|
|
{
|
|
Widget parentWidget = (Widget) 0;
|
|
if( parent )
|
|
parentWidget = (Widget) parent->GetTopWidget();
|
|
if( !parent )
|
|
parentWidget = (Widget) wxTheApp->GetTopLevelWidget();
|
|
|
|
wxASSERT_MSG( (parentWidget != (Widget) 0),
|
|
"Could not find a suitable parent shell for dialog." );
|
|
|
|
Arg args[2];
|
|
XtSetArg (args[0], XmNdefaultPosition, False);
|
|
XtSetArg (args[1], XmNautoUnmanage, False);
|
|
Widget dialogShell =
|
|
XmCreateBulletinBoardDialog( parentWidget,
|
|
wxConstCast(name.c_str(), char),
|
|
args, 2);
|
|
m_mainWidget = (WXWidget) dialogShell;
|
|
|
|
// We don't want margins, since there is enough elsewhere.
|
|
XtVaSetValues( dialogShell,
|
|
XmNmarginHeight, 0,
|
|
XmNmarginWidth, 0,
|
|
XmNresizePolicy, XmRESIZE_NONE,
|
|
NULL ) ;
|
|
|
|
XtTranslations ptr ;
|
|
XtOverrideTranslations(dialogShell,
|
|
ptr = XtParseTranslationTable("<Configure>: resize()"));
|
|
XtFree((char *)ptr);
|
|
|
|
XtRealizeWidget(dialogShell);
|
|
|
|
wxAddWindowToTable( (Widget)m_mainWidget, this );
|
|
|
|
return true;
|
|
}
|
|
|
|
void wxDialog::SetModal(bool flag)
|
|
{
|
|
#ifdef __VMS
|
|
#pragma message disable codcauunr
|
|
#endif
|
|
if ( flag )
|
|
m_windowStyle |= wxDIALOG_MODAL ;
|
|
else
|
|
if ( m_windowStyle & wxDIALOG_MODAL )
|
|
m_windowStyle -= wxDIALOG_MODAL ;
|
|
|
|
wxModelessWindows.DeleteObject(this);
|
|
if (!flag)
|
|
wxModelessWindows.Append(this);
|
|
#ifdef __VMS
|
|
#pragma message enable codcauunr
|
|
#endif
|
|
}
|
|
|
|
wxDialog::~wxDialog()
|
|
{
|
|
m_isBeingDeleted = true;
|
|
|
|
delete m_eventLoop;
|
|
|
|
if (m_mainWidget)
|
|
{
|
|
XtRemoveEventHandler((Widget) m_mainWidget, ExposureMask, False,
|
|
wxUniversalRepaintProc, (XtPointer) this);
|
|
}
|
|
|
|
m_modalShowing = false;
|
|
if (!wxUSE_INVISIBLE_RESIZE && m_mainWidget)
|
|
{
|
|
XtUnmapWidget((Widget) m_mainWidget);
|
|
}
|
|
|
|
PreDestroy();
|
|
|
|
if ( m_mainWidget )
|
|
{
|
|
wxDeleteWindowFromTable( (Widget)m_mainWidget );
|
|
XtDestroyWidget( (Widget)m_mainWidget );
|
|
}
|
|
}
|
|
|
|
// By default, pressing escape cancels the dialog
|
|
void wxDialog::OnCharHook(wxKeyEvent& event)
|
|
{
|
|
if (event.m_keyCode == WXK_ESCAPE)
|
|
{
|
|
// Behaviour changed in 2.0: we'll send a Cancel message
|
|
// to the dialog instead of Close.
|
|
wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
|
|
cancelEvent.SetEventObject( this );
|
|
GetEventHandler()->ProcessEvent(cancelEvent);
|
|
|
|
return;
|
|
}
|
|
// We didn't process this event.
|
|
event.Skip();
|
|
}
|
|
|
|
void wxDialog::DoSetSize(int x, int y, int width, int height, int sizeFlags)
|
|
{
|
|
XtVaSetValues((Widget) m_mainWidget, XmNresizePolicy, XmRESIZE_ANY, NULL);
|
|
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
|
|
XtVaSetValues((Widget) m_mainWidget, XmNresizePolicy, XmRESIZE_NONE, NULL);
|
|
}
|
|
|
|
void wxDialog::DoSetClientSize(int width, int height)
|
|
{
|
|
wxWindow::SetSize(-1, -1, width, height);
|
|
}
|
|
|
|
void wxDialog::SetTitle(const wxString& title)
|
|
{
|
|
wxTopLevelWindow::SetTitle( title );
|
|
|
|
if( !title.empty() )
|
|
{
|
|
wxXmString str( title );
|
|
XtVaSetValues( (Widget)m_mainWidget,
|
|
XmNtitle, title.c_str(),
|
|
XmNdialogTitle, str(), // Roberto Cocchi
|
|
XmNiconName, title.c_str(),
|
|
NULL );
|
|
}
|
|
}
|
|
|
|
bool wxDialog::Show( bool show )
|
|
{
|
|
if( !wxWindowBase::Show( show ) )
|
|
return false;
|
|
|
|
m_isShown = show;
|
|
|
|
if (show)
|
|
{
|
|
if (!wxUSE_INVISIBLE_RESIZE)
|
|
XtMapWidget(XtParent((Widget) m_mainWidget));
|
|
else
|
|
XtManageChild((Widget)m_mainWidget) ;
|
|
|
|
XRaiseWindow( XtDisplay( (Widget)m_mainWidget ),
|
|
XtWindow( (Widget)m_mainWidget) );
|
|
|
|
}
|
|
else
|
|
{
|
|
if (!wxUSE_INVISIBLE_RESIZE)
|
|
XtUnmapWidget(XtParent((Widget) m_mainWidget));
|
|
else
|
|
XtUnmanageChild((Widget)m_mainWidget) ;
|
|
|
|
XFlush(XtDisplay((Widget)m_mainWidget));
|
|
XSync(XtDisplay((Widget)m_mainWidget), False);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Shows a dialog modally, returning a return code
|
|
int wxDialog::ShowModal()
|
|
{
|
|
m_windowStyle |= wxDIALOG_MODAL;
|
|
|
|
Show(true);
|
|
|
|
// after the event loop ran, the widget might already have been destroyed
|
|
WXDisplay* display = (WXDisplay*)XtDisplay( (Widget)m_mainWidget );
|
|
|
|
if (m_modalShowing)
|
|
return 0;
|
|
m_eventLoop = new wxEventLoop;
|
|
|
|
m_modalShowing = true;
|
|
XtAddGrab((Widget) m_mainWidget, True, False);
|
|
|
|
m_eventLoop->Run();
|
|
|
|
// Now process all events in case they get sent to a destroyed dialog
|
|
wxFlushEvents( display );
|
|
|
|
delete m_eventLoop;
|
|
m_eventLoop = NULL;
|
|
|
|
// TODO: is it safe to call this, if the dialog may have been deleted
|
|
// by now? Probably only if we're using delayed deletion of dialogs.
|
|
return GetReturnCode();
|
|
}
|
|
|
|
void wxDialog::EndModal(int retCode)
|
|
{
|
|
if (!m_modalShowing)
|
|
return;
|
|
|
|
SetReturnCode(retCode);
|
|
|
|
// Strangely, we don't seem to need this now.
|
|
// XtRemoveGrab((Widget) m_mainWidget);
|
|
|
|
Show(false);
|
|
|
|
m_modalShowing = false;
|
|
m_eventLoop->Exit();
|
|
}
|
|
|
|
// Standard buttons
|
|
void wxDialog::OnOK(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
if ( Validate() && TransferDataFromWindow() )
|
|
{
|
|
if ( IsModal() )
|
|
EndModal(wxID_OK);
|
|
else
|
|
{
|
|
SetReturnCode(wxID_OK);
|
|
this->Show(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxDialog::OnApply(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
if (Validate())
|
|
TransferDataFromWindow();
|
|
// TODO probably need to disable the Apply button until things change again
|
|
}
|
|
|
|
void wxDialog::OnCancel(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
if ( IsModal() )
|
|
EndModal(wxID_CANCEL);
|
|
else
|
|
{
|
|
SetReturnCode(wxID_CANCEL);
|
|
this->Show(false);
|
|
}
|
|
}
|
|
|
|
void wxDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
|
|
{
|
|
// We'll send a Cancel message by default,
|
|
// which may close the dialog.
|
|
// Check for looping if the Cancel event handler calls Close().
|
|
|
|
// Note that if a cancel button and handler aren't present in the dialog,
|
|
// nothing will happen when you close the dialog via the window manager, or
|
|
// via Close().
|
|
// We wouldn't want to destroy the dialog by default, since the dialog may have been
|
|
// created on the stack.
|
|
// However, this does mean that calling dialog->Close() won't delete the dialog
|
|
// unless the handler for wxID_CANCEL does so. So use Destroy() if you want to be
|
|
// sure to destroy the dialog.
|
|
// The default OnCancel (above) simply ends a modal dialog, and hides a modeless dialog.
|
|
|
|
static wxList closing;
|
|
|
|
if ( closing.Member(this) )
|
|
return;
|
|
|
|
closing.Append(this);
|
|
|
|
wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
|
|
cancelEvent.SetEventObject( this );
|
|
GetEventHandler()->ProcessEvent(cancelEvent); // This may close the dialog
|
|
|
|
closing.DeleteObject(this);
|
|
}
|
|
|
|
// Destroy the window (delayed, if a managed window)
|
|
bool wxDialog::Destroy()
|
|
{
|
|
if (!wxPendingDelete.Member(this))
|
|
wxPendingDelete.Append(this);
|
|
return true;
|
|
}
|
|
|
|
void wxDialog::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
|
|
{
|
|
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
|
|
Refresh();
|
|
}
|
|
|
|
void wxDialog::ChangeFont(bool keepOriginalSize)
|
|
{
|
|
wxWindow::ChangeFont(keepOriginalSize);
|
|
}
|
|
|
|
void wxDialog::ChangeBackgroundColour()
|
|
{
|
|
if (GetMainWidget())
|
|
wxDoChangeBackgroundColour(GetMainWidget(), m_backgroundColour);
|
|
}
|
|
|
|
void wxDialog::ChangeForegroundColour()
|
|
{
|
|
if (GetMainWidget())
|
|
wxDoChangeForegroundColour(GetMainWidget(), m_foregroundColour);
|
|
}
|