From e42efd8be7c8f7e1fa519c4aec163dd6958a0434 Mon Sep 17 00:00:00 2001 From: Duncan Elliot <42836473+dmelliot@users.noreply.github.com> Date: Mon, 3 Dec 2018 22:34:45 +1100 Subject: [PATCH] Glyph based representation of numeric values (#674) * Add make_glyph function to core utils A new function (in line with similar functions such as make_bar), make_glyph allows generating a glyph based representation of a numeric value. An example use case would be to use a set of battery level glyphs from FontAwesome to represent battery charge percentage. * Update battery module to use make_glyph function Minor update to battery module to allow use of make_glyph function. Default glyphs do not provide anything fancy, but allow a hook point for using more interesting glyphs from fonts with battery icons. --- i3pystatus/battery.py | 6 +++++- i3pystatus/core/util.py | 47 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/i3pystatus/battery.py b/i3pystatus/battery.py index e812e76..74374c5 100644 --- a/i3pystatus/battery.py +++ b/i3pystatus/battery.py @@ -5,7 +5,7 @@ import re from i3pystatus import IntervalModule, formatp from i3pystatus.core.command import run_through_shell from i3pystatus.core.desktop import DesktopNotification -from i3pystatus.core.util import lchop, TimeWrapper, make_bar +from i3pystatus.core.util import lchop, TimeWrapper, make_bar, make_glyph class UEventParser(configparser.ConfigParser): @@ -141,6 +141,7 @@ class BatteryChecker(IntervalModule): * `{battery_ident}` — the same as the setting * `{bar}` —bar displaying the relative percentage graphically * `{bar_design}` —bar displaying the absolute percentage graphically + * `{glyph}` — A single character or string (selected from 'glyphs') representing the current battery percentage This module supports the :ref:`formatp ` extended string format syntax. By setting the ``FULL`` status to an empty string, and including @@ -195,6 +196,7 @@ class BatteryChecker(IntervalModule): ("not_present_text", "The text to display when the battery is not present. Provides {battery_ident} as formatting option"), ("no_text_full", "Don't display text when battery is full - 100%"), + ("glyphs", "Arbitrarily long string of characters (or array of strings) to represent battery charge percentage"), ) battery_ident = "ALL" @@ -220,6 +222,7 @@ class BatteryChecker(IntervalModule): critical_color = "#ff0000" not_present_color = "#ffffff" no_text_full = False + glyphs = "▁▂▃▄▅▆▇█" battery_prefix = 'BAT' base_path = '/sys/class/power_supply' @@ -318,6 +321,7 @@ class BatteryChecker(IntervalModule): "percentage_design": self.percentage(batteries, design=True), "consumption": self.consumption(batteries), "remaining": TimeWrapper(0, "%E%h:%M"), + "glyph": make_glyph(self.percentage(batteries), self.glyphs), "bar": make_bar(self.percentage(batteries)), "bar_design": make_bar(self.percentage(batteries, design=True)), } diff --git a/i3pystatus/core/util.py b/i3pystatus/core/util.py index 8e7c698..5d9bd71 100644 --- a/i3pystatus/core/util.py +++ b/i3pystatus/core/util.py @@ -523,6 +523,53 @@ def make_bar(percentage): return result +def make_glyph(number, glyphs="▁▂▃▄▅▆▇█", lower_bound=0, upper_bound=100, enable_boundary_glyphs=False): + """ + Returns a single glyph from the list of glyphs provided relative to where + the number is in the range (by default a percentage value is expected). + + This can be used to create an icon based representation of a value with an + arbitrary number of glyphs (e.g. 4 different battery status glyphs for + battery percentage level). + + :param number: The number being represented. By default a percentage value\ + between 0 and 100 (but any range can be defined with lower_bound and\ + upper_bound). + :param glyphs: Either a string of glyphs, or an array of strings. Using an array\ + of strings allows for additional pango formatting to be applied such that\ + different colors could be shown for each glyph). + :param lower_bound: A custom lower bound value for the range. + :param upper_bound: A custom upper bound value for the range. + :param enable_boundary_glyphs: Whether the first and last glyphs should be used\ + for the special case of the number being <= lower_bound or >= upper_bound\ + respectively. + :returns: The glyph found to represent the number + """ + + # Handle edge cases first + if lower_bound >= upper_bound: + raise Exception("Invalid upper/lower bounds") + elif number <= lower_bound: + return glyphs[0] + elif number >= upper_bound: + return glyphs[-1] + + if enable_boundary_glyphs: + # Trim first and last items from glyphs as boundary conditions already + # handled + glyphs = glyphs[1:-1] + + # Determine a value 0 - 1 that represents the position in the range + adjusted_value = (number - lower_bound) / (upper_bound - lower_bound) + + # Determine the closest glyph to show + # As we have positive indices, we can use int for floor rounding + # Adjusted_value should always be < 1 + glyph_index = int(len(glyphs) * adjusted_value) + + return glyphs[glyph_index] + + def user_open(url_or_command): """Open the specified paramater in the web browser if a URL is detected, othewrise pass the paramater to the shell as a subprocess. This function