-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhance battery indicator visuals with new SVGs and color coding #11881
Changes from 15 commits
dc2148c
feb382c
ae4249a
c6ab475
c7be67c
e047024
7bda84d
cf43592
0b8cfbc
fb186df
5138b77
81ee7db
4f78b5a
012cbb4
7563664
0f5c193
0461be3
fc5d511
c2ce804
3a33e93
80806a3
fd10395
27d3eb3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,28 @@ | ||
{ | ||
"version": 1, | ||
"fileType": "FactMetaData", | ||
"QGC.MetaData.Facts": | ||
[ | ||
{ | ||
"name": "display", | ||
"shortDesc": "Select values to display in indicator", | ||
"enumStrings": "Percentage,Voltage,Percentage and Voltage", | ||
"enumValues": "0,1,2", | ||
"type": "uint32", | ||
"default": false | ||
} | ||
] | ||
"version": 1, | ||
"fileType": "FactMetaData", | ||
"QGC.MetaData.Facts": [ | ||
{ | ||
"name": "display", | ||
"shortDesc": "Select values to display in indicator", | ||
"enumStrings": "Percentage,Voltage,Percentage and Voltage", | ||
"enumValues": "0,1,2", | ||
"type": "uint32", | ||
"default": false | ||
}, | ||
{ | ||
"name": "threshold1", | ||
"shortDesc": "Battery level threshold 1", | ||
"type": "uint32", | ||
"default": 80, | ||
"units": "%" | ||
}, | ||
{ | ||
"name": "threshold2", | ||
"shortDesc": "Battery level threshold 2", | ||
"type": "uint32", | ||
"default": 60, | ||
"units": "%" | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,13 @@ Item { | |
property bool _showVoltage: _indicatorDisplay.rawValue === 1 | ||
property bool _showBoth: _indicatorDisplay.rawValue === 2 | ||
|
||
// Fetch battery settings | ||
property var batterySettings: QGroundControl.settingsManager.batteryIndicatorSettings | ||
|
||
// Properties to hold the thresholds | ||
property int threshold1: batterySettings.threshold1.rawValue | ||
property int threshold2: batterySettings.threshold2.rawValue | ||
|
||
Row { | ||
id: batteryIndicatorRow | ||
anchors.top: parent.top | ||
|
@@ -81,17 +88,53 @@ Item { | |
|
||
function getBatteryColor() { | ||
switch (battery.chargeState.rawValue) { | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_OK: | ||
return qgcPal.text | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_LOW: | ||
return qgcPal.colorOrange | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_CRITICAL: | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_EMERGENCY: | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_FAILED: | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_UNHEALTHY: | ||
return qgcPal.colorRed | ||
default: | ||
return qgcPal.text | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_OK: | ||
if (!isNaN(battery.percentRemaining.rawValue)) { | ||
if (battery.percentRemaining.rawValue > threshold1) { | ||
return qgcPal.colorGreen | ||
} else if (battery.percentRemaining.rawValue > threshold2) { | ||
return qgcPal.colorYellowGreen | ||
} else { | ||
return qgcPal.colorYellow | ||
} | ||
} else { | ||
return qgcPal.text | ||
} | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_LOW: | ||
return qgcPal.colorOrange | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_CRITICAL: | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_EMERGENCY: | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_FAILED: | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_UNHEALTHY: | ||
return qgcPal.colorRed | ||
default: | ||
return qgcPal.text | ||
} | ||
} | ||
|
||
function getBatterySvgSource() { | ||
|
||
switch (battery.chargeState.rawValue) { | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_OK: | ||
if (!isNaN(battery.percentRemaining.rawValue)) { | ||
if (battery.percentRemaining.rawValue > threshold1) { | ||
return "/qmlimages/BatteryGreen.svg" | ||
} else if (battery.percentRemaining.rawValue > threshold2) { | ||
return "/qmlimages/BatteryYellowGreen.svg" | ||
} else { | ||
return "/qmlimages/BatteryYellow.svg" | ||
} | ||
} | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_LOW: | ||
return "/qmlimages/BatteryOrange.svg" // Low with orange svg | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_CRITICAL: | ||
return "/qmlimages/BatteryCritical.svg" // Critical with red svg | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_EMERGENCY: | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_FAILED: | ||
case MAVLink.MAV_BATTERY_CHARGE_STATE_UNHEALTHY: | ||
return "/qmlimages/BatteryEMERGENCY.svg" // Exclamation mark | ||
default: | ||
return "/qmlimages/Battery.svg" // Fallback if percentage is unavailable | ||
} | ||
} | ||
|
||
|
@@ -124,7 +167,7 @@ Item { | |
anchors.bottom: parent.bottom | ||
width: height | ||
sourceSize.width: width | ||
source: "/qmlimages/Battery.svg" | ||
source: getBatterySvgSource() | ||
fillMode: Image.PreserveAspectFit | ||
color: getBatteryColor() | ||
} | ||
|
@@ -138,7 +181,7 @@ Item { | |
QGCLabel { | ||
Layout.alignment: Qt.AlignHCenter | ||
verticalAlignment: Text.AlignVCenter | ||
color: getBatteryColor() | ||
color: qgcPal.text | ||
text: getBatteryPercentageText() | ||
font.pointSize: _showBoth ? ScreenTools.defaultFontPointSize : ScreenTools.mediumFontPointSize | ||
visible: _showBoth || _showPercentage | ||
|
@@ -147,7 +190,7 @@ Item { | |
QGCLabel { | ||
Layout.alignment: Qt.AlignHCenter | ||
font.pointSize: _showBoth ? ScreenTools.defaultFontPointSize : ScreenTools.mediumFontPointSize | ||
color: getBatteryColor() | ||
color: qgcPal.text | ||
text: getBatteryVoltageText() | ||
visible: _showBoth || _showVoltage | ||
} | ||
|
@@ -240,6 +283,7 @@ Item { | |
} | ||
} | ||
|
||
|
||
Component { | ||
id: batteryExpandedComponent | ||
|
||
|
@@ -278,6 +322,117 @@ Item { | |
} | ||
} | ||
} | ||
|
||
} | ||
|
||
SettingsGroupLayout { | ||
heading: qsTr("Battery State Display") | ||
Layout.fillWidth: true | ||
spacing: ScreenTools.defaultFontPixelWidth * 0.5 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The visibility of this group should be based on Also each individual settings has a Both of these combined give a good level of custom build override capability. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’ve implemented the visibility controls as you suggested, using In the bool BatteryIndicatorSettings::visible() const {
QSettings settings;
return settings.value("ShowBatterySettings", true).toBool();
}
bool BatteryIndicatorSettings::thresholdEditable() const {
QSettings settings;
return settings.value("ThresholdEditable", true).toBool();
} However, I’m unsure how to properly configure these two settings to effectively allow custom builds to hide this section if they choose to. Could you provide how to set this up correctly? Your expertise would be greatly appreciated! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the current setup, if the If the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
there is no extra work needed. SettingsGroup and SettingsFact base classes already support this automatically. |
||
|
||
RowLayout { | ||
//Layout.fillWidth: true | ||
|
||
QGCColoredImage { | ||
source: "/qmlimages/BatteryGreen.svg" | ||
height: ScreenTools.defaultFontPixelHeight * 5 | ||
width: ScreenTools.defaultFontPixelWidth * 7 | ||
fillMode: Image.PreserveAspectFit | ||
color: qgcPal.colorGreen | ||
} | ||
|
||
QGCLabel { | ||
Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 3.5 | ||
text: qsTr("100%") | ||
Layout.leftMargin: -13 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should never use fix pixels as margins. Everything needs to be based on the current font. Otherwise the ui won't scale to font size changes. The way to lay this out is as follows:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I appreciate your guidance, and I've implemented the layout adjustments as you suggested. Each battery icon, along with its corresponding percentage or text field, is now placed in its own |
||
} | ||
|
||
QGCColoredImage { | ||
source: "/qmlimages/BatteryYellowGreen.svg" | ||
height: ScreenTools.defaultFontPixelHeight * 5 | ||
width: ScreenTools.defaultFontPixelWidth * 7 | ||
fillMode: Image.PreserveAspectFit | ||
color: qgcPal.colorYellowGreen | ||
} | ||
|
||
FactTextField { | ||
id: threshold1Field | ||
fact: batterySettings.threshold1 | ||
validator: IntValidator { bottom: 16 } // Value is at least 16 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be done by specifying min in the FactMetaData. Then you get automatic validation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’ve implemented the validation fully on the C++ side in onEditingFinished: {
batterySettings.setThreshold2(parseInt(text));
} |
||
implicitWidth: ScreenTools.defaultFontPixelWidth * 6 // Reduced width | ||
Layout.leftMargin: -10 | ||
//Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 2 // Reduced width using Layout.preferredWidth | ||
height: ScreenTools.defaultFontPixelHeight * 1.5 | ||
onEditingFinished: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then you do final level of validation on a rawValueChanged signal to adjust if needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've implemented the final level of validation in the |
||
let newValue = parseInt(text); | ||
if (newValue > batterySettings.threshold2.rawValue) { | ||
batterySettings.threshold1.rawValue = newValue; | ||
} else { | ||
// Adjust value if invalid | ||
batterySettings.threshold1.rawValue = batterySettings.threshold2.rawValue - 1; | ||
text = batterySettings.threshold1.rawValue.toString(); // Update displayed text | ||
} | ||
} | ||
} | ||
|
||
QGCColoredImage { | ||
source: "/qmlimages/BatteryYellow.svg" | ||
height: ScreenTools.defaultFontPixelHeight * 5 | ||
width: ScreenTools.defaultFontPixelWidth * 7 | ||
fillMode: Image.PreserveAspectFit | ||
color: qgcPal.colorYellow | ||
} | ||
|
||
FactTextField { | ||
id: threshold2Field | ||
fact: batterySettings.threshold2 | ||
validator: IntValidator { bottom: 16 } | ||
implicitWidth: ScreenTools.defaultFontPixelWidth * 6 | ||
Layout.leftMargin: -10 | ||
height: ScreenTools.defaultFontPixelHeight * 1.5 | ||
onEditingFinished: { | ||
let newValue = parseInt(text); | ||
if (newValue < batterySettings.threshold1.rawValue) { | ||
batterySettings.threshold2.rawValue = newValue; | ||
} else { | ||
batterySettings.threshold2.rawValue = batterySettings.threshold1.rawValue - 1; | ||
text = batterySettings.threshold2.rawValue.toString(); | ||
} | ||
} | ||
} | ||
|
||
QGCColoredImage { | ||
source: "/qmlimages/BatteryOrange.svg" | ||
height: ScreenTools.defaultFontPixelHeight * 5 | ||
width: ScreenTools.defaultFontPixelWidth * 7 | ||
fillMode: Image.PreserveAspectFit | ||
color: qgcPal.colorOrange | ||
} | ||
|
||
QGCLabel { | ||
Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 2.5 | ||
text: qsTr("Low") | ||
Layout.leftMargin: -13 | ||
} | ||
|
||
QGCColoredImage { | ||
source: "/qmlimages/BatteryCritical.svg" | ||
height: ScreenTools.defaultFontPixelHeight * 5 | ||
width: ScreenTools.defaultFontPixelWidth * 7 | ||
fillMode: Image.PreserveAspectFit | ||
color: qgcPal.colorRed | ||
} | ||
|
||
QGCLabel { | ||
Layout.preferredWidth: ScreenTools.defaultFontPixelWidth * 3.5 | ||
text: qsTr("Critical") | ||
Layout.leftMargin: -13 | ||
} | ||
|
||
} | ||
|
||
|
||
|
||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this coloring still work given the fact that the svg's are already colored as opposed to white? All the other icons which are colored start out as white and then have the color applied. Did you change the palette to verify that the correct colors show up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you verify this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I verified that the coloring works properly, even though the SVG icons are already colored. The icons display correctly in both Light and Dark themes. I also tested the color application from the palette, and the correct colors show up as expected in both themes without any issues.
Light.mp4
Dark.mp4