1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
#------------------------------------------------------------------------------
# Copyright (c) 2013-2025, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
#------------------------------------------------------------------------------
from atom.api import Typed, ForwardTyped, Property, Bool, Int, set_default
from enaml.core.declarative import d_, observe
from .control import Control, ProxyControl
class ProxyProgressBar(ProxyControl):
""" The abstract definition of a proxy ProgressBar object.
"""
#: A reference to the ProgressBar declaration.
declaration = ForwardTyped(lambda: ProgressBar)
def set_minimum(self, minimum):
raise NotImplementedError
def set_maximum(self, maximum):
raise NotImplementedError
def set_value(self, value):
raise NotImplementedError
def set_text_visible(self, visible):
raise NotImplementedError
class ProgressBar(Control):
""" A control which displays a value as a ticking progress bar.
"""
#: The minimum progress value. If the minimum value is changed such
#: that it becomes greater than the current value or the maximum
#: value, then those values will be adjusted. The default is 0.
minimum = d_(Int(0))
#: The maximum progress value. If the maximum value is changed such
#: that it becomes smaller than the current value or the minimum
#: value, then those values will be adjusted. The default is 100.
maximum = d_(Int(100))
#: The position value of the Slider. The value will be clipped to
#: always fall between the minimum and maximum.
value = d_(Int(0))
#: A read only cached property which computes the integer percentage.
percentage = d_(Property(cached=True), writable=False)
#: Whether or not to display progress percentage on the control.
#: This may not be supported by all toolkits and platforms.
text_visible = d_(Bool(False))
#: How strongly a component hugs it's content. ProgressBars expand
#: to fill the available horizontal space by default.
hug_width = set_default('ignore')
#: A reference to the ProxyProgressBar object.
proxy = Typed(ProxyProgressBar)
@percentage.getter
def get_percentage(self):
""" The getter function for the read only percentage property.
"""
minimum = self.minimum
maximum = self.maximum
value = self.value
dy = maximum - minimum
if dy == 0:
res = 0
elif value == maximum:
res = 100
else:
dx = float(value - minimum)
res = int(round(100.0 * dx / dy))
# We already excluded the case where the value was exactly
# the maximum, so we can't really be at 100%, so round this
# down to 99% if necessary.
res = min(res, 99)
return res
#--------------------------------------------------------------------------
# Observers
#--------------------------------------------------------------------------
@observe('minimum', 'maximum', 'value', 'text_visible')
def _update_proxy(self, change):
""" An observer which sends state change to the proxy.
This observer also resets the 'percentage' property.
"""
# The superclass handler implementation is sufficient.
super(ProgressBar, self)._update_proxy(change)
@observe('minimum', 'maximum', 'value')
def _reset_percentage(self, change):
""" An observer which resets the percentage property.
"""
if change['type'] == 'update':
self.get_member('percentage').reset(self)
#--------------------------------------------------------------------------
# PostSetAttr Handlers
#--------------------------------------------------------------------------
def _post_setattr_minimum(self, old, new):
""" Post setattr the minimum value for the progress bar.
If the new minimum is greater than the current value or maximum,
those values are adjusted up.
"""
if new > self.maximum:
self.maximum = new
if new > self.value:
self.value = new
def _post_setattr_maximum(self, old, new):
""" Post setattr the maximum value for the progress bar.
If the new maximum is less than the current value or the minimum,
those values are adjusted down.
"""
if new < self.minimum:
self.minimum = new
if new < self.value:
self.value = new
#--------------------------------------------------------------------------
# PostValidate Handlers
#--------------------------------------------------------------------------
def _post_validate_value(self, old, new):
""" Post validate the value for the progress bar.
The value is clipped to minimum and maximum bounds.
"""
return max(self.minimum, min(new, self.maximum))
|