diff --git a/src/ev_calculator.py b/src/ev_calculator.py index ebd126a..2c79627 100644 --- a/src/ev_calculator.py +++ b/src/ev_calculator.py @@ -18,15 +18,84 @@ K = 12.5 class EVCalculator: + DEFAULT_ISO_SPEED = 100 + + APERTURE_VALUES = { + 1/32: "1/32", + 1/22: "1/22", + 1/16: "1/16", + 1/11: "1/11", + 1/8: "1/8", + 1/5.6: "1/5.6", + 1/4: "1/4", + 1/2.8: "1/2.8", + 1/2: "1/2", + 1/1.4: "1/1.4" + } + + SHUTTER_SPEED_VALUES = { + 1/4000: "1/4000", + 1/2000: "1/2000", + 1/1000: "1/1000", + 1/500: "1/500", + 1/250: "1/250", + 1/125: "1/125", + 1/60: "1/60", + 1/30: "1/30", + 1/15: "1/15", + 1/8: "1/8", + 1/4: "1/4", + 1/2: "1/2", + 1: "1", + 2: "2", + 4: "4", + 8: "8", + 15: "15", + 30: "30" + } + def luxToEV(lux: float) -> float: # Wikipedia (https://en.wikipedia.org/wiki/Light_meter#Exposure_equations) # says E = 2.5 * (2^EV), so the inverse is EV = ln(2*E/5)/ln(2) return log(2*lux/5, 2) def calcShutterSpeed(isoSpeed: int, lux: float, aperture: float): - return (aperture*aperture*K)/(lux*isoSpeed) + result = (aperture*aperture*K)/(lux*isoSpeed) + print("aperture: {}, K: {}, lux: {}, isoSpeed: {}, result: {}".format(aperture, K, lux, isoSpeed, result)) + return result def calcAperture(isoSpeed: int, lux: float, shutterSpeed: float): # shutterSpeed is in seconds return sqrt(lux*isoSpeed*shutterSpeed/K) + + def toNearestStr(valueToRound: float, roundingValues: dict[float,str]) -> [str, bool]: + # Rounds to the nearest value in the provided ORDERED dict. + # The dict is expected to have a float value as key and the corresponding human readable string value as value + # Returns the string value and a boolean set to true if the value was in the list range. + + roundingNumericValues = list(roundingValues.keys()) + roundingStringValues = list(roundingValues.values()) + + first = roundingNumericValues[0] + last = roundingNumericValues[-1] + + if valueToRound < first / 1.5: + # More than half stop below minimum value! + return [roundingStringValues[0], False] + if valueToRound > last * 1.5: + # More than half stop above maximum value! + return [roundingStringValues[-1], False] + + # Note: range(roundingValues - 1) to exclude last element + for i in range(len(roundingNumericValues) - 1): + value = float(roundingNumericValues[i]) + nextValue = float(roundingNumericValues[i + 1]) + limit = (value + nextValue) / 2 + if valueToRound <= limit: + return [roundingStringValues[i], True] + return [roundingStringValues[-1], True] + + + + diff --git a/src/sensors_polling_timer.py b/src/sensors_polling_timer.py index cb44fb3..a971930 100644 --- a/src/sensors_polling_timer.py +++ b/src/sensors_polling_timer.py @@ -1,6 +1,7 @@ from gi.repository import Gio, GLib from threading import Timer from enum import Enum +import traceback # window.py # @@ -46,6 +47,7 @@ class SensorsPollingTimer(Timer): self.function(value, unit) # Invoke callback except Exception as e: + print(traceback.format_exc(e)) if not self.onError: print("SensorsPollingTimer: error occurred, but no onError callback defined") return diff --git a/src/style.css b/src/style.css index 834eb1c..ffd44b5 100644 --- a/src/style.css +++ b/src/style.css @@ -1,5 +1,5 @@ label.lumos-big-result { - font-size: 80px; + font-size: 60px; font-weight: 800; } diff --git a/src/widgets/aperture_priority_page.py b/src/widgets/aperture_priority_page.py index 682d093..74297f9 100644 --- a/src/widgets/aperture_priority_page.py +++ b/src/widgets/aperture_priority_page.py @@ -26,25 +26,15 @@ class AperturePriorityPage(Gtk.Box): __gtype_name__ = 'AperturePriorityPage' # Values of aperture dropdown entries defined in the .ui file - __aperture_priority_speed_dropdown_values = [ - 1/32, - 1/22, - 1/16, - 1/11, - 1/8, - 1/5.6, - 1/4, - 1/2.8, - 1/2, - 1/1.4 - ] + # TODO: Load dropdown strings from APERTURE_VALUES.values() + __aperture_priority_speed_dropdown_values = list(EVCalculator.APERTURE_VALUES.keys()) # Widgets aperture_priority_aperture_dropdown = Gtk.Template.Child() aperture_priority_time_label = Gtk.Template.Child() __sensorValue = None - __isoSpeed = 100 + __isoSpeed = EVCalculator.DEFAULT_ISO_SPEED def onValuesChanged(self, isoSpeed: int, sensorValue: float, sensorUnit: str): # Check the unit is absolute ("lux") @@ -64,9 +54,16 @@ class AperturePriorityPage(Gtk.Box): def updateView(self): apertureValue = self.__aperture_priority_speed_dropdown_values[self.aperture_priority_aperture_dropdown.get_selected()] shutterSpeed = EVCalculator.calcShutterSpeed(self.__isoSpeed, self.__sensorValue, apertureValue) - # TODO: Round shutter speed value to nearest existing value and set label color to red if outside 1 stop range - self.aperture_priority_time_label.set_label("1/ {:.5f}".format(shutterSpeed)) + + # Round shutter speed value to nearest existing value and set label color to red if outside 1 stop range + [nearestValue, isInsideRange] = EVCalculator.toNearestStr(shutterSpeed, EVCalculator.SHUTTER_SPEED_VALUES) + + if isInsideRange: + self.aperture_priority_time_label.set_label(nearestValue) + else: + self.aperture_priority_time_label.set_label("{}".format(nearestValue)) @Gtk.Template.Callback() def onApertureChanged(self, dropDown: Gtk.DropDown, _: any): self.updateView() + diff --git a/src/widgets/aperture_priority_page.ui b/src/widgets/aperture_priority_page.ui index af56d19..516dc92 100644 --- a/src/widgets/aperture_priority_page.ui +++ b/src/widgets/aperture_priority_page.ui @@ -30,6 +30,7 @@ --s + true diff --git a/src/widgets/time_priority_page.py b/src/widgets/time_priority_page.py index cb033c1..321aaa6 100644 --- a/src/widgets/time_priority_page.py +++ b/src/widgets/time_priority_page.py @@ -52,7 +52,7 @@ class TimePriorityPage(Gtk.Box): time_priority_aperture_label = Gtk.Template.Child() __sensorValue = None - __isoSpeed = 100 + __isoSpeed = EVCalculator.DEFAULT_ISO_SPEED def onValuesChanged(self, isoSpeed: int, sensorValue: float, sensorUnit: str): # Check the unit is absolute ("lux") @@ -71,8 +71,13 @@ class TimePriorityPage(Gtk.Box): def updateView(self): shutterSpeed = self.__time_priority_speed_dropdown_values[self.time_priority_speed_dropdown.get_selected()] apertureValue = EVCalculator.calcAperture(self.__isoSpeed, self.__sensorValue, shutterSpeed) - # TODO: Round aperture value to nearest existing value and set label color to red if outside 1 stop range - self.time_priority_aperture_label.set_label("f/ {:.2f}".format(apertureValue)) + + # Round aperture value to nearest existing value and set label color to red if outside range + [nearestValue, isInsideRange] = EVCalculator.toNearestStr(shutterSpeed, EVCalculator.APERTURE_VALUES) + if isInsideRange: + self.time_priority_aperture_label.set_label(nearestValue) + else: + self.time_priority_aperture_label.set_label("{}".format(nearestValue)) @Gtk.Template.Callback() def onShutterSpeedChanged(self, dropDown: Gtk.DropDown, _: any): diff --git a/src/widgets/time_priority_page.ui b/src/widgets/time_priority_page.ui index f4fcfd1..5521624 100644 --- a/src/widgets/time_priority_page.ui +++ b/src/widgets/time_priority_page.ui @@ -30,6 +30,7 @@ f/-- + true diff --git a/src/window.py b/src/window.py index acb3ca6..7cc3e33 100644 --- a/src/window.py +++ b/src/window.py @@ -69,7 +69,6 @@ class LumosWindow(Adw.ApplicationWindow): self.sensor_unit_error_banner.set_revealed(True) def onError(self, e: Exception): - print(e) self.lastError = e self.error_banner.set_revealed(True)