QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskInputPredictionBar.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskInputPredictionBar.h"
7#include "QskLinearBox.h"
8#include "QskPushButton.h"
9#include "QskTextOptions.h"
10
11#include <qfontmetrics.h>
12#include <qstringlist.h>
13
14QSK_SUBCONTROL( QskInputPredictionBar, Panel )
15QSK_SUBCONTROL( QskInputPredictionBar, ButtonPanel )
16QSK_SUBCONTROL( QskInputPredictionBar, ButtonText )
17
18namespace
19{
20 class Button final : public QskPushButton
21 {
22 public:
23 Button( QQuickItem* parent )
24 : QskPushButton( parent )
25 {
26 QskTextOptions options;
27 options.setElideMode( Qt::ElideRight );
28
29 setTextOptions( options );
30 }
31
32 QSizeF contentsSizeHint(
33 Qt::SizeHint which, const QSizeF& ) const override
34 {
35 if ( which != Qt::PreferredSize )
36 return QSizeF();
37
38 auto size = QFontMetricsF( font() ).size( Qt::TextSingleLine, text() );
39
40 size = size.expandedTo( strutSizeHint( Panel ) );
41 size = outerBoxSize( Panel, size );
42
43 return size;
44 }
45
46 QskAspect::Subcontrol substitutedSubcontrol(
47 QskAspect::Subcontrol subControl ) const override
48 {
49 if ( subControl == QskPushButton::Panel )
50 return QskInputPredictionBar::ButtonPanel;
51
52 if ( subControl == QskPushButton::Text )
53 return QskInputPredictionBar::ButtonText;
54
55 return subControl;
56 }
57 };
58}
59
60class QskInputPredictionBar::PrivateData
61{
62 public:
63 QskLinearBox* layoutBox;
64 QStringList candidates;
65
66 int scrollOffset = 0;
67 const int buttonCount = 12;
68};
69
70QskInputPredictionBar::QskInputPredictionBar( QQuickItem* parent )
71 : Inherited( parent )
72 , m_data( new PrivateData )
73{
74 setAutoLayoutChildren( true );
75 initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Fixed );
76
77 m_data->layoutBox = new QskLinearBox( Qt::Horizontal, this );
78
79 for ( int i = 0; i < m_data->buttonCount; i++ )
80 {
81 auto button = new Button( m_data->layoutBox );
82 button->setVisible( false );
83 button->setSizePolicy( Qt::Horizontal, QskSizePolicy::Maximum );
84
85 connect( button, &QskPushButton::clicked,
86 this, &QskInputPredictionBar::buttonClicked );
87
88 if ( i == 0 )
89 {
90 // to keep the height
91 button->setPlacementPolicy( Qsk::Hidden, QskPlacementPolicy::Reserve );
92 }
93 }
94}
95
96QskInputPredictionBar::~QskInputPredictionBar()
97{
98}
99
100QskAspect::Subcontrol QskInputPredictionBar::substitutedSubcontrol(
101 QskAspect::Subcontrol subControl ) const
102{
103 if ( subControl == QskBox::Panel )
104 return QskInputPredictionBar::Panel;
105
106 return Inherited::substitutedSubcontrol( subControl );
107}
108
109void QskInputPredictionBar::setPrediction( const QStringList& candidates )
110{
111 if ( m_data->candidates != candidates )
112 {
113 m_data->candidates = candidates;
114 setScrollOffset( 0 );
115 }
116}
117
118QStringList QskInputPredictionBar::candidates() const
119{
120 return m_data->candidates;
121}
122
123void QskInputPredictionBar::setScrollOffset( int offset )
124{
125 m_data->scrollOffset = offset;
126
127 const int candidateCount = m_data->candidates.length();
128 const int count = std::min( candidateCount, m_data->buttonCount );
129 const bool continueLeft = m_data->scrollOffset > 0;
130 const bool continueRight = ( candidateCount - m_data->scrollOffset ) > count;
131
132 for ( int i = 0; i < count; i++ )
133 {
134 auto button = qobject_cast< QskPushButton* >(
135 m_data->layoutBox->itemAtIndex( i ) );
136
137 if ( continueLeft && i == 0 )
138 {
139 button->setText( QChar( 0x2B05 ) );
140 }
141 else if ( continueRight && ( i == m_data->buttonCount - 1 ) )
142 {
143 button->setText( QChar( 0x27A1 ) );
144 }
145 else
146 {
147 const int index = i + m_data->scrollOffset;
148 button->setText( m_data->candidates[ index ] );
149 }
150
151 button->setVisible( true );
152 }
153
154 for ( int i = count; i < m_data->buttonCount; ++i )
155 m_data->layoutBox->itemAtIndex( i )->setVisible( false );
156}
157
158void QskInputPredictionBar::buttonClicked()
159{
160 const int index = m_data->layoutBox->indexOf(
161 qobject_cast< QQuickItem* > ( sender() ) );
162
163 const int offset = m_data->scrollOffset;
164
165 if ( index == 0 )
166 {
167 if ( offset > 0 )
168 {
169 setScrollOffset( offset - 1 );
170 return;
171 }
172 }
173 else if ( index == m_data->buttonCount - 1 )
174 {
175 if ( m_data->candidates.count() - offset > m_data->buttonCount )
176 {
177 setScrollOffset( offset + 1 );
178 return;
179 }
180 }
181
182 Q_EMIT predictiveTextSelected( offset + index );
183}
184
185#include "moc_QskInputPredictionBar.cpp"
Subcontrol
For use within the rendering or lay-outing of a specific QskSkinnable.
Definition QskAspect.h:104
Layout stringing items in rows and columns.
QSizeF strutSizeHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a strut size hint.
QSizeF outerBoxSize(QskAspect, const QSizeF &innerBoxSize) const
Calculate the size, when being expanded by paddings, indentations.
@ Hidden