-
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
Conversation
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.
I like it very much. Gives a nice fresh touch and it's more informative.
One thing, are shades of each colors same / according to existing palette?
At recording they look a bit like from shifted shades palette, not similar to what we have now.
Thank you for the feedback! To maintain consistency with the existing palette, I used the following predefined colors from QGCPalette:
I’ve now updated the code to use Light: Dark: |
@gillamkid FYI |
@Paschalis dark mode is great. But in light mode, those yellow, green and orange are hard to read. What about black border? Or something else? We are very close 😊 Can you experiment with something that will allow icons to be visible on white background, in full sun? Remember that often people use QGC in the field 😅 |
Hi @zdanek , Thanks for the feedback! Using darker colors will improve readability and contrast better than adding a border. Since the other indicators don’t have borders, adding one only to the battery indicator could disrupt visual consistency. Darker colors will maintain design uniformity and enhance visibility in bright conditions. Light.webm |
In general coloring text like this is a bad idea. I just makes it too hard to read in direct sunlight on things like a Herelink or tablet controller. The icon coloring is great. But I'd leave the text color alone. That is optimized for sunlight readability. |
My other concern is the 80/60/40/20 coloring breaks. I seem to remember QGC having a talking battery warning ages ago with breaks like this and it caused concern. Can't remember if that's still in the code base. I would run that by folks on Discord. I'm guessing the first request will be to be able to make those configurable since different batteries discharge at differing rates. Also I'm guessing there will be questions about how thee values relate to the ArduPilot multi-level warning parameters thingies for battery. Don't get my wrong, I Iike it. It can just be tough to make most folks happy given the variability of vehicle platforms. |
Hi @DonLakeFlyer, Regarding your concerns about the battery indicator colors: The current master branch of QGroundControl already uses colors like orange and red for the most critical battery states ( My question is: given that the most critical states already use highly visible colors, why might the upper percentage thresholds be a concern in terms of visibility or readability? I believe that these additional thresholds help in providing detailed battery information without compromising the visibility of the more critical states. The default case in the update still uses qgcPal.text for undefined states, similar to the current implementation. I completely agree with your perspective. Your approach is very reasonable, and I see the value in making the battery level thresholds configurable. Allowing users to adjust these thresholds based on their specific battery discharge rates and preferences will definitely enhance flexibility. For example, users could change the default thresholds from 80/60/40/20 to more tailored values like 75/55/35/15 according to their needs. Thanks for your valuable input! |
Regarding thresholds, I also immediately thought about users' preferences since, people have their own needs and batteries can be non linear in discharge, so one might want to have own levels to be aware of. |
Light.webmDark.webmI'll proceed with implementing the changes to make the battery level thresholds configurable. |
They are only a concern with visibility/readability on the text. The text should not be colored, the icons are fine.
As it currently stands QGC shows:
With this new pull the battery display for orange color is hardcoded to the 21%-40% remaining battery range for all vehicles and all batteries on the vehicle. And then red coloring is hardcoded to 20% and below. There is no distinction between Low and Critical states. The hardcoded 20% red trigger sort of relates to mavlink low state. But as you can see in the P4 example, by default it does not match PX4's concept of low battery. It also does not track the vehicles concept of low battery which is configurable. Although the concept of more nuanced coloring of battery state is good thing the fact that it does not respect what the vehicle considers to be low and critical states is a pretty bad thing. In order to make this work correctly there needs to be a combination of the two approaches. The telemetry controls the state from MAV_BATTERY_CHARGE_STATE_LOW and worse and the orange to red band of coloring. And then you have a nuanced coloring when battery state is reported as MAV_BATTERY_CHARGE_STATE_OK. The problem is that means you need to know what the percentage is when the transition is made from MAV_BATTERY_CHARGE_STATE_OK to MAV_BATTERY_CHARGE_STATE_LOW. This would require firmware specific methods in FirmwarePlugin which could report back the percentage associated with the MAV_BATTERY_CHARGE_STATE_LOW transition such that the code can be written correctly. The problem with implementing something like that is that I don't think given the current state of affairs with mavlink and firmware implementations that is possible in all cases. In looking at the parameters in PX4 and ArduPilot it looks like it would be possible for PX4 since the parameters for controlling this are represented as percentages. But for ArduPilot the parameters which control low battery are represented in either milli-amps or voltages, not percentages. Maybe someone familiar with ArduPilot can chime in with some other way to do it? So it's doable for PX4 but not for ArduPilot. Which then means it would need to be controlled by a supported bit in FirmwarePlugin. We do that for other QGC features which can only be supported by one firmware. So it's not out of the ordinary. TLDR summary - Can be done correctly for PX4, but not currently (as far as I can see) for ArduPilot. |
I second what Don said on the last answer. For Ardupilot we really would want to get the low and critical values from parameters, and maybe have one additional medium point which could be configurable. But leaving it hard coded or configurable in so many levels is going to be confusing for Ardupilot users, so I would leave this particular to PX4 for the moment, if PX4 friends are fine with it. I think it would go as creating some new q_properties and getters in firmware plugin and overriding in PX4 firmware plugin, or alternatively creating a whole toolbar indicator particular to PX4 and another for Ardupilot, and move battery indicator from tool indicator to vehicle indicators group ( so we can specify the qml from each firmware plugin instead of being common ). Thanks! |
@Davidsastresas You know ArduPilot better than I do. Do you see a way for QGC to know the battery percentage value for low state given the set of parameters available? |
This update enhances the battery indicator with the following changes:
The following images demonstrate the changes and how users can configure the thresholds, along with GIFs showcasing the battery indicator in both light and dark themes: Dark.webmLight.webm |
Ok, this is getting much, much better. Thanks. Comments:
|
Current Default Master Version: Image and Text Coloring for Both Light and Dark Themes
Our new Version retains the above approach !
Appreciate your feedback and support !
The current behavior in the master branch actually changes both the image and text color based on the battery state. My update retains this approach !
The values aren't hardcoded; I'm following the default approach by using MAVLink.MAV_BATTERY_CHARGE_STATE_LOW for orange and MAVLink.MAV_BATTERY_CHARGE_STATE_CRITICAL (and others) for red. The color changes are tied to these MAVLink states rather than specific percentages. However, I can update the display to show
instead of percentage values for clarity !
I completely understand and agree with the concept you described for light and dark themes, which is why I've kept the light theme the same as in the current master version—using Black, Orange, and Red for both the image and text, as these colors work well in outdoor, direct sunlight conditions. Since no one has raised any issues with the current coloring in the light theme, I've decided to keep it as is for now. |
Also can you add a note in ChangeLog.md about this new feature? |
Love it. This is fantastic stuff. I'll do a full code review soon. |
Sure! In order to know the low and critical values for voltage we have: and in order to know the low and critical values for current we have: and to understand the total capacity of the battery we have: Please note we have a BATTX set of parameters for each battery monitor configured, so all the above parameters will exist for each instance of battery monitor configured. Considering the above, the logic would go as taking BATT_CAPACITY as 100% battery, and then understand the percentages for Low and Critical from BATT_LOW_MAH and BATT_CRT_MAH. I don't mind to work on this part for AP, but it would be good to leave it prepared so the widget takes this info from FirmwarePlugin. @Paschalis that work looks very nice so far, thanks! However, it would be good if you could do a rebase -i, and arrange the commits so we don't have those "merge into master" commits. Whenever you want to rebase, if you do a git rebase upstream/master instead of git merge, your commits will organize on top of upstream/master, instead of having that odd "merge into master" commit. It makes much easier to track commits in a PR. Thanks! |
- Added new SVG images for different battery levels: Critical, Low, Orange, Yellow, YellowGreen, and Green. - Updated QGCPalette.cc and QGCPalette.h to include new color definitions for the battery levels. - Modified BatteryIndicator.qml to use the new SVG images and color codes. - Updated qgcimages.qrc to include the new SVG images in the resources.
…eryIndicator to use predefined palette colors
…yConf.svg, BatteryConfLight.svg).
@@ -124,7 +152,7 @@ Item { | |||
anchors.bottom: parent.bottom | |||
width: height | |||
sourceSize.width: width | |||
source: "/qmlimages/Battery.svg" | |||
source: getBatterySvgSource() | |||
fillMode: Image.PreserveAspectFit | |||
color: getBatteryColor() |
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
src/UI/toolbar/BatteryIndicator.qml
Outdated
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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve implemented the validation fully on the C++ side in BatteryIndicatorSettings.cc
. Now, in the QML, we simply use:
onEditingFinished: {
batterySettings.setThreshold2(parseInt(text));
}
src/UI/toolbar/BatteryIndicator.qml
Outdated
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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
I've implemented the final level of validation in the BatteryIndicatorSettings.cc
. For threshold1
, I ensure that the value is always at least 16 and no more than 99. If the provided value is below 16, it gets adjusted to 17. If it exceeds 99, it's capped at 99. Additionally, if the new value is less than or equal to threshold2
, it automatically gets set to one more than threshold2
to maintain the required order. For threshold2
, I enforce a minimum value of 16. If the user attempts to set it to 15 or less, it gets adjusted up to 16. Moreover, if the new value is greater than or equal to threshold1
, it is set to one less than threshold1
to ensure it remains less.
src/UI/toolbar/BatteryIndicator.qml
Outdated
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 comment
The 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:
- Each battery icon plus either fixed percentage or text field should be in its own RowLayout. With the spacing on the layout set to something like font width times 1 or 2 depending on how it looks.
- Then there is a top level RowLayout which has all these RowLayouts as children. And then there is a font based spacing on that to space out the battery+pct visuals.
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.
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 RowLayout
. I've also set the spacing based on the current font width, ensuring that the UI scales properly with font size changes. The top-level RowLayout
contains all these individual layouts with appropriate font-based spacing.
src/UI/toolbar/BatteryIndicator.qml
Outdated
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 comment
The reason will be displayed to describe this comment to others. Learn more.
The visibility of this group should be based on batterySettings.visible
. This allows custom builds to hide this section if they want to.
Also each individual settings has a visible
property. If not visible then the editing field would normally be completely hidden. But in this caseI would show just a label with the percentage instead of a configurable text field.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
I’ve implemented the visibility controls as you suggested, using visible: batterySettings.visible
for the entire group and bool thresholdVisible: batterySettings.thresholdEditable
for individual settings.
In the BatteryIndicatorSettings
class, I’ve added QSettings to manage visibility and editability, defaulting to true
if no value is set:
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 comment
The reason will be displayed to describe this comment to others. Learn more.
In the current setup, if the thresholdVisible
property is false, the FactTextField
for threshold1
and threshold2
will be hidden, and a QGCLabel
will display the current percentages. This ensures that users can still see the battery thresholds without the editing fields when they're not meant to be configurable.
If the thresholdVisible
property is true, the FactTextField
for both threshold1
and threshold2
will be visible, allowing users to edit the thresholds directly.
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.
However, I’m unsure how to properly configure these two settings to effectively allow custom builds to hide this section
there is no extra work needed. SettingsGroup and SettingsFact base classes already support this automatically.
Ok, so then with what @Davidsastresas explains we could plumb FirmwarePlugin to tell us what the battery percentage is for both the Low and Critical states. This would allow us to do the following things:
I think this would be nice addition to this work, but I would deal with it in a separate pull after this goes through. |
Also after writing up my last comment which include talking about threshold percentage validation it go me thinking about the fact that threshold validation is being done in ui code. In reality this is incorrect. Since these settings can be changed from the C++ side of things as well. These sort of things happen with custom builds. The better way to do it would be to use the SettingsGroup and FactMetaData systems to do the validation fully on the C++ side. @Paschalis This isn't that hard, but requires knowledge of both those systems. If you want to do it then I can explain how. If not (since you've already put a ton of effort into this) I can do this myself after this gets merged in with the way it is now. |
DEFINE_SETTINGFACT(threshold1) | ||
DEFINE_SETTINGFACT(threshold2) | ||
|
||
Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged) |
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.
So all f this is incorrect with respect to how settings groups.facts work:
- There is no need for adding a visible property. It already exists on both the group and on each setting. You can access them in Qml using
QGroundControl.settingsManager.batteryIndicatorSettings.visible
for visibility which should control whether to show the battery indicator panel. And thenQGroundControl.settingsManager.batteryIndicatorSettings.threshold1.visible
for the thresholds. - To implement validation on the C++ side you need to implement you own settings fact creation using
DECLARE_SETTINGSFACT_NO_FUNC
. Look at AppSettings.cc for examples. Then in that code you connect to the rawValueChanged signal. And in you signal handler that is where you do the validation.
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.
I streamlined the visibility management by utilizing existing properties in QGroundControl.settingsManager.batteryIndicatorSettings and removed redundant properties. Additionally, I implemented validation for threshold settings using DECLARE_SETTINGSFACT_NO_FUNC
and confirmed the correct storage of new threshold values after verifying defaults from the JSON file.
Thanks!
- Modified BatteryIndicator.SettingsGroup.json to adjust default values for thresholds and visibility. - Updated BatteryIndicatorSettings.cc and BatteryIndicatorSettings.h to include validation logic and visibility management for threshold settings. - Updated BatteryIndicator.qml to dynamically toggle between FactTextField and QGCLabel based on visibility settings.
Sorry for falling off the face of the earth on this. I was out of town. This all looks great. I reviewed the code and it looks correct. I'm going to double-check it after it's merged in just to be sure in a lot more detail. |
@Paschalis And thanks again for this works. It's a great new feature. |
The following GIFs demonstrate the changes:
Before:
After:
Or you can click on the videos below to see the changes:
Before: before.webm
After: after.webm