qskinny/src/inputpanel/QskInputPredictionBar.cpp

185 lines
4.9 KiB
C++
Raw Normal View History

2018-04-06 15:30:24 +00:00
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskInputPredictionBar.h"
2018-04-06 15:30:24 +00:00
#include "QskPushButton.h"
#include "QskLinearBox.h"
#include "QskTextOptions.h"
#include <QFontMetricsF>
#include <QStringList>
2018-04-06 15:30:24 +00:00
QSK_SUBCONTROL( QskInputPredictionBar, Panel )
QSK_SUBCONTROL( QskInputPredictionBar, ButtonPanel )
QSK_SUBCONTROL( QskInputPredictionBar, ButtonText )
2018-04-06 15:30:24 +00:00
namespace
{
class Button final : public QskPushButton
{
public:
Button( QQuickItem* parent ):
QskPushButton( parent )
{
QskTextOptions options;
options.setElideMode( Qt::ElideRight );
setTextOptions( options );
}
virtual QSizeF contentsSizeHint() const override
{
auto size = QFontMetricsF( font() ).size( Qt::TextSingleLine, text() );
const QSizeF minSize( metric( Panel | QskAspect::MinimumWidth ),
metric( Panel | QskAspect::MinimumHeight ) );
size = size.expandedTo( minSize );
size = outerBoxSize( Panel, size );
return size;
}
2018-04-06 15:30:24 +00:00
virtual QskAspect::Subcontrol effectiveSubcontrol(
QskAspect::Subcontrol subControl ) const override final
{
if( subControl == QskPushButton::Panel )
return QskInputPredictionBar::ButtonPanel;
2018-04-06 15:30:24 +00:00
if( subControl == QskPushButton::Text )
return QskInputPredictionBar::ButtonText;
2018-04-06 15:30:24 +00:00
return subControl;
}
};
}
class QskInputPredictionBar::PrivateData
2018-04-06 15:30:24 +00:00
{
public:
QskLinearBox* layoutBox;
QStringList candidates;
2018-04-06 15:30:24 +00:00
int scrollOffset = 0;
2018-04-06 15:30:24 +00:00
const int buttonCount = 12;
};
QskInputPredictionBar::QskInputPredictionBar( QQuickItem* parent ):
2018-04-06 15:30:24 +00:00
Inherited( parent ),
m_data( new PrivateData )
{
setAutoLayoutChildren( true );
initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Fixed );
2018-04-06 15:30:24 +00:00
m_data->layoutBox = new QskLinearBox( Qt::Horizontal, this );
for( int i = 0; i < m_data->buttonCount; i++ )
{
auto button = new Button( m_data->layoutBox );
button->setVisible( false );
button->setSizePolicy( Qt::Horizontal, QskSizePolicy::Maximum );
2018-04-06 15:30:24 +00:00
connect( button, &QskPushButton::clicked,
this, &QskInputPredictionBar::buttonClicked );
if ( i == 0 )
{
// to keep the height
m_data->layoutBox->setRetainSizeWhenHidden( button, true );
}
2018-04-06 15:30:24 +00:00
}
}
QskInputPredictionBar::~QskInputPredictionBar()
2018-04-06 15:30:24 +00:00
{
}
QskAspect::Subcontrol QskInputPredictionBar::effectiveSubcontrol(
2018-04-06 15:30:24 +00:00
QskAspect::Subcontrol subControl ) const
{
if( subControl == QskBox::Panel )
return QskInputPredictionBar::Panel;
2018-04-06 15:30:24 +00:00
return subControl;
}
void QskInputPredictionBar::setPrediction( const QStringList& candidates )
2018-04-06 15:30:24 +00:00
{
if( m_data->candidates != candidates )
{
m_data->candidates = candidates;
setScrollOffset( 0 );
2018-04-06 15:30:24 +00:00
}
}
QStringList QskInputPredictionBar::candidates() const
{
return m_data->candidates;
}
void QskInputPredictionBar::setScrollOffset( int offset )
2018-04-06 15:30:24 +00:00
{
m_data->scrollOffset = offset;
2018-04-06 15:30:24 +00:00
const auto candidateCount = m_data->candidates.length();
const auto count = std::min( candidateCount, m_data->buttonCount );
const bool continueLeft = m_data->scrollOffset > 0;
const bool continueRight = ( candidateCount - m_data->scrollOffset ) > count;
2018-04-06 15:30:24 +00:00
for( int i = 0; i < count; i++ )
{
auto button = qobject_cast< QskPushButton* >(
m_data->layoutBox->itemAtIndex( i ) );
if( continueLeft && i == 0 )
{
button->setText( QChar( 0x2B05 ) );
}
else if( continueRight && ( i == m_data->buttonCount - 1 ) )
{
button->setText( QChar( 0x27A1 ) );
}
else
{
const int index = i + m_data->scrollOffset;
2018-04-06 15:30:24 +00:00
button->setText( m_data->candidates[index] );
}
button->setVisible( true );
}
for( int i = count; i < m_data->buttonCount; ++i )
m_data->layoutBox->itemAtIndex( i )->setVisible( false );
}
void QskInputPredictionBar::buttonClicked()
2018-04-06 15:30:24 +00:00
{
const int index = m_data->layoutBox->indexOf(
qobject_cast< QQuickItem* > ( sender() ) );
2018-04-06 15:30:24 +00:00
const int offset = m_data->scrollOffset;
2018-04-06 15:30:24 +00:00
if ( index == 0 )
{
if ( offset > 0 )
{
setScrollOffset( offset - 1 );
2018-04-06 15:30:24 +00:00
return;
}
}
else if ( index == m_data->buttonCount - 1 )
{
if ( m_data->candidates.count() - offset > m_data->buttonCount )
2018-04-06 15:30:24 +00:00
{
setScrollOffset( offset + 1 );
2018-04-06 15:30:24 +00:00
return;
}
}
Q_EMIT predictiveTextSelected( offset + index );
2018-04-06 15:30:24 +00:00
}
#include "moc_QskInputPredictionBar.cpp"