qskinny/src/controls/QskAbstractButton.cpp

388 lines
8.1 KiB
C++
Raw Normal View History

2017-07-21 18:21:34 +02:00
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskAbstractButton.h"
#include "QskAspect.h"
2018-05-09 08:20:32 +02:00
#include "QskEvent.h"
#include "QskQuick.h"
2017-07-21 18:21:34 +02:00
2018-07-19 14:10:48 +02:00
#include <qbasictimer.h>
2017-07-21 18:21:34 +02:00
QSK_STATE( QskAbstractButton, Flat, QskAspect::FirstSystemState << 1 )
QSK_STATE( QskAbstractButton, Checked, QskAspect::LastSystemState >> 4 )
QSK_STATE( QskAbstractButton, Pressed, QskAspect::LastSystemState >> 3 )
QSK_STATE( QskAbstractButton, Checkable, QskAspect::LastSystemState >> 2 )
static QskAbstractButton* qskCheckedSibling( const QskAbstractButton* button )
{
QQuickItem* parentItem = button->parentItem();
if ( parentItem == nullptr )
return nullptr;
const auto siblings = parentItem->childItems();
for ( QQuickItem* sibling : siblings )
{
if ( QskAbstractButton* btn = qobject_cast< QskAbstractButton* >( sibling ) )
{
if ( btn != button && btn->exclusive() && btn->isChecked() )
return btn;
}
}
return nullptr;
}
class QskAbstractButton::PrivateData
{
2018-08-03 08:15:28 +02:00
public:
PrivateData()
: autoRepeatDelay( 300 )
, autoRepeatInterval( 100 )
, exclusive( false )
, autoRepeat( false )
2017-07-21 18:21:34 +02:00
{
}
QBasicTimer repeatTimer;
2018-08-03 08:15:28 +02:00
int autoRepeatDelay; // milliseconds
2017-07-21 18:21:34 +02:00
int autoRepeatInterval; // milliseconds
bool exclusive : 1;
bool autoRepeat : 1;
};
2018-08-03 08:15:28 +02:00
QskAbstractButton::QskAbstractButton( QQuickItem* parent )
: Inherited( parent )
, m_data( new PrivateData() )
2017-07-21 18:21:34 +02:00
{
setFocusPolicy( Qt::StrongFocus );
2017-07-21 18:21:34 +02:00
setAcceptedMouseButtons( Qt::LeftButton );
setAcceptHoverEvents( true );
}
QskAbstractButton::~QskAbstractButton()
{
}
void QskAbstractButton::click()
{
setPressed( true );
releaseButton();
}
void QskAbstractButton::releaseButton()
{
if ( !isPressed() )
return;
if ( skinState() & Checkable )
{
// we will have toggled before released,
// maybe there is more work to have the signals coming
// in a logical order. TODO ...
2018-07-26 12:24:27 +02:00
setCheckedState( !( skinState() & Checked ) );
2017-07-21 18:21:34 +02:00
}
setPressed( false );
Q_EMIT clicked();
}
2018-07-26 12:24:27 +02:00
void QskAbstractButton::setCheckedState( bool on )
{
setChecked( on );
}
2017-07-21 18:21:34 +02:00
void QskAbstractButton::toggle()
{
setChecked( !( skinState() & Checked ) );
}
bool QskAbstractButton::isPressed() const
{
return skinState() & Pressed;
}
void QskAbstractButton::setPressed( bool on )
{
if ( on == isPressed() )
return;
setSkinStateFlag( Pressed, on );
2018-07-26 12:24:27 +02:00
Q_EMIT pressedChanged( on );
2017-07-21 18:21:34 +02:00
if ( on )
Q_EMIT pressed();
else
Q_EMIT released();
if ( m_data->autoRepeat )
{
if ( on )
{
m_data->repeatTimer.start( m_data->autoRepeatDelay, this );
}
else
{
m_data->repeatTimer.stop();
}
}
}
void QskAbstractButton::setCheckable( bool on )
{
if ( on == isCheckable() )
return;
setSkinStateFlag( Checkable, on );
2018-07-26 12:24:27 +02:00
Q_EMIT checkableChanged( on );
2017-07-21 18:21:34 +02:00
}
bool QskAbstractButton::isCheckable() const
{
return skinState() & Checkable;
}
void QskAbstractButton::setChecked( bool on )
{
if ( on == isChecked() )
return;
if ( m_data->exclusive && !on )
{
// an exclusive button can't be unchecked
return;
}
auto checkedButton = qskCheckedSibling( this );
if ( checkedButton )
{
// we enter temporary state, where no buttons are selected,
// better delay the notifications
checkedButton->setSkinStateFlag( Checked, false );
}
setSkinStateFlag( Checked, on );
2018-07-26 12:24:27 +02:00
Q_EMIT checkedChanged( on );
2017-07-21 18:21:34 +02:00
Q_EMIT toggled( on );
if ( checkedButton )
{
2018-07-26 12:24:27 +02:00
Q_EMIT checkedButton->checkedChanged( false );
2017-07-21 18:21:34 +02:00
Q_EMIT checkedButton->toggled( false );
}
}
bool QskAbstractButton::isChecked() const
{
return skinState() & Checked;
}
void QskAbstractButton::setAutoRepeat( bool on )
{
if ( on != m_data->autoRepeat )
{
m_data->autoRepeat = on;
if ( m_data->autoRepeat && isPressed() )
m_data->repeatTimer.start( m_data->autoRepeatDelay, this );
else
m_data->repeatTimer.stop();
2018-07-26 12:24:27 +02:00
Q_EMIT autoRepeatChanged( on );
2017-07-21 18:21:34 +02:00
}
}
bool QskAbstractButton::autoRepeat() const
{
return m_data->autoRepeat;
}
void QskAbstractButton::setAutoRepeatDelay( int ms )
{
if ( ms != m_data->autoRepeatDelay )
{
m_data->autoRepeatDelay = ms;
Q_EMIT autoRepeatDelayChanged();
}
}
int QskAbstractButton::autoRepeatDelay() const
{
return m_data->autoRepeatDelay;
}
void QskAbstractButton::setAutoRepeatInterval( int ms )
{
if ( ms != m_data->autoRepeatInterval )
{
m_data->autoRepeatInterval = ms;
Q_EMIT autoRepeatIntervalChanged();
}
}
int QskAbstractButton::autoRepeatInterval() const
{
return m_data->autoRepeatInterval;
}
void QskAbstractButton::setExclusive( bool on )
{
if ( on != m_data->exclusive )
{
m_data->exclusive = on;
2018-07-26 12:24:27 +02:00
Q_EMIT exclusiveChanged( on );
2017-07-21 18:21:34 +02:00
}
}
bool QskAbstractButton::exclusive() const
{
return m_data->exclusive;
}
bool QskAbstractButton::event( QEvent* event )
{
2018-05-09 08:20:32 +02:00
const auto eventType = static_cast< int >( event->type() );
2018-08-03 08:15:28 +02:00
switch ( eventType )
2017-07-21 18:21:34 +02:00
{
2018-05-09 08:20:32 +02:00
case QEvent::Shortcut:
{
// TODO
// setFocus( true, Qt::ShortcutFocusReason );
break;
}
case QskEvent::WindowChange:
{
if ( qskIsItemComplete( this ) && isPressed() )
{
/*
When the window change happens on pressed() we won't get
the corrsponding release.
*/
setPressed( false );
}
break;
}
2017-07-21 18:21:34 +02:00
}
return Inherited::event( event );
}
void QskAbstractButton::keyPressEvent( QKeyEvent* event )
{
switch ( event->key() )
2017-07-21 18:21:34 +02:00
{
case Qt::Key_Select:
case Qt::Key_Space:
2017-07-21 18:21:34 +02:00
{
if ( !event->isAutoRepeat() )
2017-07-21 18:21:34 +02:00
setPressed( true );
// always accepting
return;
2017-07-21 18:21:34 +02:00
}
}
Inherited::keyPressEvent( event );
}
void QskAbstractButton::keyReleaseEvent( QKeyEvent* event )
{
if ( !event->isAutoRepeat() )
{
switch ( event->key() )
{
case Qt::Key_Select:
case Qt::Key_Space:
{
releaseButton();
return;
}
default:
break;
}
}
Inherited::keyReleaseEvent( event );
}
void QskAbstractButton::mouseMoveEvent( QMouseEvent* event )
{
if ( isPressed() )
{
if ( !contains( event->pos() ) )
{
setPressed( false );
Q_EMIT canceled();
}
}
event->accept();
}
void QskAbstractButton::mousePressEvent( QMouseEvent* )
2017-07-21 18:21:34 +02:00
{
// QGuiApplication::styleHints()->mousePressAndHoldInterval() ???
2017-07-21 18:21:34 +02:00
setPressed( true );
}
void QskAbstractButton::mouseReleaseEvent( QMouseEvent* )
2017-07-21 18:21:34 +02:00
{
releaseButton();
}
void QskAbstractButton::mouseUngrabEvent()
{
if ( isPressed() )
{
setPressed( false );
Q_EMIT canceled();
}
}
void QskAbstractButton::focusInEvent( QFocusEvent* event )
{
Inherited::focusInEvent( event );
}
void QskAbstractButton::focusOutEvent( QFocusEvent* event )
{
if ( isPressed() )
{
setPressed( false );
Q_EMIT canceled();
}
Inherited::focusOutEvent( event );
}
void QskAbstractButton::timerEvent( QTimerEvent* event )
{
if ( event->timerId() == m_data->repeatTimer.timerId() )
{
if ( isPressed() )
{
Q_EMIT released();
Q_EMIT clicked();
Q_EMIT pressed();
m_data->repeatTimer.start( m_data->autoRepeatInterval, this );
}
else
{
m_data->repeatTimer.stop();
}
return;
}
Inherited::timerEvent( event );
}
#include "moc_QskAbstractButton.cpp"