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 "."
|
||||
|
||||
LineEdit
|
||||
FocusScope
|
||||
{
|
||||
id: root
|
||||
placeholder: "KSFO"
|
||||
suggestedWidthString: "XXXX"
|
||||
readonly property Positioned airport: airport
|
||||
implicitWidth: edit.implicitWidth + nameDisplay.width
|
||||
implicitHeight: edit.implicitHeight
|
||||
|
||||
property alias label: edit.label
|
||||
|
||||
signal clickedName();
|
||||
|
||||
Positioned {
|
||||
id: airport
|
||||
|
@ -17,24 +22,12 @@ LineEdit
|
|||
function selectAirport(guid)
|
||||
{
|
||||
airport.guid = guid
|
||||
text = airport.ident
|
||||
edit.text = airport.ident
|
||||
// we don't want this to trigger a search ....
|
||||
searchTimer.stop();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
signal pickAirport(var guid);
|
||||
|
||||
NavaidSearch {
|
||||
id: searchCompleter
|
||||
|
@ -43,22 +36,18 @@ LineEdit
|
|||
|
||||
onSearchComplete: {
|
||||
if (exactMatch !== 0) {
|
||||
selectAirport(exactMatch)
|
||||
pickAirport(exactMatch)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
searchTimer.restart();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: searchTimer
|
||||
interval: 400
|
||||
onTriggered: {
|
||||
if (root.text.length >= 2) {
|
||||
searchCompleter.setSearch(root.text, NavaidSearch.Airplane)
|
||||
if (edit.text.length >= 2) {
|
||||
searchCompleter.setSearch(edit.text, _launcher.aircraftType)
|
||||
} else {
|
||||
// ensure we update with no search (cancel, effectively)
|
||||
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.verticalCenter: parent.verticalCenter
|
||||
text: airport.name
|
||||
visible: airport.valid
|
||||
width: Style.strutSize * 3
|
||||
elide: Text.ElideRight
|
||||
onClicked: root.clickedName()
|
||||
}
|
||||
|
||||
Component {
|
||||
|
@ -84,7 +119,6 @@ LineEdit
|
|||
color: "white"
|
||||
height: choicesColumn.childrenRect.height + Style.margin * 2
|
||||
width: choicesColumn.width + Style.margin * 2
|
||||
|
||||
visible: searchCompleter.haveExistingSearch
|
||||
|
||||
Rectangle {
|
||||
|
@ -124,6 +158,8 @@ LineEdit
|
|||
text: model.ident + " - " + model.name
|
||||
height: implicitHeight + Style.margin
|
||||
font.pixelSize: Style.baseFontPixelSize
|
||||
|
||||
readonly property bool isCurrent: (selectionPopup.currentIndex === model.index)
|
||||
color: choiceArea.containsMouse ? Style.themeColor : Style.baseTextColor
|
||||
|
||||
MouseArea {
|
||||
|
@ -133,7 +169,7 @@ LineEdit
|
|||
hoverEnabled: true
|
||||
|
||||
onClicked: {
|
||||
root.selectAirport(model.guid)
|
||||
root.pickAirport(model.guid)
|
||||
root.focus = false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ FocusScope {
|
|||
height: parent.height
|
||||
width: metrics.width
|
||||
maximumLength: fieldWidth
|
||||
font.pixelSize: Style.baseFontPixelSize
|
||||
|
||||
Keys.onUpPressed: {
|
||||
incrementValue();
|
||||
|
|
|
@ -8,6 +8,7 @@ FocusScope {
|
|||
property alias validator: edit.validator
|
||||
property alias text: edit.text
|
||||
property bool enabled: true
|
||||
property bool commitOnReturn: true
|
||||
|
||||
property alias suggestedWidthString: metrics.text
|
||||
readonly property int suggestedWidth: useFullWidth ? root.width
|
||||
|
@ -21,6 +22,12 @@ FocusScope {
|
|||
implicitHeight: editFrame.height
|
||||
implicitWidth: suggestedWidth + label.implicitWidth + (Style.margin * 3)
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (activeFocus && commitOnReturn) {
|
||||
focus = false;
|
||||
}
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
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: {
|
||||
if (quantity.unit === Units.NoUnits) {
|
||||
var q = quantity;
|
||||
|
@ -187,6 +212,11 @@ FocusScope {
|
|||
root.decrementValue();
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
root.focus = false;
|
||||
// will trigger onActiveFocusChanged
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
selectAll();
|
||||
|
@ -347,8 +377,7 @@ FocusScope {
|
|||
hoverEnabled: true
|
||||
|
||||
onClicked: {
|
||||
units.selectedIndex = model.index;
|
||||
root.commit(root.quantity.convertToUnit(units.selectedUnit));
|
||||
root.changeToUnits(model.index);
|
||||
unitSelectionPopup.visible = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ Rectangle {
|
|||
border.color: edit.activeFocus ? Style.frameColor : Style.minorFrameColor
|
||||
border.width: 1
|
||||
|
||||
signal editingFinished();
|
||||
|
||||
TextEdit {
|
||||
id: edit
|
||||
enabled: editFrame.enabled
|
||||
|
@ -20,7 +22,7 @@ Rectangle {
|
|||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: Style.margin
|
||||
height: Math.max(Style.strutSize * 4, implicitHeight)
|
||||
height: Math.max(Style.strutSize * 2, implicitHeight)
|
||||
textFormat: TextEdit.PlainText
|
||||
font.family: "Courier"
|
||||
selectByMouse: true
|
||||
|
@ -34,5 +36,11 @@ Rectangle {
|
|||
font.family: "Courier"
|
||||
color: Style.disabledTextColor
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (!activeFocus) {
|
||||
editFrame.editingFinished()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ Item {
|
|||
property string headerText: ""
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -70,7 +70,7 @@ Item {
|
|||
StyledText {
|
||||
id: label
|
||||
anchors.left: root.left
|
||||
anchors.leftMargin: 8
|
||||
anchors.leftMargin: Style.margin
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
horizontalAlignment: Text.AlignRight
|
||||
enabled: root.enabled
|
||||
|
|
|
@ -7,8 +7,9 @@ FocusScope {
|
|||
property alias label: label.text
|
||||
property bool enabled: true
|
||||
property var value: new Date()
|
||||
property bool isDuration: true
|
||||
|
||||
implicitHeight: label.implicitHeight
|
||||
implicitHeight: editFrame.height
|
||||
implicitWidth: label.implicitWidth + Style.margin + editFrame.width
|
||||
|
||||
function updateCurrentTime()
|
||||
|
@ -16,6 +17,12 @@ FocusScope {
|
|||
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)
|
||||
{
|
||||
hours.value = date.getHours();
|
||||
|
@ -32,13 +39,18 @@ FocusScope {
|
|||
enabled: root.enabled
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
if (activeFocus) {
|
||||
focus = false;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: editFrame
|
||||
radius: Style.roundRadius
|
||||
border.color: root.focus ? Style.themeColor : Style.minorFrameColor
|
||||
clip: true
|
||||
|
||||
border.width: 1
|
||||
height: 30
|
||||
|
||||
height: hours.height + Style.margin
|
||||
|
||||
anchors.left: label.right
|
||||
anchors.leftMargin: Style.margin
|
||||
|
@ -58,14 +70,14 @@ FocusScope {
|
|||
DateTimeValueEdit {
|
||||
id: hours
|
||||
minValue: 0
|
||||
maxValue: 23
|
||||
maxValue: root.isDuration ? 9999 : 23
|
||||
widthString: "00"
|
||||
nextToFocus: minutes
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onCommit: updateCurrentTime();
|
||||
}
|
||||
|
||||
Text {
|
||||
StyledText {
|
||||
text: " : "
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
enabled: root.enabled
|
||||
|
@ -81,6 +93,17 @@ FocusScope {
|
|||
onCommit: updateCurrentTime();
|
||||
}
|
||||
} // 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…
Reference in a new issue