UI: small fixes to various controls
Especially, add return key handling to many editing controls
This commit is contained in:
parent
f33b15575f
commit
e062026d9c
7 changed files with 144 additions and 40 deletions
|
@ -4,11 +4,16 @@ import FlightGear 1.0
|
||||||
import FlightGear.Launcher 1.0
|
import FlightGear.Launcher 1.0
|
||||||
import "."
|
import "."
|
||||||
|
|
||||||
LineEdit
|
FocusScope
|
||||||
{
|
{
|
||||||
id: root
|
id: root
|
||||||
placeholder: "KSFO"
|
readonly property Positioned airport: airport
|
||||||
suggestedWidthString: "XXXX"
|
implicitWidth: edit.implicitWidth + nameDisplay.width
|
||||||
|
implicitHeight: edit.implicitHeight
|
||||||
|
|
||||||
|
property alias label: edit.label
|
||||||
|
|
||||||
|
signal clickedName();
|
||||||
|
|
||||||
Positioned {
|
Positioned {
|
||||||
id: airport
|
id: airport
|
||||||
|
@ -17,24 +22,12 @@ LineEdit
|
||||||
function selectAirport(guid)
|
function selectAirport(guid)
|
||||||
{
|
{
|
||||||
airport.guid = guid
|
airport.guid = guid
|
||||||
text = airport.ident
|
edit.text = airport.ident
|
||||||
// we don't want this to trigger a search ....
|
// we don't want this to trigger a search ....
|
||||||
searchTimer.stop();
|
searchTimer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
signal pickAirport(var guid);
|
||||||
if (activeFocus) {
|
|
||||||
OverlayShared.globalOverlay.showOverlayAtItemOffset(overlay, root, Qt.point(xOffsetForEditFrame, root.height + Style.margin))
|
|
||||||
} else {
|
|
||||||
OverlayShared.globalOverlay.dismissOverlay()
|
|
||||||
searchCompleter.clear();
|
|
||||||
if (!airport.valid) {
|
|
||||||
text = ""; // ensure we always contain a valid ICAO or nothing
|
|
||||||
// we don't want this to trigger a search ....
|
|
||||||
searchTimer.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NavaidSearch {
|
NavaidSearch {
|
||||||
id: searchCompleter
|
id: searchCompleter
|
||||||
|
@ -43,22 +36,18 @@ LineEdit
|
||||||
|
|
||||||
onSearchComplete: {
|
onSearchComplete: {
|
||||||
if (exactMatch !== 0) {
|
if (exactMatch !== 0) {
|
||||||
selectAirport(exactMatch)
|
pickAirport(exactMatch)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onTextChanged: {
|
|
||||||
searchTimer.restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: searchTimer
|
id: searchTimer
|
||||||
interval: 400
|
interval: 400
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (root.text.length >= 2) {
|
if (edit.text.length >= 2) {
|
||||||
searchCompleter.setSearch(root.text, NavaidSearch.Airplane)
|
searchCompleter.setSearch(edit.text, _launcher.aircraftType)
|
||||||
} else {
|
} else {
|
||||||
// ensure we update with no search (cancel, effectively)
|
// ensure we update with no search (cancel, effectively)
|
||||||
searchCompleter.clear();
|
searchCompleter.clear();
|
||||||
|
@ -66,14 +55,60 @@ LineEdit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
|
||||||
anchors.left: parent.right
|
LineEdit
|
||||||
|
{
|
||||||
|
id: edit
|
||||||
|
placeholder: "KSFO"
|
||||||
|
suggestedWidthString: "XXXX"
|
||||||
|
commitOnReturn: false
|
||||||
|
focus: true
|
||||||
|
|
||||||
|
onActiveFocusChanged: {
|
||||||
|
if (activeFocus) {
|
||||||
|
OverlayShared.globalOverlay.showOverlayAtItemOffset(overlay, root, Qt.point(xOffsetForEditFrame, root.height + Style.margin))
|
||||||
|
} else {
|
||||||
|
OverlayShared.globalOverlay.dismissOverlay()
|
||||||
|
searchCompleter.clear();
|
||||||
|
if (!airport.valid) {
|
||||||
|
text = ""; // ensure we always contain a valid ICAO or nothing
|
||||||
|
// we don't want this to trigger a search ....
|
||||||
|
searchTimer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
searchTimer.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
// start a search right now, if we don't have one active
|
||||||
|
if (!searchCompleter.haveExistingSearch && (edit.text.length >= 2)) {
|
||||||
|
searchCompleter.setSearch(edit.text, _launcher.aircraftType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we have a search and at least one valid result, select it
|
||||||
|
// combined with the previous behaviour, this means entering an ICAO
|
||||||
|
// code (which are returend synchronously inside setSearch) and
|
||||||
|
// hitting enter/return works as expected
|
||||||
|
if (searchCompleter.haveExistingSearch && (searchCompleter.numResults > 0)) {
|
||||||
|
root.pickAirport(searchCompleter.guidAtIndex(0));
|
||||||
|
root.focus = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ClickableText {
|
||||||
|
id: nameDisplay
|
||||||
|
anchors.left: edit.right
|
||||||
anchors.leftMargin: Style.margin
|
anchors.leftMargin: Style.margin
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: airport.name
|
text: airport.name
|
||||||
visible: airport.valid
|
visible: airport.valid
|
||||||
width: Style.strutSize * 3
|
width: Style.strutSize * 3
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
|
onClicked: root.clickedName()
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
|
@ -84,7 +119,6 @@ LineEdit
|
||||||
color: "white"
|
color: "white"
|
||||||
height: choicesColumn.childrenRect.height + Style.margin * 2
|
height: choicesColumn.childrenRect.height + Style.margin * 2
|
||||||
width: choicesColumn.width + Style.margin * 2
|
width: choicesColumn.width + Style.margin * 2
|
||||||
|
|
||||||
visible: searchCompleter.haveExistingSearch
|
visible: searchCompleter.haveExistingSearch
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -124,6 +158,8 @@ LineEdit
|
||||||
text: model.ident + " - " + model.name
|
text: model.ident + " - " + model.name
|
||||||
height: implicitHeight + Style.margin
|
height: implicitHeight + Style.margin
|
||||||
font.pixelSize: Style.baseFontPixelSize
|
font.pixelSize: Style.baseFontPixelSize
|
||||||
|
|
||||||
|
readonly property bool isCurrent: (selectionPopup.currentIndex === model.index)
|
||||||
color: choiceArea.containsMouse ? Style.themeColor : Style.baseTextColor
|
color: choiceArea.containsMouse ? Style.themeColor : Style.baseTextColor
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
@ -133,7 +169,7 @@ LineEdit
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.selectAirport(model.guid)
|
root.pickAirport(model.guid)
|
||||||
root.focus = false
|
root.focus = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,7 @@ FocusScope {
|
||||||
height: parent.height
|
height: parent.height
|
||||||
width: metrics.width
|
width: metrics.width
|
||||||
maximumLength: fieldWidth
|
maximumLength: fieldWidth
|
||||||
|
font.pixelSize: Style.baseFontPixelSize
|
||||||
|
|
||||||
Keys.onUpPressed: {
|
Keys.onUpPressed: {
|
||||||
incrementValue();
|
incrementValue();
|
||||||
|
|
|
@ -8,6 +8,7 @@ FocusScope {
|
||||||
property alias validator: edit.validator
|
property alias validator: edit.validator
|
||||||
property alias text: edit.text
|
property alias text: edit.text
|
||||||
property bool enabled: true
|
property bool enabled: true
|
||||||
|
property bool commitOnReturn: true
|
||||||
|
|
||||||
property alias suggestedWidthString: metrics.text
|
property alias suggestedWidthString: metrics.text
|
||||||
readonly property int suggestedWidth: useFullWidth ? root.width
|
readonly property int suggestedWidth: useFullWidth ? root.width
|
||||||
|
@ -21,6 +22,12 @@ FocusScope {
|
||||||
implicitHeight: editFrame.height
|
implicitHeight: editFrame.height
|
||||||
implicitWidth: suggestedWidth + label.implicitWidth + (Style.margin * 3)
|
implicitWidth: suggestedWidth + label.implicitWidth + (Style.margin * 3)
|
||||||
|
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
if (activeFocus && commitOnReturn) {
|
||||||
|
focus = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TextMetrics {
|
TextMetrics {
|
||||||
id: metrics
|
id: metrics
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,31 @@ FocusScope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeToUnits(unitIndex)
|
||||||
|
{
|
||||||
|
if (edit.activeFocus) {
|
||||||
|
// build up a quantity with the current text value, in the
|
||||||
|
// previous units. We need to parse as text before we
|
||||||
|
// change the selected unit
|
||||||
|
var q = root.quantity;
|
||||||
|
q.value = clampValue(parseTextAsValue());
|
||||||
|
|
||||||
|
// convert to the new quantity
|
||||||
|
units.selectedIndex = unitIndex;
|
||||||
|
var newQuantity = q.convertToUnit(units.selectedUnit)
|
||||||
|
|
||||||
|
console.info("Changing text to:" + newQuantity.value.toFixed(units.numDecimals));
|
||||||
|
edit.text = newQuantity.value.toFixed(units.numDecimals)
|
||||||
|
|
||||||
|
console.info("Change units commit:" + newQuantity.value)
|
||||||
|
commit(newQuantity);
|
||||||
|
} else {
|
||||||
|
// not focused, easy
|
||||||
|
units.selectedIndex = unitIndex;
|
||||||
|
root.commit(root.quantity.convertToUnit(units.selectedUnit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (quantity.unit === Units.NoUnits) {
|
if (quantity.unit === Units.NoUnits) {
|
||||||
var q = quantity;
|
var q = quantity;
|
||||||
|
@ -187,6 +212,11 @@ FocusScope {
|
||||||
root.decrementValue();
|
root.decrementValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
root.focus = false;
|
||||||
|
// will trigger onActiveFocusChanged
|
||||||
|
}
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
onActiveFocusChanged: {
|
||||||
if (activeFocus) {
|
if (activeFocus) {
|
||||||
selectAll();
|
selectAll();
|
||||||
|
@ -347,8 +377,7 @@ FocusScope {
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
units.selectedIndex = model.index;
|
root.changeToUnits(model.index);
|
||||||
root.commit(root.quantity.convertToUnit(units.selectedUnit));
|
|
||||||
unitSelectionPopup.visible = false;
|
unitSelectionPopup.visible = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ Rectangle {
|
||||||
border.color: edit.activeFocus ? Style.frameColor : Style.minorFrameColor
|
border.color: edit.activeFocus ? Style.frameColor : Style.minorFrameColor
|
||||||
border.width: 1
|
border.width: 1
|
||||||
|
|
||||||
|
signal editingFinished();
|
||||||
|
|
||||||
TextEdit {
|
TextEdit {
|
||||||
id: edit
|
id: edit
|
||||||
enabled: editFrame.enabled
|
enabled: editFrame.enabled
|
||||||
|
@ -20,7 +22,7 @@ Rectangle {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.margins: Style.margin
|
anchors.margins: Style.margin
|
||||||
height: Math.max(Style.strutSize * 4, implicitHeight)
|
height: Math.max(Style.strutSize * 2, implicitHeight)
|
||||||
textFormat: TextEdit.PlainText
|
textFormat: TextEdit.PlainText
|
||||||
font.family: "Courier"
|
font.family: "Courier"
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
|
@ -34,5 +36,11 @@ Rectangle {
|
||||||
font.family: "Courier"
|
font.family: "Courier"
|
||||||
color: Style.disabledTextColor
|
color: Style.disabledTextColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onActiveFocusChanged: {
|
||||||
|
if (!activeFocus) {
|
||||||
|
editFrame.editingFinished()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ Item {
|
||||||
property string headerText: ""
|
property string headerText: ""
|
||||||
|
|
||||||
implicitHeight: Math.max(label.implicitHeight, currentChoiceFrame.height)
|
implicitHeight: Math.max(label.implicitHeight, currentChoiceFrame.height)
|
||||||
implicitWidth: label.implicitWidth + Style.margin + currentChoiceFrame.__naturalWidth
|
implicitWidth: label.implicitWidth + (Style.margin * 2) + currentChoiceFrame.__naturalWidth
|
||||||
|
|
||||||
function select(index)
|
function select(index)
|
||||||
{
|
{
|
||||||
|
@ -70,7 +70,7 @@ Item {
|
||||||
StyledText {
|
StyledText {
|
||||||
id: label
|
id: label
|
||||||
anchors.left: root.left
|
anchors.left: root.left
|
||||||
anchors.leftMargin: 8
|
anchors.leftMargin: Style.margin
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
horizontalAlignment: Text.AlignRight
|
horizontalAlignment: Text.AlignRight
|
||||||
enabled: root.enabled
|
enabled: root.enabled
|
||||||
|
|
|
@ -7,8 +7,9 @@ FocusScope {
|
||||||
property alias label: label.text
|
property alias label: label.text
|
||||||
property bool enabled: true
|
property bool enabled: true
|
||||||
property var value: new Date()
|
property var value: new Date()
|
||||||
|
property bool isDuration: true
|
||||||
|
|
||||||
implicitHeight: label.implicitHeight
|
implicitHeight: editFrame.height
|
||||||
implicitWidth: label.implicitWidth + Style.margin + editFrame.width
|
implicitWidth: label.implicitWidth + Style.margin + editFrame.width
|
||||||
|
|
||||||
function updateCurrentTime()
|
function updateCurrentTime()
|
||||||
|
@ -16,6 +17,12 @@ FocusScope {
|
||||||
root.value = new Date(0, 0, 0, hours.value, minutes.value);
|
root.value = new Date(0, 0, 0, hours.value, minutes.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setDurationMinutes(minutes)
|
||||||
|
{
|
||||||
|
var d = new Date(0, 0, 0, 0, minutes);
|
||||||
|
setTime(d);
|
||||||
|
}
|
||||||
|
|
||||||
function setTime(date)
|
function setTime(date)
|
||||||
{
|
{
|
||||||
hours.value = date.getHours();
|
hours.value = date.getHours();
|
||||||
|
@ -32,13 +39,18 @@ FocusScope {
|
||||||
enabled: root.enabled
|
enabled: root.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
if (activeFocus) {
|
||||||
|
focus = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: editFrame
|
id: editFrame
|
||||||
radius: Style.roundRadius
|
clip: true
|
||||||
border.color: root.focus ? Style.themeColor : Style.minorFrameColor
|
|
||||||
|
|
||||||
border.width: 1
|
|
||||||
height: 30
|
height: hours.height + Style.margin
|
||||||
|
|
||||||
anchors.left: label.right
|
anchors.left: label.right
|
||||||
anchors.leftMargin: Style.margin
|
anchors.leftMargin: Style.margin
|
||||||
|
@ -58,14 +70,14 @@ FocusScope {
|
||||||
DateTimeValueEdit {
|
DateTimeValueEdit {
|
||||||
id: hours
|
id: hours
|
||||||
minValue: 0
|
minValue: 0
|
||||||
maxValue: 23
|
maxValue: root.isDuration ? 9999 : 23
|
||||||
widthString: "00"
|
widthString: "00"
|
||||||
nextToFocus: minutes
|
nextToFocus: minutes
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
onCommit: updateCurrentTime();
|
onCommit: updateCurrentTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
StyledText {
|
||||||
text: " : "
|
text: " : "
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
enabled: root.enabled
|
enabled: root.enabled
|
||||||
|
@ -81,6 +93,17 @@ FocusScope {
|
||||||
onCommit: updateCurrentTime();
|
onCommit: updateCurrentTime();
|
||||||
}
|
}
|
||||||
} // of time elements row
|
} // of time elements row
|
||||||
|
|
||||||
|
// frame rectange - we need this so we can clip our children
|
||||||
|
// but ensure our frame also apepars on top
|
||||||
|
Rectangle {
|
||||||
|
z: 100
|
||||||
|
anchors.fill: parent
|
||||||
|
border.color: root.focus ? Style.themeColor : Style.minorFrameColor
|
||||||
|
border.width: 1
|
||||||
|
radius: Style.roundRadius
|
||||||
|
color: "transparent"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue