UI tweaks for the launcher
This commit is contained in:
parent
8eb4d76411
commit
71a1348037
16 changed files with 749 additions and 23 deletions
|
@ -59,7 +59,7 @@ bool PopupWindowTracker::eventFilter(QObject *watched, QEvent *event)
|
|||
} else {
|
||||
m_window->close();
|
||||
setWindow(nullptr);
|
||||
return true;
|
||||
// still fall through
|
||||
}
|
||||
}
|
||||
|
||||
|
|
93
src/GUI/QmlRadioButtonHelper.cxx
Normal file
93
src/GUI/QmlRadioButtonHelper.cxx
Normal file
|
@ -0,0 +1,93 @@
|
|||
// QmlRadioButtonHelper.hxx - helper for QtQuick radio button impl
|
||||
//
|
||||
// Written by James Turner, started April 2018.
|
||||
//
|
||||
// Copyright (C) 2015 James Turner <james@flightgear.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#include "QmlRadioButtonHelper.hxx"
|
||||
|
||||
#include <QMetaObject>
|
||||
#include <QDebug>
|
||||
|
||||
QmlRadioButtonGroup::QmlRadioButtonGroup(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
QmlRadioButtonGroupAttached* QmlRadioButtonGroup::qmlAttachedProperties(QObject *object)
|
||||
{
|
||||
return new QmlRadioButtonGroupAttached(object);
|
||||
}
|
||||
|
||||
QObject *QmlRadioButtonGroup::selected() const
|
||||
{
|
||||
return m_selected;
|
||||
}
|
||||
|
||||
void QmlRadioButtonGroup::setSelected(QObject *selected)
|
||||
{
|
||||
if (m_selected == selected)
|
||||
return;
|
||||
|
||||
m_selected = selected;
|
||||
emit selectedChanged(m_selected);
|
||||
}
|
||||
|
||||
QmlRadioButtonGroupAttached::QmlRadioButtonGroupAttached(QObject *pr) :
|
||||
QObject(pr)
|
||||
{
|
||||
}
|
||||
|
||||
QmlRadioButtonGroup *QmlRadioButtonGroupAttached::group() const
|
||||
{
|
||||
return m_group;
|
||||
}
|
||||
|
||||
bool QmlRadioButtonGroupAttached::isSelected() const
|
||||
{
|
||||
if (!m_group)
|
||||
return false;
|
||||
|
||||
return (m_group->selected() == this);
|
||||
}
|
||||
|
||||
void QmlRadioButtonGroupAttached::setGroup(QmlRadioButtonGroup *group)
|
||||
{
|
||||
if (m_group == group)
|
||||
return;
|
||||
|
||||
if (m_group) {
|
||||
disconnect(m_group, &QmlRadioButtonGroup::selectedChanged,
|
||||
this, &QmlRadioButtonGroupAttached::onGroupSelectionChanged);
|
||||
}
|
||||
|
||||
m_group = group;
|
||||
|
||||
if (m_group) {
|
||||
connect(m_group, &QmlRadioButtonGroup::selectedChanged,
|
||||
this, &QmlRadioButtonGroupAttached::onGroupSelectionChanged);
|
||||
}
|
||||
|
||||
emit groupChanged(m_group);
|
||||
emit isSelectedChanged(isSelected());
|
||||
}
|
||||
|
||||
void QmlRadioButtonGroupAttached::onGroupSelectionChanged()
|
||||
{
|
||||
emit isSelectedChanged(isSelected());
|
||||
}
|
78
src/GUI/QmlRadioButtonHelper.hxx
Normal file
78
src/GUI/QmlRadioButtonHelper.hxx
Normal file
|
@ -0,0 +1,78 @@
|
|||
// QmlRadioButtonHelper.hxx - helper for QtQuick radio button impl
|
||||
//
|
||||
// Written by James Turner, started April 2018.
|
||||
//
|
||||
// Copyright (C) 2015 James Turner <james@flightgear.org>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifndef QMLRADIOBUTTONHELPER_HXX
|
||||
#define QMLRADIOBUTTONHELPER_HXX
|
||||
|
||||
#include <QObject>
|
||||
#include <QQmlEngine> // for QML_DECLARE_TYPEINFO
|
||||
|
||||
class QmlRadioButtonGroup;
|
||||
|
||||
class QmlRadioButtonGroupAttached : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QmlRadioButtonGroup* group READ group WRITE setGroup NOTIFY groupChanged)
|
||||
Q_PROPERTY(bool isSelected READ isSelected NOTIFY isSelectedChanged)
|
||||
public:
|
||||
QmlRadioButtonGroupAttached(QObject* pr = nullptr);
|
||||
|
||||
QmlRadioButtonGroup* group() const;
|
||||
bool isSelected() const;
|
||||
|
||||
public slots:
|
||||
void setGroup(QmlRadioButtonGroup* group);
|
||||
|
||||
signals:
|
||||
void groupChanged(QmlRadioButtonGroup* group);
|
||||
void isSelectedChanged(bool isSelected);
|
||||
|
||||
private:
|
||||
void onGroupSelectionChanged();
|
||||
|
||||
QmlRadioButtonGroup* m_group = nullptr;
|
||||
};
|
||||
|
||||
class QmlRadioButtonGroup : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QObject* selected READ selected WRITE setSelected NOTIFY selectedChanged)
|
||||
public:
|
||||
explicit QmlRadioButtonGroup(QObject *parent = nullptr);
|
||||
|
||||
static QmlRadioButtonGroupAttached *qmlAttachedProperties(QObject *);
|
||||
|
||||
QObject* selected() const;
|
||||
|
||||
signals:
|
||||
void selectedChanged(QObject* selected);
|
||||
|
||||
public slots:
|
||||
void setSelected(QObject* selected);
|
||||
|
||||
private:
|
||||
QObject* m_selected = nullptr;
|
||||
};
|
||||
|
||||
QML_DECLARE_TYPEINFO(QmlRadioButtonGroup, QML_HAS_ATTACHED_PROPERTIES)
|
||||
|
||||
#endif // QMLRADIOBUTTONHELPER_HXX
|
|
@ -12,7 +12,7 @@ Item {
|
|||
footer.height
|
||||
implicitWidth: ListView.view.width
|
||||
|
||||
readonly property bool __isSelected: (_launcher.selectedAircraft == model.uri)
|
||||
readonly property bool __isSelected: (_launcher.selectedAircraft === model.uri)
|
||||
|
||||
property bool __showAlternateText: false
|
||||
|
||||
|
@ -100,13 +100,13 @@ Item {
|
|||
wrapMode: Text.WordWrap
|
||||
elide: Text.ElideRight
|
||||
height: implicitHeight
|
||||
visible: (model.description != "") || root.__showAlternateText
|
||||
visible: (model.description !== "") || root.__showAlternateText
|
||||
}
|
||||
|
||||
AircraftDownloadPanel
|
||||
{
|
||||
id: downloadPanel
|
||||
visible: (model.package != undefined)
|
||||
visible: (model.package !== undefined)
|
||||
packageSize: model.packageSizeBytes
|
||||
installStatus: model.packageStatus
|
||||
downloadedBytes: model.downloadedBytes
|
||||
|
|
|
@ -93,7 +93,7 @@ FocusScope {
|
|||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if ((event.key == Qt.Key_Colon) || (event.key == Qt.Key_Slash)) {
|
||||
if ((event.key === Qt.Key_Colon) || (event.key === Qt.Key_Slash)) {
|
||||
nextToFocus.focus = true;
|
||||
event.accepted = true;
|
||||
}
|
||||
|
@ -136,9 +136,10 @@ FocusScope {
|
|||
}
|
||||
|
||||
onWheel: {
|
||||
if (wheel.angleDelta > 0) {
|
||||
var delta = wheel.angleDelta.y
|
||||
if (delta > 0) {
|
||||
root.incrementValue()
|
||||
} else if (wheel.angleDelta < 0) {
|
||||
} else if (delta < 0) {
|
||||
root.decrementValue()
|
||||
}
|
||||
}
|
||||
|
|
214
src/GUI/qml/DoubleSpinbox.qml
Normal file
214
src/GUI/qml/DoubleSpinbox.qml
Normal file
|
@ -0,0 +1,214 @@
|
|||
import QtQuick 2.4
|
||||
import "."
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
property string label
|
||||
property bool enabled: true
|
||||
property int value: 0
|
||||
property alias min: validator.bottom
|
||||
property int max: validator.top
|
||||
property alias decimals: validator.decimals
|
||||
|
||||
property bool wrap: false
|
||||
property alias suffix: suffix.text
|
||||
property alias prefix: prefix.text
|
||||
property alias maxDigits: edit.maximumLength
|
||||
property int step: 1
|
||||
|
||||
implicitHeight: editFrame.height
|
||||
// we have a margin between the frame and the label, and on each
|
||||
implicitWidth: label.width + editFrame.width + Style.margin
|
||||
|
||||
signal commit(var newValue);
|
||||
|
||||
function incrementValue()
|
||||
{
|
||||
if (edit.activeFocus) {
|
||||
value = Math.min(parseFloat(edit.text) + root.step, root.max)
|
||||
edit.text = value
|
||||
} else {
|
||||
commit(Math.min(value + root.step, root.max))
|
||||
}
|
||||
}
|
||||
|
||||
function decrementValue()
|
||||
{
|
||||
if (edit.activeFocus) {
|
||||
value = Math.max(parseFloat(edit.text) - root.step, root.min)
|
||||
edit.text = value
|
||||
} else {
|
||||
commit(Math.max(value - root.step, root.min))
|
||||
}
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: metrics
|
||||
text: root.max // use maximum value
|
||||
}
|
||||
|
||||
Text {
|
||||
id: label
|
||||
text: root.label
|
||||
anchors.verticalCenter: editFrame.verticalCenter
|
||||
color: editFrame.activeFocus ? Style.themeColor :
|
||||
(root.enabled ? "black" : Style.inactiveThemeColor)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
height: root.height
|
||||
width: root.width
|
||||
enabled: root.enabled
|
||||
|
||||
// use wheel events to adjust up/dowm
|
||||
onClicked: {
|
||||
edit.forceActiveFocus();
|
||||
}
|
||||
|
||||
onWheel: {
|
||||
var delta = wheel.angleDelta.y
|
||||
if (delta > 0) {
|
||||
root.incrementValue()
|
||||
} else if (delta < 0) {
|
||||
root.decrementValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binding {
|
||||
when: !edit.activeFocus
|
||||
target: edit
|
||||
property: "text"
|
||||
value: root.value
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: editFrame
|
||||
clip: true
|
||||
anchors.left: label.right
|
||||
anchors.margins: Style.margin
|
||||
|
||||
height: edit.implicitHeight + Style.margin
|
||||
width: edit.width + prefix.width + suffix.width + upDownArea.width + Style.margin * 2
|
||||
radius: Style.roundRadius
|
||||
border.color: edit.activeFocus ? Style.frameColor : Style.minorFrameColor
|
||||
border.width: 1
|
||||
|
||||
|
||||
Text {
|
||||
id: prefix
|
||||
visible: root.prefix !== ""
|
||||
color: Style.baseTextColor
|
||||
anchors.baseline: edit.baseline
|
||||
anchors.left: parent.left
|
||||
anchors.margins: Style.margin
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: edit
|
||||
enabled: root.enabled
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: prefix.right
|
||||
selectByMouse: true
|
||||
width: metrics.width
|
||||
horizontalAlignment: Text.AlignRight
|
||||
|
||||
focus: true
|
||||
color: enabled && activeFocus ? Style.themeColor : Style.baseTextColor
|
||||
|
||||
validator: DoubleValidator {
|
||||
id: validator
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
root.incrementValue();
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
root.decrementValue();
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
selectAll();
|
||||
} else {
|
||||
commit(parseFloat(text))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: suffix
|
||||
visible: root.suffix !== ""
|
||||
color: Style.baseTextColor
|
||||
anchors.baseline: edit.baseline
|
||||
anchors.right: upDownArea.left
|
||||
}
|
||||
|
||||
Item {
|
||||
id: upDownArea
|
||||
// color: "white"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Style.margin
|
||||
anchors.verticalCenter: editFrame.verticalCenter
|
||||
height: upDownIcon.implicitHeight
|
||||
visible: edit.activeFocus
|
||||
width: upDownIcon.implicitWidth
|
||||
|
||||
Image {
|
||||
id: upDownIcon
|
||||
// show up/down arrows
|
||||
source: "qrc:///up-down-arrow"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
width: parent.width
|
||||
height: parent.height / 2
|
||||
onPressed: {
|
||||
root.incrementValue();
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
opacity: 0.5
|
||||
color: Style.themeColor
|
||||
visible: parent.pressed
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: upRepeat
|
||||
interval: 250
|
||||
running: parent.pressed
|
||||
repeat: true
|
||||
onTriggered: root.incrementValue()
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
width: parent.width
|
||||
height: parent.height / 2
|
||||
anchors.bottom: parent.bottom
|
||||
onPressed: {
|
||||
root.decrementValue();
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
opacity: 0.5
|
||||
color: Style.themeColor
|
||||
visible: parent.pressed
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: downRepeat
|
||||
interval: 250
|
||||
running: parent.pressed
|
||||
repeat: true
|
||||
onTriggered: root.decrementValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
} // of frame rectangle
|
||||
|
||||
|
||||
}
|
212
src/GUI/qml/IntegerSpinbox.qml
Normal file
212
src/GUI/qml/IntegerSpinbox.qml
Normal file
|
@ -0,0 +1,212 @@
|
|||
import QtQuick 2.4
|
||||
import "."
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
property string label
|
||||
property bool enabled: true
|
||||
property int value: 0
|
||||
property alias min: validator.bottom
|
||||
property int max: validator.top
|
||||
property bool wrap: false
|
||||
property alias suffix: suffix.text
|
||||
property alias prefix: prefix.text
|
||||
property alias maxDigits: edit.maximumLength
|
||||
property int step: 1
|
||||
|
||||
implicitHeight: editFrame.height
|
||||
// we have a margin between the frame and the label, and on each
|
||||
implicitWidth: label.width + editFrame.width + Style.margin
|
||||
|
||||
signal commit(var newValue);
|
||||
|
||||
function incrementValue()
|
||||
{
|
||||
if (edit.activeFocus) {
|
||||
value = Math.min(parseInt(edit.text) + root.step, root.max)
|
||||
edit.text = value
|
||||
} else {
|
||||
commit(Math.min(value + root.step, root.max))
|
||||
}
|
||||
}
|
||||
|
||||
function decrementValue()
|
||||
{
|
||||
if (edit.activeFocus) {
|
||||
value = Math.max(parseInt(edit.text) - root.step, root.min)
|
||||
edit.text = value
|
||||
} else {
|
||||
commit(Math.max(value - root.step, root.min))
|
||||
}
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: metrics
|
||||
text: root.max // use maximum value
|
||||
}
|
||||
|
||||
Text {
|
||||
id: label
|
||||
text: root.label
|
||||
anchors.verticalCenter: editFrame.verticalCenter
|
||||
color: editFrame.activeFocus ? Style.themeColor :
|
||||
(root.enabled ? "black" : Style.inactiveThemeColor)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
height: root.height
|
||||
width: root.width
|
||||
enabled: root.enabled
|
||||
|
||||
// use wheel events to adjust up/dowm
|
||||
onClicked: {
|
||||
edit.forceActiveFocus();
|
||||
}
|
||||
|
||||
onWheel: {
|
||||
var delta = wheel.angleDelta.y
|
||||
if (delta > 0) {
|
||||
root.incrementValue()
|
||||
} else if (delta < 0) {
|
||||
root.decrementValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binding {
|
||||
when: !edit.activeFocus
|
||||
target: edit
|
||||
property: "text"
|
||||
value: root.value
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: editFrame
|
||||
clip: true
|
||||
anchors.left: label.right
|
||||
anchors.margins: Style.margin
|
||||
|
||||
height: edit.implicitHeight + Style.margin
|
||||
width: edit.width + prefix.width + suffix.width + upDownArea.width + Style.margin * 2
|
||||
radius: Style.roundRadius
|
||||
border.color: edit.activeFocus ? Style.frameColor : Style.minorFrameColor
|
||||
border.width: 1
|
||||
|
||||
|
||||
Text {
|
||||
id: prefix
|
||||
visible: root.prefix !== ""
|
||||
color: Style.baseTextColor
|
||||
anchors.baseline: edit.baseline
|
||||
anchors.left: parent.left
|
||||
anchors.margins: Style.margin
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: edit
|
||||
enabled: root.enabled
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: prefix.right
|
||||
selectByMouse: true
|
||||
width: metrics.width
|
||||
horizontalAlignment: Text.AlignRight
|
||||
|
||||
focus: true
|
||||
color: enabled && activeFocus ? Style.themeColor : Style.baseTextColor
|
||||
|
||||
validator: IntValidator {
|
||||
id: validator
|
||||
}
|
||||
|
||||
Keys.onUpPressed: {
|
||||
root.incrementValue();
|
||||
}
|
||||
|
||||
Keys.onDownPressed: {
|
||||
root.decrementValue();
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
selectAll();
|
||||
} else {
|
||||
commit(parseInt(text))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: suffix
|
||||
visible: root.suffix !== ""
|
||||
color: Style.baseTextColor
|
||||
anchors.baseline: edit.baseline
|
||||
anchors.right: upDownArea.left
|
||||
}
|
||||
|
||||
Item {
|
||||
id: upDownArea
|
||||
// color: "white"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Style.margin
|
||||
anchors.verticalCenter: editFrame.verticalCenter
|
||||
height: upDownIcon.implicitHeight
|
||||
visible: edit.activeFocus
|
||||
width: upDownIcon.implicitWidth
|
||||
|
||||
Image {
|
||||
id: upDownIcon
|
||||
// show up/down arrows
|
||||
source: "qrc:///up-down-arrow"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
width: parent.width
|
||||
height: parent.height / 2
|
||||
onPressed: {
|
||||
root.incrementValue();
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
opacity: 0.5
|
||||
color: Style.themeColor
|
||||
visible: parent.pressed
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: upRepeat
|
||||
interval: 250
|
||||
running: parent.pressed
|
||||
repeat: true
|
||||
onTriggered: root.incrementValue()
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
width: parent.width
|
||||
height: parent.height / 2
|
||||
anchors.bottom: parent.bottom
|
||||
onPressed: {
|
||||
root.decrementValue();
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
opacity: 0.5
|
||||
color: Style.themeColor
|
||||
visible: parent.pressed
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: downRepeat
|
||||
interval: 250
|
||||
running: parent.pressed
|
||||
repeat: true
|
||||
onTriggered: root.decrementValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
} // of frame rectangle
|
||||
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ FocusScope {
|
|||
property string placeholder: ""
|
||||
property alias validator: edit.validator
|
||||
property alias text: edit.text
|
||||
property bool enabled: true
|
||||
|
||||
property alias suggestedWidthString: metrics.text
|
||||
readonly property int suggestedWidth: useFullWidth ? root.width
|
||||
|
@ -16,6 +17,7 @@ FocusScope {
|
|||
property bool useFullWidth: false
|
||||
|
||||
implicitHeight: editFrame.height
|
||||
implicitWidth: suggestedWidth + label.implicitWidth + (Style.margin * 3)
|
||||
|
||||
TextMetrics {
|
||||
id: metrics
|
||||
|
@ -35,10 +37,8 @@ FocusScope {
|
|||
anchors.left: label.right
|
||||
anchors.margins: Style.margin
|
||||
|
||||
|
||||
height: edit.implicitHeight + Style.margin
|
||||
|
||||
width: Math.min(root.width - (label.width + Style.margin * 2), Math.max(suggestedWidth, edit.implicitWidth));
|
||||
width: Math.min(root.width - (label.width + Style.margin), Math.max(suggestedWidth, edit.implicitWidth) + Style.margin * 2);
|
||||
|
||||
radius: Style.roundRadius
|
||||
border.color: edit.activeFocus ? Style.frameColor : Style.minorFrameColor
|
||||
|
@ -54,6 +54,7 @@ FocusScope {
|
|||
anchors.margins: Style.margin
|
||||
selectByMouse: true
|
||||
focus: true
|
||||
color: enabled && activeFocus ? Style.themeColor : Style.baseTextColor
|
||||
|
||||
Text {
|
||||
id: placeholder
|
||||
|
|
|
@ -14,7 +14,11 @@ Item {
|
|||
property int currentIndex: 0
|
||||
property bool __dummy: false
|
||||
|
||||
property alias header: choicesHeader.sourceComponent
|
||||
property string headerText: ""
|
||||
|
||||
implicitHeight: Math.max(label.implicitHeight, currentChoiceFrame.height)
|
||||
implicitWidth: label.implicitWidth + Style.margin + currentChoiceFrame.__naturalWidth
|
||||
|
||||
Item {
|
||||
Repeater {
|
||||
|
@ -44,8 +48,16 @@ Item {
|
|||
__dummy = !__dummy // force update of currentText
|
||||
}
|
||||
|
||||
function haveHeader()
|
||||
{
|
||||
return headerText !== "";
|
||||
}
|
||||
|
||||
function currentText()
|
||||
{
|
||||
if ((currentIndex == -1) && haveHeader())
|
||||
return headerText;
|
||||
|
||||
var foo = __dummy; // fake propery dependency to update this
|
||||
var item = internalModel.itemAt(currentIndex);
|
||||
if (!item) return "";
|
||||
|
@ -65,17 +77,19 @@ Item {
|
|||
Rectangle {
|
||||
id: currentChoiceFrame
|
||||
radius: Style.roundRadius
|
||||
border.color: mouseArea.containsMouse ? Style.themeColor : Style.minorFrameColor
|
||||
border.color: root.enabled ? (mouseArea.containsMouse ? Style.themeColor : Style.minorFrameColor)
|
||||
: Style.inactiveThemeColor
|
||||
border.width: 1
|
||||
height: currentChoiceText.implicitHeight + Style.margin
|
||||
clip: true
|
||||
|
||||
anchors.left: label.right
|
||||
anchors.leftMargin: Style.margin
|
||||
|
||||
// width of current item, or available space after the label
|
||||
width: Math.min(root.width - (label.width + Style.margin),
|
||||
currentChoiceText.implicitWidth + (Style.margin * 2) + upDownIcon.width);
|
||||
width: Math.min(root.width - (label.width + Style.margin), __naturalWidth);
|
||||
|
||||
readonly property int __naturalWidth: currentChoiceText.implicitWidth + (Style.margin * 3) + upDownIcon.width
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Text {
|
||||
|
@ -102,7 +116,7 @@ Item {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
id: mouseArea
|
||||
hoverEnabled: true
|
||||
hoverEnabled: root.enabled
|
||||
enabled: root.enabled
|
||||
onClicked: {
|
||||
var screenPos = _launcher.mapToGlobal(currentChoiceText, Qt.point(0, -currentChoiceText.height * currentIndex))
|
||||
|
@ -138,13 +152,42 @@ Item {
|
|||
anchors.fill: parent
|
||||
}
|
||||
|
||||
// text repeater
|
||||
// choice layout column
|
||||
Column {
|
||||
id: choicesColumn
|
||||
spacing: Style.margin
|
||||
x: Style.margin
|
||||
y: Style.margin
|
||||
|
||||
// optional header component:
|
||||
Loader {
|
||||
id: choicesHeader
|
||||
active: root.haveHeader()
|
||||
|
||||
// default component is just a plain text element, same as
|
||||
// normal items
|
||||
sourceComponent: Text {
|
||||
text: root.headerText
|
||||
height: implicitHeight + Style.margin
|
||||
width: popupFrame.width
|
||||
}
|
||||
|
||||
height: item ? item.height : 0
|
||||
width: item ? item.width : 0
|
||||
|
||||
// essentially the same mouse area as normal items
|
||||
MouseArea {
|
||||
width: popupFrame.width // full width of the popup
|
||||
height: parent.height
|
||||
z: -1 // so header can do other mouse behaviours
|
||||
onClicked: {
|
||||
root.currentIndex = -1;
|
||||
popupFrame.visible = false
|
||||
}
|
||||
}
|
||||
} // of header loader
|
||||
|
||||
// main item repeater
|
||||
Repeater {
|
||||
id: choicesRepeater
|
||||
model: root.model
|
||||
|
|
68
src/GUI/qml/RadioButton.qml
Normal file
68
src/GUI/qml/RadioButton.qml
Normal file
|
@ -0,0 +1,68 @@
|
|||
import QtQuick 2.4
|
||||
import FlightGear 1.0
|
||||
import "."
|
||||
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property bool selected
|
||||
property RadioButtonGroup group // nil by default
|
||||
|
||||
signal clicked()
|
||||
|
||||
implicitHeight: outerRing.height + Style.margin
|
||||
implicitWidth: outerRing.width + Style.margin
|
||||
|
||||
Binding {
|
||||
when: root.group != null
|
||||
target: root
|
||||
property: "selected"
|
||||
value: (root.group.selected === root)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: innerRing
|
||||
anchors.centerIn: parent
|
||||
width: radius * 2
|
||||
height: radius * 2
|
||||
radius: Style.roundRadius
|
||||
color: Style.themeColor
|
||||
visible: selected || mouse.containsMouse
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: outerRing
|
||||
anchors.centerIn: parent
|
||||
border.color: Style.themeColor
|
||||
border.width: 2
|
||||
color: "transparent"
|
||||
radius: Style.roundRadius + 4
|
||||
width: radius * 2
|
||||
height: radius * 2
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: pressRing
|
||||
opacity: 0.3
|
||||
width: outerRing.width * 2
|
||||
height: outerRing.height * 2
|
||||
visible: mouse.pressed
|
||||
radius: width / 2
|
||||
color: "#7f7f7f"
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
if (root.group) {
|
||||
root.group.selected = root;
|
||||
}
|
||||
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,14 +5,15 @@ FocusScope
|
|||
{
|
||||
id: root
|
||||
|
||||
width:frame.width
|
||||
width: Style.strutSize * 3
|
||||
height: frame.height
|
||||
|
||||
// property string text
|
||||
property string placeholder: qsTr("Search")
|
||||
property bool active: false
|
||||
|
||||
signal search(string term)
|
||||
|
||||
property bool autoSubmit: true
|
||||
property alias autoSubmitTimeout: searchTimer.interval
|
||||
|
||||
onActiveChanged: {
|
||||
|
@ -23,7 +24,7 @@ FocusScope
|
|||
|
||||
function clear()
|
||||
{
|
||||
buttonText.text = "Search"
|
||||
buttonText.text = ""
|
||||
root.focus = false
|
||||
searchTimer.stop();
|
||||
root.search("");
|
||||
|
@ -34,12 +35,14 @@ FocusScope
|
|||
id: frame
|
||||
radius: Style.roundRadius
|
||||
|
||||
width: Style.strutSize * 3
|
||||
width: root.width
|
||||
height: Math.max(searchIcon.height, buttonText.height) + (Style.roundRadius)
|
||||
border.width: 1
|
||||
border.color: (mouse.containsMouse | active) ? Style.themeColor: Style.minorFrameColor
|
||||
clip: true
|
||||
|
||||
|
||||
|
||||
TextInput {
|
||||
id: buttonText
|
||||
anchors.left: parent.left
|
||||
|
@ -51,7 +54,9 @@ FocusScope
|
|||
focus: true
|
||||
|
||||
onTextChanged: {
|
||||
searchTimer.restart();
|
||||
if (root.autoSubmit) {
|
||||
searchTimer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
onEditingFinished: {
|
||||
|
@ -63,7 +68,14 @@ FocusScope
|
|||
}
|
||||
}
|
||||
|
||||
text: "Search"
|
||||
text: ""
|
||||
|
||||
// placeholder text, hides itself whenever parent has non-empty text
|
||||
Text {
|
||||
anchors.fill: parent
|
||||
visible: parent.text == ""
|
||||
text: root.placeholder
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
|
|
|
@ -121,7 +121,7 @@ Item {
|
|||
label: qsTr("Show debugging console")
|
||||
description: qsTr("Open a console window showing debug output from the application.")
|
||||
advanced: true
|
||||
hidden: _osName != "win"
|
||||
hidden: _osName !== "win"
|
||||
keywords: ["console", "terminal", "log", "debug"]
|
||||
setting: "console"
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ Item {
|
|||
property bool enabled: true
|
||||
|
||||
implicitWidth: track.width + label.width + 16
|
||||
implicitHeight: label.height
|
||||
implicitHeight: Math.max(label.height, thumb.height)
|
||||
|
||||
Rectangle {
|
||||
id: track
|
||||
|
|
BIN
src/GUI/qml/icons8-linear-spinner.gif
Normal file
BIN
src/GUI/qml/icons8-linear-spinner.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
|
@ -86,6 +86,10 @@
|
|||
<file>qml/PathListDelegate.qml</file>
|
||||
<file>qml/AddCatalogPanel.qml</file>
|
||||
<file>qml/LineEdit.qml</file>
|
||||
<file alias="linear-spinner">qml/icons8-linear-spinner.gif</file>
|
||||
<file>qml/RadioButton.qml</file>
|
||||
<file>qml/IntegerSpinbox.qml</file>
|
||||
<file>qml/DoubleSpinbox.qml</file>
|
||||
</qresource>
|
||||
<qresource prefix="/preview">
|
||||
<file alias="close-icon">preview-close.png</file>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 768 B After Width: | Height: | Size: 802 B |
Loading…
Reference in a new issue