QskShortcut moved to QskShortcutMap, new class QskShortcut for the QML
use case ( makes sense from C++ as well, but is less efficient as it needs one QObject per shortcut )
This commit is contained in:
parent
ccf1834a9c
commit
c1e7571e10
@ -1,7 +1,7 @@
|
||||
#include "MainWindow.h"
|
||||
#include "SkinFactory.h"
|
||||
|
||||
#include <QskShortcut.h>
|
||||
#include <QskShortcutMap.h>
|
||||
#include <QskSetup.h>
|
||||
#include <SkinnyShortcut.h>
|
||||
|
||||
@ -35,10 +35,10 @@ int main( int argc, char** argv )
|
||||
cout << "CTRL-S to change the skin." << endl;
|
||||
cout << "CTRL-T to change the color scheme, when the \"Default\" skin is active." << endl;
|
||||
|
||||
QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_T ),
|
||||
QskShortcutMap::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_T ),
|
||||
false, &skinFactory, SLOT(toggleScheme()) );
|
||||
|
||||
QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_S ),
|
||||
QskShortcutMap::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_S ),
|
||||
false, &skinFactory, SLOT(rotateSkin()) );
|
||||
|
||||
// With CTRL-B you can rotate a couple of visual debug modes
|
||||
|
@ -12,6 +12,12 @@ Qsk.Window
|
||||
height: 600
|
||||
color: "Beige"
|
||||
|
||||
Qsk.Shortcut
|
||||
{
|
||||
sequence : "Ctrl+X"
|
||||
onActivated: console.log( "Ctrl+X" )
|
||||
}
|
||||
|
||||
Qsk.LinearBox
|
||||
{
|
||||
orientation: Qt.Horizontal
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <QskGraphicLabel.h>
|
||||
#include <QskGradient.h>
|
||||
#include <QskAspect.h>
|
||||
#include <QskShortcut.h>
|
||||
#include <QskShortcutMap.h>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QKeySequence>
|
||||
@ -34,7 +34,7 @@ public:
|
||||
setSizePolicy( QskSizePolicy::MinimumExpanding,
|
||||
QskSizePolicy::MinimumExpanding );
|
||||
|
||||
QskShortcut::addShortcut( this, QKeySequence( Qt::Key_P ), true,
|
||||
QskShortcutMap::addShortcut( this, QKeySequence( Qt::Key_P ), true,
|
||||
[=] { qDebug() << graphicSource; } );
|
||||
}
|
||||
};
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "QskScrollArea.h"
|
||||
#include "QskSeparator.h"
|
||||
#include "QskSimpleListBox.h"
|
||||
#include "QskShortcut.h"
|
||||
#include "QskSlider.h"
|
||||
#include "QskStackBox.h"
|
||||
#include "QskStandardSymbol.h"
|
||||
@ -239,6 +240,7 @@ void QskModule::registerTypes()
|
||||
qRegisterMetaType< QskSkin* >();
|
||||
|
||||
QSK_REGISTER( QskMain, "Main" );
|
||||
QSK_REGISTER( QskShortcut, "Shortcut" );
|
||||
|
||||
QSK_REGISTER( QskWindow, "Window" );
|
||||
|
||||
|
@ -4,245 +4,221 @@
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskShortcut.h"
|
||||
#include "QskControl.h"
|
||||
|
||||
#include "QskShortcutMap.h"
|
||||
#include <QQuickItem>
|
||||
#include <QQuickWindow>
|
||||
#include <QMetaMethod>
|
||||
#include <QKeySequence>
|
||||
#include <QGlobalStatic>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
static inline QShortcutMap& qskShortcutMap()
|
||||
{
|
||||
return QGuiApplicationPrivate::instance()->shortcutMap;
|
||||
}
|
||||
|
||||
class QskShortcutHandler final : public QObject
|
||||
{
|
||||
public:
|
||||
QskShortcutHandler();
|
||||
|
||||
int add( QQuickItem*, const QKeySequence&,
|
||||
const QObject* receiver, const char* method );
|
||||
|
||||
int add( QQuickItem*, const QKeySequence&,
|
||||
const QObject* receiver, QtPrivate::QSlotObjectBase* );
|
||||
|
||||
void remove( int id );
|
||||
|
||||
void setEnabled( int id, bool );
|
||||
void setAutoRepeat( int id, bool repeat );
|
||||
|
||||
virtual bool eventFilter( QObject*, QEvent* ) override final;
|
||||
|
||||
private:
|
||||
int insert( QQuickItem*, const QKeySequence&,
|
||||
const QObject* receiver, const QMetaMethod&, QtPrivate::QSlotObjectBase* );
|
||||
|
||||
void cleanUp( QObject* );
|
||||
|
||||
static bool contextMatcher( QObject*, Qt::ShortcutContext );
|
||||
|
||||
class InvokeData
|
||||
{
|
||||
public:
|
||||
InvokeData():
|
||||
item( nullptr ),
|
||||
receiver( nullptr ),
|
||||
slotObject( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
~InvokeData()
|
||||
{
|
||||
if ( slotObject )
|
||||
slotObject->destroyIfLastRef();
|
||||
}
|
||||
|
||||
QQuickItem* item;
|
||||
const QObject* receiver;
|
||||
QMetaMethod method;
|
||||
QtPrivate::QSlotObjectBase* slotObject;
|
||||
};
|
||||
|
||||
std::map< int, InvokeData > m_invokeDataMap;
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC( QskShortcutHandler, qskShortcutHandler )
|
||||
|
||||
QskShortcutHandler::QskShortcutHandler()
|
||||
{
|
||||
installEventFilter( this );
|
||||
}
|
||||
|
||||
int QskShortcutHandler::add( QQuickItem* item, const QKeySequence& key,
|
||||
const QObject* receiver, const char* method )
|
||||
{
|
||||
int id = 0;
|
||||
|
||||
if ( receiver )
|
||||
{
|
||||
const QMetaObject* metaObject = receiver->metaObject();
|
||||
|
||||
const int methodIndex = metaObject->indexOfMethod(
|
||||
QMetaObject::normalizedSignature( method ).constData() + 1 );
|
||||
|
||||
if ( methodIndex >= 0 )
|
||||
{
|
||||
id = insert( item, key,
|
||||
receiver, metaObject->method( methodIndex ), nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int QskShortcutHandler::add( QQuickItem* item, const QKeySequence& key,
|
||||
const QObject* receiver, QtPrivate::QSlotObjectBase* slotObj )
|
||||
{
|
||||
return insert( item, key, receiver, QMetaMethod(), slotObj );
|
||||
}
|
||||
|
||||
int QskShortcutHandler::insert(
|
||||
QQuickItem* item, const QKeySequence& key,
|
||||
const QObject* receiver, const QMetaMethod& method,
|
||||
QtPrivate::QSlotObjectBase* slotObject )
|
||||
{
|
||||
if ( receiver )
|
||||
{
|
||||
receiver->disconnect( this );
|
||||
connect( receiver, &QObject::destroyed, this, &QskShortcutHandler::cleanUp );
|
||||
}
|
||||
|
||||
int id = 0;
|
||||
|
||||
auto& map = qskShortcutMap();
|
||||
|
||||
if ( item )
|
||||
{
|
||||
if ( item != receiver )
|
||||
{
|
||||
item->disconnect( this );
|
||||
connect( item, &QObject::destroyed, this, &QskShortcutHandler::cleanUp );
|
||||
}
|
||||
|
||||
id = map.addShortcut( item, key, Qt::WindowShortcut, contextMatcher );
|
||||
}
|
||||
else
|
||||
{
|
||||
id = map.addShortcut( this, key, Qt::ApplicationShortcut, contextMatcher );
|
||||
}
|
||||
|
||||
auto& data = m_invokeDataMap[ id ];
|
||||
|
||||
data.item = item;
|
||||
data.receiver = receiver;
|
||||
|
||||
if ( slotObject )
|
||||
data.slotObject = slotObject;
|
||||
else
|
||||
data.method = method;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void QskShortcutHandler::remove( int id )
|
||||
{
|
||||
auto it = m_invokeDataMap.find( id );
|
||||
if ( it == m_invokeDataMap.end() )
|
||||
return;
|
||||
|
||||
auto& map = qskShortcutMap();
|
||||
map.removeShortcut( id, nullptr );
|
||||
|
||||
const QQuickItem* item = it->second.item;
|
||||
const QObject* receiver = it->second.receiver;
|
||||
|
||||
m_invokeDataMap.erase( it );
|
||||
|
||||
/*
|
||||
Finally let's check if we can disconnect
|
||||
from the destroyed signals
|
||||
*/
|
||||
for ( const auto& entry : qskAsConst( m_invokeDataMap ) )
|
||||
{
|
||||
if ( item == nullptr && receiver == nullptr )
|
||||
break;
|
||||
|
||||
if ( entry.second.item == item )
|
||||
item = nullptr;
|
||||
|
||||
if ( entry.second.receiver == receiver )
|
||||
receiver = nullptr;
|
||||
}
|
||||
|
||||
if ( item )
|
||||
item->disconnect( this );
|
||||
|
||||
if ( receiver && receiver != item )
|
||||
receiver->disconnect( this );
|
||||
}
|
||||
|
||||
void QskShortcutHandler::cleanUp( QObject* object )
|
||||
{
|
||||
/*
|
||||
When item != receiver we might remain being connected
|
||||
to destroyed signals we are not interested in anymore. TODO ...
|
||||
*/
|
||||
auto& map = qskShortcutMap();
|
||||
|
||||
for ( auto it = m_invokeDataMap.begin(); it != m_invokeDataMap.end(); )
|
||||
{
|
||||
const auto& data = it->second;
|
||||
|
||||
if ( data.item == object || data.receiver == object )
|
||||
{
|
||||
map.removeShortcut( it->first, nullptr );
|
||||
it = m_invokeDataMap.erase( it );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
bool QskShortcutHandler::contextMatcher( QObject* object, Qt::ShortcutContext context )
|
||||
static bool qskContextMatcher( QObject* object, Qt::ShortcutContext context )
|
||||
{
|
||||
if ( context == Qt::ApplicationShortcut )
|
||||
return true;
|
||||
|
||||
if ( context == Qt::WindowShortcut )
|
||||
{
|
||||
const auto focusWindow = QGuiApplication::focusWindow();
|
||||
if ( const auto shortcut = qobject_cast< const QskShortcut* >( object ) )
|
||||
return shortcut->isFocusInScope();
|
||||
}
|
||||
|
||||
if ( auto item = qobject_cast< const QQuickItem* >( object ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
class QskShortcut::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
id( 0 ),
|
||||
autoRepeat( true ),
|
||||
enabled( true ),
|
||||
isWindowContext( true ),
|
||||
isComplete( true )
|
||||
{
|
||||
}
|
||||
|
||||
~PrivateData()
|
||||
{
|
||||
if ( id != 0 )
|
||||
qskShortcutMap().removeShortcut( id, nullptr );
|
||||
}
|
||||
|
||||
void resetShortcut( QskShortcut* shortcut )
|
||||
{
|
||||
if ( !isComplete )
|
||||
return;
|
||||
|
||||
auto& map = qskShortcutMap();
|
||||
|
||||
const int oldId = id;
|
||||
|
||||
if ( id != 0 )
|
||||
{
|
||||
const auto window = item->window();
|
||||
if ( window == nullptr || window != focusWindow )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
map.removeShortcut( id, nullptr );
|
||||
id = 0;
|
||||
}
|
||||
|
||||
while ( item )
|
||||
{
|
||||
/*
|
||||
We have to find out if the active focus is inside
|
||||
the surronding shortcut scope.
|
||||
*/
|
||||
if ( QskControl::isShortcutScope( item ) )
|
||||
{
|
||||
if ( !item->hasFocus() )
|
||||
return false;
|
||||
}
|
||||
if ( !sequence.isEmpty() )
|
||||
{
|
||||
id = map.addShortcut( shortcut, sequence,
|
||||
shortcut->context(), qskContextMatcher );
|
||||
|
||||
item = item->parentItem();
|
||||
}
|
||||
if ( !autoRepeat )
|
||||
map.setShortcutAutoRepeat( false, id, shortcut );
|
||||
|
||||
if ( !enabled )
|
||||
map.setShortcutEnabled( false, id, shortcut );
|
||||
}
|
||||
|
||||
if ( oldId != id )
|
||||
shortcut->Q_EMIT shortcutIdChanged( id );
|
||||
}
|
||||
|
||||
public:
|
||||
QKeySequence sequence;
|
||||
|
||||
int id;
|
||||
|
||||
bool autoRepeat : 1;
|
||||
bool enabled : 1;
|
||||
bool isWindowContext : 1;
|
||||
bool isComplete : 1;
|
||||
};
|
||||
|
||||
QskShortcut::QskShortcut( QObject* parent ):
|
||||
Inherited( parent ),
|
||||
m_data( new PrivateData )
|
||||
{
|
||||
}
|
||||
|
||||
QskShortcut::QskShortcut( const QKeySequence& sequence, QObject* parent ):
|
||||
QskShortcut( sequence, Qt::WindowShortcut, parent )
|
||||
{
|
||||
}
|
||||
|
||||
QskShortcut::QskShortcut( const QKeySequence& sequence,
|
||||
Qt::ShortcutContext context, QObject* parent ):
|
||||
Inherited( parent ),
|
||||
m_data( new PrivateData )
|
||||
{
|
||||
m_data->sequence = sequence;
|
||||
m_data->isWindowContext = ( context == Qt::WindowShortcut );
|
||||
m_data->resetShortcut( this );
|
||||
}
|
||||
|
||||
QskShortcut::~QskShortcut()
|
||||
{
|
||||
}
|
||||
|
||||
int QskShortcut::shortcutId() const
|
||||
{
|
||||
return m_data->id;
|
||||
}
|
||||
|
||||
Qt::ShortcutContext QskShortcut::context() const
|
||||
{
|
||||
return m_data->isWindowContext
|
||||
? Qt::WindowShortcut : Qt::ApplicationShortcut;
|
||||
}
|
||||
|
||||
void QskShortcut::setContext( Qt::ShortcutContext context )
|
||||
{
|
||||
if ( context == Qt::ApplicationShortcut
|
||||
|| context == Qt::WindowShortcut )
|
||||
{
|
||||
const bool isWindowContext = ( context == Qt::WindowShortcut );
|
||||
|
||||
if ( isWindowContext != m_data->isWindowContext )
|
||||
{
|
||||
m_data->isWindowContext = isWindowContext;
|
||||
m_data->resetShortcut( this );
|
||||
|
||||
Q_EMIT contextChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QskShortcut::setSequence( const QKeySequence& sequence )
|
||||
{
|
||||
if ( sequence != m_data->sequence )
|
||||
{
|
||||
m_data->sequence = sequence;
|
||||
m_data->resetShortcut( this );
|
||||
|
||||
Q_EMIT sequenceChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QKeySequence QskShortcut::sequence() const
|
||||
{
|
||||
return m_data->sequence;
|
||||
}
|
||||
|
||||
void QskShortcut::setSequenceVariant( const QVariant& sequence )
|
||||
{
|
||||
if ( sequence.type() == QVariant::Int )
|
||||
setSequence( static_cast<QKeySequence::StandardKey>( sequence.toInt() ) );
|
||||
else
|
||||
setSequence( QKeySequence::fromString( sequence.toString() ) );
|
||||
}
|
||||
|
||||
QVariant QskShortcut::sequenceVariant() const
|
||||
{
|
||||
return m_data->sequence.toString();
|
||||
}
|
||||
|
||||
void QskShortcut::setEnabled( bool on )
|
||||
{
|
||||
if ( on != m_data->enabled )
|
||||
{
|
||||
m_data->enabled = on;
|
||||
|
||||
if ( m_data->id != 0 )
|
||||
qskShortcutMap().setShortcutEnabled( on, m_data->id, this );
|
||||
|
||||
Q_EMIT enabledChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool QskShortcut::isEnabled() const
|
||||
{
|
||||
return m_data->enabled;
|
||||
}
|
||||
|
||||
void QskShortcut::setAutoRepeat( bool on )
|
||||
{
|
||||
if ( on != m_data->autoRepeat )
|
||||
{
|
||||
m_data->autoRepeat = on;
|
||||
|
||||
if ( m_data->id != 0 )
|
||||
qskShortcutMap().setShortcutEnabled( on, m_data->id, this );
|
||||
|
||||
Q_EMIT autoRepeatChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool QskShortcut::autoRepeat() const
|
||||
{
|
||||
return m_data->autoRepeat;
|
||||
}
|
||||
|
||||
bool QskShortcut::event( QEvent* event )
|
||||
{
|
||||
if ( event->type() == QEvent::Shortcut )
|
||||
{
|
||||
auto* shortcutEvent = static_cast< QShortcutEvent* >( event );
|
||||
|
||||
if ( shortcutEvent->shortcutId() == m_data->id )
|
||||
{
|
||||
if ( shortcutEvent->isAmbiguous() )
|
||||
Q_EMIT activatedAmbiguously();
|
||||
else
|
||||
Q_EMIT activated();
|
||||
|
||||
// we want to process the following QShortcutEvent
|
||||
object->installEventFilter( qskShortcutHandler );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -250,105 +226,46 @@ bool QskShortcutHandler::contextMatcher( QObject* object, Qt::ShortcutContext co
|
||||
return false;
|
||||
}
|
||||
|
||||
void QskShortcutHandler::setEnabled( int id, bool enabled )
|
||||
bool QskShortcut::isFocusInScope() const
|
||||
{
|
||||
auto& map = qskShortcutMap();
|
||||
map.setShortcutEnabled( enabled, id, this );
|
||||
}
|
||||
|
||||
void QskShortcutHandler::setAutoRepeat( int id, bool repeat )
|
||||
{
|
||||
auto& map = qskShortcutMap();
|
||||
map.setShortcutAutoRepeat( repeat, id, this );
|
||||
}
|
||||
|
||||
bool QskShortcutHandler::eventFilter( QObject* object, QEvent* event )
|
||||
{
|
||||
if ( event->type() != QEvent::Shortcut )
|
||||
return false;
|
||||
|
||||
if ( object != this )
|
||||
object->removeEventFilter( this );
|
||||
|
||||
const QShortcutEvent* se = static_cast< const QShortcutEvent* >( event );
|
||||
|
||||
#if 0
|
||||
// do we want to handle this ???
|
||||
if ( se->isAmbiguous() )
|
||||
....
|
||||
#endif
|
||||
|
||||
const auto it = m_invokeDataMap.find( se->shortcutId() );
|
||||
if ( it != m_invokeDataMap.end() )
|
||||
{
|
||||
const auto& invokeData = it->second;
|
||||
|
||||
Q_ASSERT( invokeData.item == nullptr || invokeData.item == object );
|
||||
|
||||
auto receiver = const_cast< QObject* >( invokeData.receiver );
|
||||
|
||||
if ( invokeData.slotObject )
|
||||
{
|
||||
void* args[] = { 0 };
|
||||
|
||||
if ( receiver && receiver->thread() != thread() )
|
||||
{
|
||||
QCoreApplication::postEvent( receiver,
|
||||
new QMetaCallEvent( invokeData.slotObject, nullptr, 0, 0, nullptr, args ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
invokeData.slotObject->call( receiver, args );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
invokeData.method.invoke( receiver, Qt::AutoConnection );
|
||||
}
|
||||
|
||||
if ( !m_data->isWindowContext )
|
||||
return true;
|
||||
}
|
||||
|
||||
// seems like someone else is also interested in shortcuts
|
||||
return false;
|
||||
}
|
||||
const QQuickItem* contextItem = nullptr;
|
||||
|
||||
int QskShortcut::addMethod( QQuickItem* item, const QKeySequence& key,
|
||||
bool autoRepeat, const QObject* receiver, const char* method )
|
||||
{
|
||||
if ( receiver == nullptr )
|
||||
if ( parent()->isWindowType() )
|
||||
{
|
||||
return 0;
|
||||
if ( auto window = qobject_cast< const QQuickWindow* >( parent() ) )
|
||||
contextItem = window->contentItem();
|
||||
}
|
||||
else
|
||||
{
|
||||
contextItem = qobject_cast< const QQuickItem* >( parent() );
|
||||
}
|
||||
|
||||
int id = qskShortcutHandler->add( item, key, receiver, method );
|
||||
if ( id && !autoRepeat )
|
||||
qskShortcutHandler->setAutoRepeat( id, false );
|
||||
|
||||
return id;
|
||||
if ( contextItem )
|
||||
{
|
||||
return QskShortcutMap::contextMatcher( contextItem, Qt::WindowShortcut );
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning( "QskShortcut has no valid parent for Qt::WindowShortcut" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int QskShortcut::addSlotObject( QQuickItem* item, const QKeySequence& key,
|
||||
bool autoRepeat, const QObject* receiver, QtPrivate::QSlotObjectBase* slotObject )
|
||||
void QskShortcut::classBegin()
|
||||
{
|
||||
int id = qskShortcutHandler->add( item, key, receiver, slotObject );
|
||||
if ( id && !autoRepeat )
|
||||
qskShortcutHandler->setAutoRepeat( id, false );
|
||||
|
||||
return id;
|
||||
m_data->isComplete = false;
|
||||
}
|
||||
|
||||
void QskShortcut::setAutoRepeat( int id, bool on )
|
||||
void QskShortcut::componentComplete()
|
||||
{
|
||||
qskShortcutHandler->setAutoRepeat( id, on );
|
||||
if ( m_data->isComplete == false )
|
||||
{
|
||||
m_data->isComplete = true;
|
||||
m_data->resetShortcut( this );
|
||||
}
|
||||
}
|
||||
|
||||
void QskShortcut::setEnabled( int id, bool on )
|
||||
{
|
||||
qskShortcutHandler->setEnabled( id, on );
|
||||
}
|
||||
|
||||
void QskShortcut::removeShortcut( int id )
|
||||
{
|
||||
qskShortcutHandler->remove( id );
|
||||
}
|
||||
#include "moc_QskShortcut.cpp"
|
||||
|
@ -7,219 +7,87 @@
|
||||
#define QSK_SHORTCUT_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include <QQuickWindow>
|
||||
|
||||
class QQuickItem;
|
||||
#include <QObject>
|
||||
#include <QQmlParserStatus>
|
||||
#include <Qt>
|
||||
#include <memory>
|
||||
|
||||
class QKeySequence;
|
||||
|
||||
class QSK_EXPORT QskShortcut
|
||||
/*
|
||||
For QML, with C++ there is also QskShortcutMap that does
|
||||
not need to create QObjects per shortcut
|
||||
*/
|
||||
class QSK_EXPORT QskShortcut : public QObject, public QQmlParserStatus
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES( QQmlParserStatus )
|
||||
|
||||
Q_PROPERTY( QVariant sequence READ sequenceVariant
|
||||
WRITE setSequenceVariant NOTIFY sequenceChanged FINAL)
|
||||
|
||||
Q_PROPERTY( Qt::ShortcutContext context READ context
|
||||
WRITE setContext NOTIFY contextChanged )
|
||||
|
||||
Q_PROPERTY( bool enabled READ isEnabled
|
||||
WRITE setEnabled NOTIFY enabledChanged )
|
||||
|
||||
Q_PROPERTY( bool autoRepeat READ autoRepeat
|
||||
WRITE setAutoRepeat NOTIFY autoRepeatChanged )
|
||||
|
||||
Q_PROPERTY( int shortcutId READ shortcutId
|
||||
NOTIFY shortcutIdChanged )
|
||||
|
||||
using Inherited = QObject;
|
||||
|
||||
public:
|
||||
static void setAutoRepeat( int, bool on );
|
||||
static void setEnabled( int, bool on );
|
||||
QskShortcut( QObject* parent = nullptr );
|
||||
|
||||
static void removeShortcut( int );
|
||||
QskShortcut( const QKeySequence&, QObject* = nullptr );
|
||||
QskShortcut( const QKeySequence&, Qt::ShortcutContext, QObject* = nullptr );
|
||||
|
||||
// -- traditional slots
|
||||
static int addShortcut( const QKeySequence&, bool autoRepeat,
|
||||
const QObject* receiver, const char* method );
|
||||
virtual ~QskShortcut();
|
||||
|
||||
static int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat,
|
||||
const QObject* receiver, const char* method );
|
||||
int shortcutId() const;
|
||||
|
||||
static int addShortcut( QQuickItem*, const QKeySequence&, bool autoRepeat,
|
||||
const QObject* receiver, const char* method );
|
||||
void setSequence( const QKeySequence& );
|
||||
QKeySequence sequence() const;
|
||||
|
||||
// -- calling a QObject method
|
||||
template< typename Func1 >
|
||||
static int addShortcut( const QKeySequence&, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot );
|
||||
// for QML
|
||||
void setSequenceVariant( const QVariant& );
|
||||
QVariant sequenceVariant() const;
|
||||
|
||||
template< typename Func1 >
|
||||
static int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot );
|
||||
Qt::ShortcutContext context() const;
|
||||
void setContext(Qt::ShortcutContext context);
|
||||
|
||||
template< typename Func1 >
|
||||
static int addShortcut( QQuickItem*, const QKeySequence&, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot );
|
||||
void setEnabled( bool );
|
||||
bool isEnabled() const;
|
||||
|
||||
// -- calling a functor or function pointer inside a thread context
|
||||
template< typename Func1 >
|
||||
static int addShortcut( const QKeySequence&, bool autoRepeat,
|
||||
const QObject* context, Func1 slot );
|
||||
void setAutoRepeat( bool );
|
||||
bool autoRepeat() const;
|
||||
|
||||
template< typename Func1 >
|
||||
static int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat,
|
||||
const QObject* context, Func1 slot );
|
||||
virtual bool isFocusInScope() const;
|
||||
|
||||
template< typename Func1 >
|
||||
static int addShortcut( QQuickItem*, const QKeySequence&, bool autoRepeat,
|
||||
const QObject* context, Func1 slot );
|
||||
Q_SIGNALS:
|
||||
void sequenceChanged();
|
||||
void contextChanged();
|
||||
void enabledChanged();
|
||||
void autoRepeatChanged();
|
||||
|
||||
// -- calling a functor or function pointer
|
||||
template< typename Func1 >
|
||||
static int addShortcut( const QKeySequence&, bool autoRepeat, Func1 slot );
|
||||
void activated();
|
||||
void activatedAmbiguously();
|
||||
|
||||
template< typename Func1 >
|
||||
static int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat, Func1 slot );
|
||||
int shortcutIdChanged( int ) const;
|
||||
|
||||
template< typename Func1 >
|
||||
static int addShortcut( QQuickItem*, const QKeySequence&, bool autoRepeat, Func1 slot );
|
||||
protected:
|
||||
virtual bool event( QEvent* ) override;
|
||||
virtual void classBegin() override;
|
||||
virtual void componentComplete() override;
|
||||
|
||||
private:
|
||||
QskShortcut() = delete;
|
||||
~QskShortcut() = delete;
|
||||
|
||||
static int addMethod( QQuickItem*, const QKeySequence&, bool autoRepeat,
|
||||
const QObject* receiver, const char* method );
|
||||
|
||||
template< typename Func1 >
|
||||
static int addMemberSlot( QQuickItem*, const QKeySequence&, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot );
|
||||
|
||||
template< typename Func1 >
|
||||
static int addFunctorSlot( QQuickItem*, const QKeySequence&,
|
||||
bool autoRepeat, const QObject* context, Func1 slot );
|
||||
|
||||
static int addSlotObject(
|
||||
QQuickItem* item, const QKeySequence&, bool autoRepeat,
|
||||
const QObject* receiver, QtPrivate::QSlotObjectBase* );
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcut::addMemberSlot(
|
||||
QQuickItem* item, const QKeySequence& key, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot )
|
||||
{
|
||||
using namespace QtPrivate;
|
||||
typedef FunctionPointer< Func1 > SlotType;
|
||||
|
||||
Q_STATIC_ASSERT_X( int( SlotType::ArgumentCount ) == 0,
|
||||
"The slot must not have any arguments.");
|
||||
|
||||
return addSlotObject( item, key, autoRepeat, receiver,
|
||||
new QSlotObject< Func1, typename SlotType::Arguments, void >( slot ) );
|
||||
}
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcut::addFunctorSlot(
|
||||
QQuickItem* item, const QKeySequence& key, bool autoRepeat,
|
||||
const QObject* context, Func1 slot )
|
||||
{
|
||||
using namespace QtPrivate;
|
||||
typedef FunctionPointer< Func1 > SlotType;
|
||||
|
||||
Q_STATIC_ASSERT_X( int( SlotType::ArgumentCount ) <= 0,
|
||||
"The slot must not have any arguments.");
|
||||
|
||||
Q_STATIC_ASSERT_X( !SlotType::IsPointerToMemberFunction,
|
||||
"The slot must be no member function." );
|
||||
|
||||
using Args = List_Left< void, 0 >::Value;
|
||||
|
||||
return addSlotObject( item, key, autoRepeat, context,
|
||||
new QFunctorSlotObject< Func1, 0, Args, void >( slot ) );
|
||||
}
|
||||
|
||||
// -- traditional slots
|
||||
|
||||
inline int QskShortcut::addShortcut(
|
||||
QQuickItem* item, const QKeySequence& key, bool autoRepeat,
|
||||
const QObject* receiver, const char* method )
|
||||
{
|
||||
return addMethod( item, key, autoRepeat, receiver, method );
|
||||
}
|
||||
|
||||
inline int QskShortcut::addShortcut(
|
||||
const QKeySequence& key, bool autoRepeat,
|
||||
const QObject* receiver, const char* method )
|
||||
{
|
||||
return addMethod( nullptr, key, autoRepeat, receiver, method );
|
||||
}
|
||||
|
||||
inline int QskShortcut::addShortcut(
|
||||
QQuickWindow* window, const QKeySequence& key, bool autoRepeat,
|
||||
const QObject* receiver, const char* method )
|
||||
{
|
||||
auto item = window ? window->contentItem() : nullptr;
|
||||
return addMethod( item, key, autoRepeat, receiver, method );
|
||||
}
|
||||
|
||||
// -- calling a QObject method
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcut::addShortcut(
|
||||
QQuickItem* item, const QKeySequence& key, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot )
|
||||
{
|
||||
return addMemberSlot( item, key, autoRepeat, receiver, slot );
|
||||
}
|
||||
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcut::addShortcut(
|
||||
QQuickWindow* window, const QKeySequence& key, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot )
|
||||
{
|
||||
auto item = window ? window->contentItem() : nullptr;
|
||||
return addMemberSlot( item, key, autoRepeat, receiver, slot );
|
||||
}
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcut::addShortcut(
|
||||
const QKeySequence& key, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot )
|
||||
{
|
||||
return addMemberSlot( nullptr, key, autoRepeat, receiver, slot );
|
||||
}
|
||||
|
||||
// -- calling a functor or function pointer with context
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcut::addShortcut(
|
||||
QQuickItem* item, const QKeySequence& key, bool autoRepeat,
|
||||
const QObject* context, Func1 slot )
|
||||
{
|
||||
return addFunctorSlot( item, key, autoRepeat, context, slot );
|
||||
}
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcut::addShortcut(
|
||||
QQuickWindow* window, const QKeySequence& key, bool autoRepeat,
|
||||
const QObject* context, Func1 slot )
|
||||
{
|
||||
auto item = window ? window->contentItem() : nullptr;
|
||||
return addFunctorSlot( item, key, autoRepeat, context, slot );
|
||||
}
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcut::addShortcut( const QKeySequence& key, bool autoRepeat,
|
||||
const QObject* context, Func1 slot )
|
||||
{
|
||||
return addFunctorSlot( nullptr, key, autoRepeat, context, slot );
|
||||
}
|
||||
|
||||
// -- calling a functor or function pointer
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcut::addShortcut(
|
||||
QQuickItem* item, const QKeySequence& key, bool autoRepeat, Func1 slot )
|
||||
{
|
||||
return addFunctorSlot( item, key, autoRepeat, nullptr, slot );
|
||||
}
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcut::addShortcut(
|
||||
QQuickWindow* window, const QKeySequence& key, bool autoRepeat, Func1 slot )
|
||||
{
|
||||
auto item = window ? window->contentItem() : nullptr;
|
||||
return addFunctorSlot( item, key, autoRepeat, nullptr, autoRepeat, slot );
|
||||
}
|
||||
|
||||
template< typename Func1 >
|
||||
int QskShortcut::addShortcut( const QKeySequence& key, bool autoRepeat, Func1 slot )
|
||||
{
|
||||
return addFunctorSlot( nullptr, key, autoRepeat, nullptr, slot );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
375
src/controls/QskShortcutMap.cpp
Normal file
375
src/controls/QskShortcutMap.cpp
Normal file
@ -0,0 +1,375 @@
|
||||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskShortcutMap.h"
|
||||
#include "QskControl.h"
|
||||
|
||||
#include <QQuickWindow>
|
||||
#include <QMetaMethod>
|
||||
#include <QKeySequence>
|
||||
#include <QGlobalStatic>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
static inline QShortcutMap& qskShortcutMap()
|
||||
{
|
||||
return QGuiApplicationPrivate::instance()->shortcutMap;
|
||||
}
|
||||
|
||||
class QskShortcutHandler final : public QObject
|
||||
{
|
||||
public:
|
||||
QskShortcutHandler();
|
||||
|
||||
int add( QQuickItem*, const QKeySequence&,
|
||||
const QObject* receiver, const char* method );
|
||||
|
||||
int add( QQuickItem*, const QKeySequence&,
|
||||
const QObject* receiver, QtPrivate::QSlotObjectBase* );
|
||||
|
||||
void remove( int id );
|
||||
|
||||
void setEnabled( int id, bool );
|
||||
void setAutoRepeat( int id, bool repeat );
|
||||
|
||||
virtual bool eventFilter( QObject*, QEvent* ) override final;
|
||||
|
||||
private:
|
||||
int insert( QQuickItem*, const QKeySequence&,
|
||||
const QObject* receiver, const QMetaMethod&, QtPrivate::QSlotObjectBase* );
|
||||
|
||||
void cleanUp( QObject* );
|
||||
|
||||
class InvokeData
|
||||
{
|
||||
public:
|
||||
InvokeData():
|
||||
item( nullptr ),
|
||||
receiver( nullptr ),
|
||||
slotObject( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
~InvokeData()
|
||||
{
|
||||
if ( slotObject )
|
||||
slotObject->destroyIfLastRef();
|
||||
}
|
||||
|
||||
QQuickItem* item;
|
||||
const QObject* receiver;
|
||||
QMetaMethod method;
|
||||
QtPrivate::QSlotObjectBase* slotObject;
|
||||
};
|
||||
|
||||
std::map< int, InvokeData > m_invokeDataMap;
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC( QskShortcutHandler, qskShortcutHandler )
|
||||
|
||||
static bool qskContextMatcher( QObject* object, Qt::ShortcutContext context )
|
||||
{
|
||||
if ( context == Qt::ApplicationShortcut )
|
||||
return true;
|
||||
|
||||
auto item = qobject_cast< QQuickItem* >( object );
|
||||
if ( item && context == Qt::WindowShortcut )
|
||||
{
|
||||
if ( QskShortcutMap::contextMatcher( item, context ) )
|
||||
{
|
||||
/*
|
||||
Unfortunatley there is no way to have to know about
|
||||
the contextItem without making it the receiver of
|
||||
the following QShortcutEvent. So we have to install
|
||||
an event handler to process and swallow it in QskShortcutHandler.
|
||||
*/
|
||||
|
||||
item->installEventFilter( qskShortcutHandler );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QskShortcutHandler::QskShortcutHandler()
|
||||
{
|
||||
// to process all sort of shortcut events at the same place
|
||||
installEventFilter( this );
|
||||
}
|
||||
|
||||
int QskShortcutHandler::add( QQuickItem* item, const QKeySequence& sequence,
|
||||
const QObject* receiver, const char* method )
|
||||
{
|
||||
int id = 0;
|
||||
|
||||
if ( receiver )
|
||||
{
|
||||
const QMetaObject* metaObject = receiver->metaObject();
|
||||
|
||||
const int methodIndex = metaObject->indexOfMethod(
|
||||
QMetaObject::normalizedSignature( method ).constData() + 1 );
|
||||
|
||||
if ( methodIndex >= 0 )
|
||||
{
|
||||
id = insert( item, sequence,
|
||||
receiver, metaObject->method( methodIndex ), nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int QskShortcutHandler::add( QQuickItem* item, const QKeySequence& sequence,
|
||||
const QObject* receiver, QtPrivate::QSlotObjectBase* slotObj )
|
||||
{
|
||||
return insert( item, sequence, receiver, QMetaMethod(), slotObj );
|
||||
}
|
||||
|
||||
int QskShortcutHandler::insert(
|
||||
QQuickItem* item, const QKeySequence& sequence,
|
||||
const QObject* receiver, const QMetaMethod& method,
|
||||
QtPrivate::QSlotObjectBase* slotObject )
|
||||
{
|
||||
if ( receiver )
|
||||
{
|
||||
receiver->disconnect( this );
|
||||
connect( receiver, &QObject::destroyed, this, &QskShortcutHandler::cleanUp );
|
||||
}
|
||||
|
||||
int id = 0;
|
||||
|
||||
auto& map = qskShortcutMap();
|
||||
|
||||
if ( item )
|
||||
{
|
||||
if ( item != receiver )
|
||||
{
|
||||
item->disconnect( this );
|
||||
connect( item, &QObject::destroyed, this, &QskShortcutHandler::cleanUp );
|
||||
}
|
||||
|
||||
id = map.addShortcut( item, sequence, Qt::WindowShortcut, qskContextMatcher );
|
||||
}
|
||||
else
|
||||
{
|
||||
id = map.addShortcut( this, sequence, Qt::ApplicationShortcut, qskContextMatcher );
|
||||
}
|
||||
|
||||
auto& data = m_invokeDataMap[ id ];
|
||||
|
||||
data.item = item;
|
||||
data.receiver = receiver;
|
||||
|
||||
if ( slotObject )
|
||||
data.slotObject = slotObject;
|
||||
else
|
||||
data.method = method;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void QskShortcutHandler::remove( int id )
|
||||
{
|
||||
auto it = m_invokeDataMap.find( id );
|
||||
if ( it == m_invokeDataMap.end() )
|
||||
return;
|
||||
|
||||
auto& map = qskShortcutMap();
|
||||
map.removeShortcut( id, nullptr );
|
||||
|
||||
const QQuickItem* item = it->second.item;
|
||||
const QObject* receiver = it->second.receiver;
|
||||
|
||||
m_invokeDataMap.erase( it );
|
||||
|
||||
/*
|
||||
Finally let's check if we can disconnect
|
||||
from the destroyed signals
|
||||
*/
|
||||
for ( const auto& entry : qskAsConst( m_invokeDataMap ) )
|
||||
{
|
||||
if ( item == nullptr && receiver == nullptr )
|
||||
break;
|
||||
|
||||
if ( entry.second.item == item )
|
||||
item = nullptr;
|
||||
|
||||
if ( entry.second.receiver == receiver )
|
||||
receiver = nullptr;
|
||||
}
|
||||
|
||||
if ( item )
|
||||
item->disconnect( this );
|
||||
|
||||
if ( receiver && receiver != item )
|
||||
receiver->disconnect( this );
|
||||
}
|
||||
|
||||
void QskShortcutHandler::cleanUp( QObject* object )
|
||||
{
|
||||
/*
|
||||
When item != receiver we might remain being connected
|
||||
to destroyed signals we are not interested in anymore. TODO ...
|
||||
*/
|
||||
auto& map = qskShortcutMap();
|
||||
|
||||
for ( auto it = m_invokeDataMap.begin(); it != m_invokeDataMap.end(); )
|
||||
{
|
||||
const auto& data = it->second;
|
||||
|
||||
if ( data.item == object || data.receiver == object )
|
||||
{
|
||||
map.removeShortcut( it->first, nullptr );
|
||||
it = m_invokeDataMap.erase( it );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void QskShortcutHandler::setEnabled( int id, bool enabled )
|
||||
{
|
||||
auto& map = qskShortcutMap();
|
||||
map.setShortcutEnabled( enabled, id, this );
|
||||
}
|
||||
|
||||
void QskShortcutHandler::setAutoRepeat( int id, bool repeat )
|
||||
{
|
||||
auto& map = qskShortcutMap();
|
||||
map.setShortcutAutoRepeat( repeat, id, this );
|
||||
}
|
||||
|
||||
bool QskShortcutHandler::eventFilter( QObject* object, QEvent* event )
|
||||
{
|
||||
if ( event->type() != QEvent::Shortcut )
|
||||
return false;
|
||||
|
||||
if ( object != this )
|
||||
object->removeEventFilter( this );
|
||||
|
||||
const QShortcutEvent* se = static_cast< const QShortcutEvent* >( event );
|
||||
|
||||
#if 0
|
||||
// do we want to handle this ???
|
||||
if ( se->isAmbiguous() )
|
||||
....
|
||||
#endif
|
||||
|
||||
const auto it = m_invokeDataMap.find( se->shortcutId() );
|
||||
if ( it != m_invokeDataMap.end() )
|
||||
{
|
||||
const auto& invokeData = it->second;
|
||||
|
||||
Q_ASSERT( invokeData.item == nullptr || invokeData.item == object );
|
||||
|
||||
auto receiver = const_cast< QObject* >( invokeData.receiver );
|
||||
|
||||
if ( invokeData.slotObject )
|
||||
{
|
||||
void* args[] = { 0 };
|
||||
|
||||
if ( receiver && receiver->thread() != thread() )
|
||||
{
|
||||
QCoreApplication::postEvent( receiver,
|
||||
new QMetaCallEvent( invokeData.slotObject, nullptr, 0, 0, nullptr, args ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
invokeData.slotObject->call( receiver, args );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
invokeData.method.invoke( receiver, Qt::AutoConnection );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// seems like someone else is also interested in shortcuts
|
||||
return false;
|
||||
}
|
||||
|
||||
int QskShortcutMap::addMethod( QQuickItem* item, const QKeySequence& sequence,
|
||||
bool autoRepeat, const QObject* receiver, const char* method )
|
||||
{
|
||||
if ( receiver == nullptr )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int id = qskShortcutHandler->add( item, sequence, receiver, method );
|
||||
if ( id && !autoRepeat )
|
||||
qskShortcutHandler->setAutoRepeat( id, false );
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int QskShortcutMap::addSlotObject( QQuickItem* item, const QKeySequence& sequence,
|
||||
bool autoRepeat, const QObject* receiver, QtPrivate::QSlotObjectBase* slotObject )
|
||||
{
|
||||
int id = qskShortcutHandler->add( item, sequence, receiver, slotObject );
|
||||
if ( id && !autoRepeat )
|
||||
qskShortcutHandler->setAutoRepeat( id, false );
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void QskShortcutMap::setAutoRepeat( int id, bool on )
|
||||
{
|
||||
qskShortcutHandler->setAutoRepeat( id, on );
|
||||
}
|
||||
|
||||
void QskShortcutMap::setEnabled( int id, bool on )
|
||||
{
|
||||
qskShortcutHandler->setEnabled( id, on );
|
||||
}
|
||||
|
||||
void QskShortcutMap::removeShortcut( int id )
|
||||
{
|
||||
qskShortcutHandler->remove( id );
|
||||
}
|
||||
|
||||
bool QskShortcutMap::contextMatcher(
|
||||
const QQuickItem* item, Qt::ShortcutContext context )
|
||||
{
|
||||
if ( context == Qt::ApplicationShortcut )
|
||||
return true;
|
||||
|
||||
if ( item && context == Qt::WindowShortcut )
|
||||
{
|
||||
const auto focusWindow = QGuiApplication::focusWindow();
|
||||
|
||||
const auto window = item->window();
|
||||
if ( window == nullptr || window != focusWindow )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while ( item )
|
||||
{
|
||||
/*
|
||||
We have to find out if the active focus is inside
|
||||
the surronding shortcut scope.
|
||||
*/
|
||||
if ( QskControl::isShortcutScope( item ) )
|
||||
{
|
||||
if ( !item->hasFocus() )
|
||||
return false;
|
||||
}
|
||||
|
||||
item = item->parentItem();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
228
src/controls/QskShortcutMap.h
Normal file
228
src/controls/QskShortcutMap.h
Normal file
@ -0,0 +1,228 @@
|
||||
/******************************************************************************
|
||||
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QSK_SHORTCUT_MAP_H
|
||||
#define QSK_SHORTCUT_MAP_H
|
||||
|
||||
#include "QskGlobal.h"
|
||||
#include <QQuickWindow>
|
||||
|
||||
class QQuickItem;
|
||||
class QKeySequence;
|
||||
|
||||
class QSK_EXPORT QskShortcutMap
|
||||
{
|
||||
public:
|
||||
static void setAutoRepeat( int, bool on );
|
||||
static void setEnabled( int, bool on );
|
||||
|
||||
static void removeShortcut( int );
|
||||
|
||||
// -- traditional slots
|
||||
static int addShortcut( const QKeySequence&, bool autoRepeat,
|
||||
const QObject* receiver, const char* method );
|
||||
|
||||
static int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat,
|
||||
const QObject* receiver, const char* method );
|
||||
|
||||
static int addShortcut( QQuickItem*, const QKeySequence&, bool autoRepeat,
|
||||
const QObject* receiver, const char* method );
|
||||
|
||||
// -- calling a QObject method
|
||||
template< typename Func1 >
|
||||
static int addShortcut( const QKeySequence&, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot );
|
||||
|
||||
template< typename Func1 >
|
||||
static int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot );
|
||||
|
||||
template< typename Func1 >
|
||||
static int addShortcut( QQuickItem*, const QKeySequence&, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot );
|
||||
|
||||
// -- calling a functor or function pointer inside a thread context
|
||||
template< typename Func1 >
|
||||
static int addShortcut( const QKeySequence&, bool autoRepeat,
|
||||
const QObject* context, Func1 slot );
|
||||
|
||||
template< typename Func1 >
|
||||
static int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat,
|
||||
const QObject* context, Func1 slot );
|
||||
|
||||
template< typename Func1 >
|
||||
static int addShortcut( QQuickItem*, const QKeySequence&, bool autoRepeat,
|
||||
const QObject* context, Func1 slot );
|
||||
|
||||
// -- calling a functor or function pointer
|
||||
template< typename Func1 >
|
||||
static int addShortcut( const QKeySequence&, bool autoRepeat, Func1 slot );
|
||||
|
||||
template< typename Func1 >
|
||||
static int addShortcut( QQuickWindow*, const QKeySequence&, bool autoRepeat, Func1 slot );
|
||||
|
||||
template< typename Func1 >
|
||||
static int addShortcut( QQuickItem*, const QKeySequence&, bool autoRepeat, Func1 slot );
|
||||
|
||||
static bool contextMatcher( const QQuickItem*, Qt::ShortcutContext );
|
||||
|
||||
private:
|
||||
QskShortcutMap() = delete;
|
||||
~QskShortcutMap() = delete;
|
||||
|
||||
static int addMethod( QQuickItem*, const QKeySequence&, bool autoRepeat,
|
||||
const QObject* receiver, const char* method );
|
||||
|
||||
template< typename Func1 >
|
||||
static int addMemberSlot( QQuickItem*, const QKeySequence&, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot );
|
||||
|
||||
template< typename Func1 >
|
||||
static int addFunctorSlot( QQuickItem*, const QKeySequence&,
|
||||
bool autoRepeat, const QObject* context, Func1 slot );
|
||||
|
||||
static int addSlotObject(
|
||||
QQuickItem* item, const QKeySequence&, bool autoRepeat,
|
||||
const QObject* receiver, QtPrivate::QSlotObjectBase* );
|
||||
};
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcutMap::addMemberSlot(
|
||||
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot )
|
||||
{
|
||||
using namespace QtPrivate;
|
||||
typedef FunctionPointer< Func1 > SlotType;
|
||||
|
||||
Q_STATIC_ASSERT_X( int( SlotType::ArgumentCount ) == 0,
|
||||
"The slot must not have any arguments.");
|
||||
|
||||
return addSlotObject( item, sequence, autoRepeat, receiver,
|
||||
new QSlotObject< Func1, typename SlotType::Arguments, void >( slot ) );
|
||||
}
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcutMap::addFunctorSlot(
|
||||
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat,
|
||||
const QObject* context, Func1 slot )
|
||||
{
|
||||
using namespace QtPrivate;
|
||||
typedef FunctionPointer< Func1 > SlotType;
|
||||
|
||||
Q_STATIC_ASSERT_X( int( SlotType::ArgumentCount ) <= 0,
|
||||
"The slot must not have any arguments.");
|
||||
|
||||
Q_STATIC_ASSERT_X( !SlotType::IsPointerToMemberFunction,
|
||||
"The slot must be no member function." );
|
||||
|
||||
using Args = List_Left< void, 0 >::Value;
|
||||
|
||||
return addSlotObject( item, sequence, autoRepeat, context,
|
||||
new QFunctorSlotObject< Func1, 0, Args, void >( slot ) );
|
||||
}
|
||||
|
||||
// -- traditional slots
|
||||
|
||||
inline int QskShortcutMap::addShortcut(
|
||||
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat,
|
||||
const QObject* receiver, const char* method )
|
||||
{
|
||||
return addMethod( item, sequence, autoRepeat, receiver, method );
|
||||
}
|
||||
|
||||
inline int QskShortcutMap::addShortcut(
|
||||
const QKeySequence& sequence, bool autoRepeat,
|
||||
const QObject* receiver, const char* method )
|
||||
{
|
||||
return addMethod( nullptr, sequence, autoRepeat, receiver, method );
|
||||
}
|
||||
|
||||
inline int QskShortcutMap::addShortcut(
|
||||
QQuickWindow* window, const QKeySequence& sequence, bool autoRepeat,
|
||||
const QObject* receiver, const char* method )
|
||||
{
|
||||
auto item = window ? window->contentItem() : nullptr;
|
||||
return addMethod( item, sequence, autoRepeat, receiver, method );
|
||||
}
|
||||
|
||||
// -- calling a QObject method
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcutMap::addShortcut(
|
||||
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot )
|
||||
{
|
||||
return addMemberSlot( item, sequence, autoRepeat, receiver, slot );
|
||||
}
|
||||
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcutMap::addShortcut(
|
||||
QQuickWindow* window, const QKeySequence& sequence, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot )
|
||||
{
|
||||
auto item = window ? window->contentItem() : nullptr;
|
||||
return addMemberSlot( item, sequence, autoRepeat, receiver, slot );
|
||||
}
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcutMap::addShortcut(
|
||||
const QKeySequence& sequence, bool autoRepeat,
|
||||
const typename QtPrivate::FunctionPointer< Func1 >::Object* receiver, Func1 slot )
|
||||
{
|
||||
return addMemberSlot( nullptr, sequence, autoRepeat, receiver, slot );
|
||||
}
|
||||
|
||||
// -- calling a functor or function pointer with context
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcutMap::addShortcut(
|
||||
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat,
|
||||
const QObject* context, Func1 slot )
|
||||
{
|
||||
return addFunctorSlot( item, sequence, autoRepeat, context, slot );
|
||||
}
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcutMap::addShortcut(
|
||||
QQuickWindow* window, const QKeySequence& sequence, bool autoRepeat,
|
||||
const QObject* context, Func1 slot )
|
||||
{
|
||||
auto item = window ? window->contentItem() : nullptr;
|
||||
return addFunctorSlot( item, sequence, autoRepeat, context, slot );
|
||||
}
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcutMap::addShortcut( const QKeySequence& sequence, bool autoRepeat,
|
||||
const QObject* context, Func1 slot )
|
||||
{
|
||||
return addFunctorSlot( nullptr, sequence, autoRepeat, context, slot );
|
||||
}
|
||||
|
||||
// -- calling a functor or function pointer
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcutMap::addShortcut(
|
||||
QQuickItem* item, const QKeySequence& sequence, bool autoRepeat, Func1 slot )
|
||||
{
|
||||
return addFunctorSlot( item, sequence, autoRepeat, nullptr, slot );
|
||||
}
|
||||
|
||||
template< typename Func1 >
|
||||
inline int QskShortcutMap::addShortcut(
|
||||
QQuickWindow* window, const QKeySequence& sequence, bool autoRepeat, Func1 slot )
|
||||
{
|
||||
auto item = window ? window->contentItem() : nullptr;
|
||||
return addFunctorSlot( item, sequence, autoRepeat, nullptr, autoRepeat, slot );
|
||||
}
|
||||
|
||||
template< typename Func1 >
|
||||
int QskShortcutMap::addShortcut(
|
||||
const QKeySequence& sequence, bool autoRepeat, Func1 slot )
|
||||
{
|
||||
return addFunctorSlot( nullptr, sequence, autoRepeat, nullptr, slot );
|
||||
}
|
||||
|
||||
#endif
|
@ -152,6 +152,7 @@ HEADERS += \
|
||||
controls/QskSeparatorSkinlet.h \
|
||||
controls/QskSetup.h \
|
||||
controls/QskShortcut.h \
|
||||
controls/QskShortcutMap.h \
|
||||
controls/QskSimpleListBox.h \
|
||||
controls/QskSkinFactory.h \
|
||||
controls/QskSkin.h \
|
||||
@ -215,6 +216,7 @@ SOURCES += \
|
||||
controls/QskSeparatorSkinlet.cpp \
|
||||
controls/QskSetup.cpp \
|
||||
controls/QskShortcut.cpp \
|
||||
controls/QskShortcutMap.cpp \
|
||||
controls/QskSimpleListBox.cpp \
|
||||
controls/QskSkin.cpp \
|
||||
controls/QskSkinHintTable.cpp \
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "SkinnyShortcut.h"
|
||||
|
||||
#include <QskSkinFactory.h>
|
||||
#include <QskShortcut.h>
|
||||
#include <QskShortcutMap.h>
|
||||
#include <QskSetup.h>
|
||||
#include <QskWindow.h>
|
||||
#include <QskAspect.h>
|
||||
@ -31,21 +31,21 @@ void SkinnyShortcut::enable( Types types )
|
||||
|
||||
if ( types & RotateSkin )
|
||||
{
|
||||
QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_S ),
|
||||
QskShortcutMap::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_S ),
|
||||
false, &s_shortcut, &SkinnyShortcut::rotateSkin );
|
||||
cout << "CTRL-S to change the skin." << endl;
|
||||
}
|
||||
|
||||
if ( types & DebugBackground )
|
||||
{
|
||||
QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_B ),
|
||||
QskShortcutMap::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_B ),
|
||||
false, &s_shortcut, &SkinnyShortcut::showBackground );
|
||||
cout << "CTRL-B to enable visual debugging modes." << endl;
|
||||
}
|
||||
|
||||
if ( types & DebugStatistics )
|
||||
{
|
||||
QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_K ),
|
||||
QskShortcutMap::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_K ),
|
||||
false, &s_shortcut, &SkinnyShortcut::debugStatistics );
|
||||
cout << "CTRL-K to dump statistics about the items/nodes being currently used." << endl;
|
||||
}
|
||||
@ -55,7 +55,7 @@ void SkinnyShortcut::enable( Types types )
|
||||
// QKeySequence::Quit crashes the application
|
||||
// when not being implemented by the platform !!
|
||||
|
||||
QskShortcut::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_Q ),
|
||||
QskShortcutMap::addShortcut( QKeySequence( Qt::CTRL + Qt::Key_Q ),
|
||||
false, QGuiApplication::instance(), &QGuiApplication::quit );
|
||||
cout << "CTRL-Q to terminate the application." << endl;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user