mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-13 18:28:35 +12:00
512 lines
13 KiB
C++
512 lines
13 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/common/cshelp.cpp
|
|
// Purpose: Context sensitive help class implementation
|
|
// Author: Julian Smart, Vadim Zeitlin
|
|
// Modified by:
|
|
// Created: 08/09/2000
|
|
// RCS-ID: $Id: cshelp.cpp 52329 2008-03-05 13:20:26Z VZ $
|
|
// Copyright: (c) 2000 Julian Smart, Vadim Zeitlin
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#if wxUSE_HELP
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/app.h"
|
|
#include "wx/module.h"
|
|
#endif
|
|
|
|
#include "wx/tipwin.h"
|
|
#include "wx/cshelp.h"
|
|
|
|
#if wxUSE_MS_HTML_HELP
|
|
#include "wx/msw/helpchm.h" // for ShowContextHelpPopup
|
|
#include "wx/utils.h" // for wxGetMousePosition()
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxContextHelpEvtHandler private class
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// This class exists in order to eat events until the left mouse button is
|
|
// pressed
|
|
class wxContextHelpEvtHandler: public wxEvtHandler
|
|
{
|
|
public:
|
|
wxContextHelpEvtHandler(wxContextHelp* contextHelp)
|
|
{
|
|
m_contextHelp = contextHelp;
|
|
}
|
|
|
|
virtual bool ProcessEvent(wxEvent& event);
|
|
|
|
//// Data
|
|
wxContextHelp* m_contextHelp;
|
|
|
|
DECLARE_NO_COPY_CLASS(wxContextHelpEvtHandler)
|
|
};
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxContextHelp
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Invokes context-sensitive help
|
|
*/
|
|
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject)
|
|
|
|
wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp)
|
|
{
|
|
m_inHelp = false;
|
|
|
|
if (beginHelp)
|
|
BeginContextHelp(win);
|
|
}
|
|
|
|
wxContextHelp::~wxContextHelp()
|
|
{
|
|
if (m_inHelp)
|
|
EndContextHelp();
|
|
}
|
|
|
|
// Not currently needed, but on some systems capture may not work as
|
|
// expected so we'll leave it here for now.
|
|
#ifdef __WXMOTIF__
|
|
static void wxPushOrPopEventHandlers(wxContextHelp* help, wxWindow* win, bool push)
|
|
{
|
|
if (push)
|
|
win->PushEventHandler(new wxContextHelpEvtHandler(help));
|
|
else
|
|
win->PopEventHandler(true);
|
|
|
|
wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
|
|
while (node)
|
|
{
|
|
wxWindow* child = node->GetData();
|
|
wxPushOrPopEventHandlers(help, child, push);
|
|
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Begin 'context help mode'
|
|
bool wxContextHelp::BeginContextHelp(wxWindow* win)
|
|
{
|
|
if (!win)
|
|
win = wxTheApp->GetTopWindow();
|
|
if (!win)
|
|
return false;
|
|
|
|
wxCursor cursor(wxCURSOR_QUESTION_ARROW);
|
|
wxCursor oldCursor = win->GetCursor();
|
|
win->SetCursor(cursor);
|
|
|
|
#ifdef __WXMAC__
|
|
wxSetCursor(cursor);
|
|
#endif
|
|
|
|
m_status = false;
|
|
|
|
#ifdef __WXMOTIF__
|
|
wxPushOrPopEventHandlers(this, win, true);
|
|
#else
|
|
win->PushEventHandler(new wxContextHelpEvtHandler(this));
|
|
#endif
|
|
|
|
win->CaptureMouse();
|
|
|
|
EventLoop();
|
|
|
|
win->ReleaseMouse();
|
|
|
|
#ifdef __WXMOTIF__
|
|
wxPushOrPopEventHandlers(this, win, false);
|
|
#else
|
|
win->PopEventHandler(true);
|
|
#endif
|
|
|
|
win->SetCursor(oldCursor);
|
|
|
|
#ifdef __WXMAC__
|
|
wxSetCursor(wxNullCursor);
|
|
#endif
|
|
|
|
if (m_status)
|
|
{
|
|
wxPoint pt;
|
|
wxWindow* winAtPtr = wxFindWindowAtPointer(pt);
|
|
|
|
#if 0
|
|
if (winAtPtr)
|
|
{
|
|
printf("Picked %s (%d)\n", winAtPtr->GetName().c_str(),
|
|
winAtPtr->GetId());
|
|
}
|
|
#endif
|
|
|
|
if (winAtPtr)
|
|
DispatchEvent(winAtPtr, pt);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxContextHelp::EndContextHelp()
|
|
{
|
|
m_inHelp = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxContextHelp::EventLoop()
|
|
{
|
|
m_inHelp = true;
|
|
|
|
while ( m_inHelp )
|
|
{
|
|
if (wxTheApp->Pending())
|
|
{
|
|
wxTheApp->Dispatch();
|
|
}
|
|
else
|
|
{
|
|
wxTheApp->ProcessIdle();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event)
|
|
{
|
|
if (event.GetEventType() == wxEVT_LEFT_DOWN)
|
|
{
|
|
m_contextHelp->SetStatus(true);
|
|
m_contextHelp->EndContextHelp();
|
|
return true;
|
|
}
|
|
|
|
if ((event.GetEventType() == wxEVT_CHAR) ||
|
|
(event.GetEventType() == wxEVT_KEY_DOWN) ||
|
|
(event.GetEventType() == wxEVT_ACTIVATE) ||
|
|
(event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED))
|
|
{
|
|
// May have already been set to true by a left-click
|
|
//m_contextHelp->SetStatus(false);
|
|
m_contextHelp->EndContextHelp();
|
|
return true;
|
|
}
|
|
|
|
if ((event.GetEventType() == wxEVT_PAINT) ||
|
|
(event.GetEventType() == wxEVT_ERASE_BACKGROUND))
|
|
{
|
|
event.Skip();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Dispatch the help event to the relevant window
|
|
bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt)
|
|
{
|
|
wxCHECK_MSG( win, false, _T("win parameter can't be NULL") );
|
|
|
|
wxHelpEvent helpEvent(wxEVT_HELP, win->GetId(), pt,
|
|
wxHelpEvent::Origin_HelpButton);
|
|
helpEvent.SetEventObject(win);
|
|
|
|
return win->GetEventHandler()->ProcessEvent(helpEvent);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxContextHelpButton
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*
|
|
* wxContextHelpButton
|
|
* You can add this to your dialogs (especially on non-Windows platforms)
|
|
* to put the application into context help mode.
|
|
*/
|
|
|
|
#ifndef __WXPM__
|
|
|
|
static const char * csquery_xpm[] = {
|
|
"12 11 2 1",
|
|
" c None",
|
|
". c #000000",
|
|
" ",
|
|
" .... ",
|
|
" .. .. ",
|
|
" .. .. ",
|
|
" .. ",
|
|
" .. ",
|
|
" .. ",
|
|
" ",
|
|
" .. ",
|
|
" .. ",
|
|
" "};
|
|
|
|
#endif
|
|
|
|
IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton)
|
|
|
|
BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton)
|
|
EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp)
|
|
END_EVENT_TABLE()
|
|
|
|
wxContextHelpButton::wxContextHelpButton(wxWindow* parent,
|
|
wxWindowID id,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style)
|
|
#if defined(__WXPM__)
|
|
: wxBitmapButton(parent, id, wxBitmap(wxCSQUERY_BITMAP
|
|
,wxBITMAP_TYPE_RESOURCE
|
|
),
|
|
pos, size, style)
|
|
#else
|
|
: wxBitmapButton(parent, id, wxBitmap(csquery_xpm),
|
|
pos, size, style)
|
|
#endif
|
|
{
|
|
}
|
|
|
|
void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
wxContextHelp contextHelp(GetParent());
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxHelpProvider
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxHelpProvider *wxHelpProvider::ms_helpProvider = (wxHelpProvider *)NULL;
|
|
|
|
// trivial implementation of some methods which we don't want to make pure
|
|
// virtual for convenience
|
|
|
|
void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window),
|
|
const wxString& WXUNUSED(text))
|
|
{
|
|
}
|
|
|
|
void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id),
|
|
const wxString& WXUNUSED(text))
|
|
{
|
|
}
|
|
|
|
// removes the association
|
|
void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window))
|
|
{
|
|
}
|
|
|
|
wxHelpProvider::~wxHelpProvider()
|
|
{
|
|
}
|
|
|
|
wxString wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase *window)
|
|
{
|
|
if ( m_helptextAtPoint != wxDefaultPosition ||
|
|
m_helptextOrigin != wxHelpEvent::Origin_Unknown )
|
|
{
|
|
wxCHECK_MSG( window, wxEmptyString, _T("window must not be NULL") );
|
|
|
|
wxPoint pt = m_helptextAtPoint;
|
|
wxHelpEvent::Origin origin = m_helptextOrigin;
|
|
|
|
m_helptextAtPoint = wxDefaultPosition;
|
|
m_helptextOrigin = wxHelpEvent::Origin_Unknown;
|
|
|
|
return window->GetHelpTextAtPoint(pt, origin);
|
|
}
|
|
|
|
return GetHelp(window);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxSimpleHelpProvider
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#define WINHASH_KEY(w) wxPtrToUInt(w)
|
|
|
|
wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window)
|
|
{
|
|
wxSimpleHelpProviderHashMap::iterator it = m_hashWindows.find(WINHASH_KEY(window));
|
|
|
|
if ( it == m_hashWindows.end() )
|
|
{
|
|
it = m_hashIds.find(window->GetId());
|
|
if ( it == m_hashIds.end() )
|
|
return wxEmptyString;
|
|
}
|
|
|
|
return it->second;
|
|
}
|
|
|
|
void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
|
|
{
|
|
m_hashWindows.erase(WINHASH_KEY(window));
|
|
m_hashWindows[WINHASH_KEY(window)] = text;
|
|
}
|
|
|
|
void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text)
|
|
{
|
|
wxSimpleHelpProviderHashMap::key_type key = (wxSimpleHelpProviderHashMap::key_type)id;
|
|
m_hashIds.erase(key);
|
|
m_hashIds[key] = text;
|
|
}
|
|
|
|
// removes the association
|
|
void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
|
|
{
|
|
m_hashWindows.erase(WINHASH_KEY(window));
|
|
}
|
|
|
|
bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
|
|
{
|
|
#if wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
|
|
#if wxUSE_MS_HTML_HELP
|
|
// m_helptextAtPoint will be reset by GetHelpTextMaybeAtPoint(), stash it
|
|
const wxPoint posTooltip = m_helptextAtPoint;
|
|
#endif // wxUSE_MS_HTML_HELP
|
|
|
|
const wxString text = GetHelpTextMaybeAtPoint(window);
|
|
|
|
if ( !text.empty() )
|
|
{
|
|
// use the native help popup style if it's available
|
|
#if wxUSE_MS_HTML_HELP
|
|
if ( !wxCHMHelpController::ShowContextHelpPopup
|
|
(
|
|
text,
|
|
posTooltip,
|
|
(wxWindow *)window
|
|
) )
|
|
#endif // wxUSE_MS_HTML_HELP
|
|
{
|
|
#if wxUSE_TIPWINDOW
|
|
static wxTipWindow* s_tipWindow = NULL;
|
|
|
|
if ( s_tipWindow )
|
|
{
|
|
// Prevent s_tipWindow being nulled in OnIdle, thereby removing
|
|
// the chance for the window to be closed by ShowHelp
|
|
s_tipWindow->SetTipWindowPtr(NULL);
|
|
s_tipWindow->Close();
|
|
}
|
|
|
|
s_tipWindow = new wxTipWindow((wxWindow *)window, text,
|
|
100, &s_tipWindow);
|
|
#else // !wxUSE_TIPWINDOW
|
|
// we tried wxCHMHelpController but it failed and we don't have
|
|
// wxTipWindow to fall back on, so
|
|
return false;
|
|
#endif // wxUSE_TIPWINDOW
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#else // !wxUSE_MS_HTML_HELP && !wxUSE_TIPWINDOW
|
|
wxUnusedVar(window);
|
|
#endif // wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
|
|
|
|
return false;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxHelpControllerHelpProvider
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
|
|
{
|
|
m_helpController = hc;
|
|
}
|
|
|
|
bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
|
|
{
|
|
const wxString text = GetHelpTextMaybeAtPoint(window);
|
|
|
|
if ( text.empty() )
|
|
return false;
|
|
|
|
if ( m_helpController )
|
|
{
|
|
// if it's a numeric topic, show it
|
|
long topic;
|
|
if ( text.ToLong(&topic) )
|
|
return m_helpController->DisplayContextPopup(topic);
|
|
|
|
// otherwise show the text directly
|
|
if ( m_helpController->DisplayTextPopup(text, wxGetMousePosition()) )
|
|
return true;
|
|
}
|
|
|
|
// if there is no help controller or it's not capable of showing the help,
|
|
// fallback to the default method
|
|
return wxSimpleHelpProvider::ShowHelp(window);
|
|
}
|
|
|
|
// Convenience function for turning context id into wxString
|
|
wxString wxContextId(int id)
|
|
{
|
|
return wxString::Format(_T("%d"), id);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxHelpProviderModule: module responsible for cleaning up help provider.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class wxHelpProviderModule : public wxModule
|
|
{
|
|
public:
|
|
bool OnInit();
|
|
void OnExit();
|
|
|
|
private:
|
|
DECLARE_DYNAMIC_CLASS(wxHelpProviderModule)
|
|
};
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule)
|
|
|
|
bool wxHelpProviderModule::OnInit()
|
|
{
|
|
// Probably we don't want to do anything by default,
|
|
// since it could pull in extra code
|
|
// wxHelpProvider::Set(new wxSimpleHelpProvider);
|
|
|
|
return true;
|
|
}
|
|
|
|
void wxHelpProviderModule::OnExit()
|
|
{
|
|
if (wxHelpProvider::Get())
|
|
{
|
|
delete wxHelpProvider::Get();
|
|
wxHelpProvider::Set(NULL);
|
|
}
|
|
}
|
|
|
|
#endif // wxUSE_HELP
|