#!/usr/bin/env python
# -*- coding: utf-8 -*-
# It script it publish under GNU GENERAL PUBLIC LICENSE
# http://www.gnu.org/licenses/gpl-3.0.en.html
# Author: the Galaxie Curses Team, all rights reserved
import GLXCurses
# Reference Document: https://developer.gnome.org/gtk3/stable/GtkAdjustment.html
[docs]class Adjustment(GLXCurses.Object):
"""
A representation of an adjustable bounded value
"""
def __init__(self):
"""
**Properties**
.. py:attribute:: lower
The minimum value of the adjustment.
:Type: float
:Flags: Read / Write
:Default value: 0.0
.. py:attribute:: page_increment
The page increment of the adjustment.
:Type: float
:Flags: Read / Write
:Default value: 0.0
.. py:attribute:: page_size
The page size of the adjustment. Note that the page-size is irrelevant and should be set to zero if the
adjustment is used for a simple scalar value, e.g. in a
:class:`SpinButton <GLXCurses.SpinButton.SpinButton>`.
:Type: float
:Flags: Read / Write
:Default value: 0.0
.. py:attribute:: step_increment
The step increment of the adjustment.
:Type: float
:Flags: Read / Write
:Default value: 0.0
.. py:attribute:: minimum_increment
The smaller of step increment and page increment.
:Type: float
:Flags: Read / Write
:Default value: 0.0
.. py:attribute:: upper
The maximum value of the adjustment.
:Type: float
:Flags: Read / Write
:Default value: 0.0
.. note:: The values will be restricted by ``upper - page-size`` if the page-size property is nonzero.
.. py:attribute:: value
The value of the adjustment.
:Type: float
:Flags: Read / Write
:Default value: 0.0
**Description**
The :class:`Adjustment <GLXCurses.Adjustment.Adjustment>` object represents a value which has an associated
lower and upper bound, together with step and page increments,and a page size.It is used within several widgets,
including :class:`SpinButton <GLXCurses.SpinButton.SpinButton>`,
:class:`Viewport <GLXCurses.Viewport.Viewport>`,
and :class:`Range <GLXCurses.Range.Range>` (which is a base class for
:class:`Scrollbar <GLXCurses.Scrollbar.Scrollbar>` and :class:`Scale <GLXCurses.Scale.Scale>`).
The Adjustment object does not update the value itself.
Instead it is left up to the owner of the :class:`Adjustment <GLXCurses.Adjustment.Adjustment>`
to control the value.
**Functions**
"""
# Load heritage
GLXCurses.Object.__init__(self)
# It's a GLXCurse Type
self.glxc_type = "GLXCurses.Adjustment"
# Unique ID it permit to individually identify a widget by example for get_focus get_default
self.id = GLXCurses.new_id()
# Widgets can be named, which allows you to refer to them from a GLXCStyle
self.name = "{0}{1}".format(self.__class__.__name__, self.id)
self.lower = float(0.0)
self.page_increment = float(0.0)
self.page_size = float(0.0)
self.step_increment = float(0.0)
self.minimum_increment = float(0.0)
self.upper = float(0.0)
self.value = float(0.0)
self.two = None
self.average = None
[docs] def new(
self,
value=float(0.0),
lower=float(0.0),
upper=float(0.0),
step_increment=float(0.0),
page_increment=float(0.0),
page_size=float(0.0),
):
"""
Creates a new :func:`GLXCurses.Adjustment <GLXCurses.Adjustment.Adjustment>`.
:param value: The initial value
:param lower: The minimum value
:param upper: The maximum value
:param step_increment: The step increment
:param page_increment: The page increment
:param page_size: The page size
:type value: float
:type lower: float
:type upper: float
:type step_increment: float
:type page_increment: float
:type page_size: float
:return: a new :func:`GLXCurses.Adjustment <GLXCurses.Adjustment.Adjustment>`
:rtype: :func:`GLXCurses.Adjustment <GLXCurses.Adjustment.Adjustment>`
:raise TypeError: if ``value`` is not float
:raise TypeError: if ``lower`` is not float
:raise TypeError: if ``upper`` is not float
:raise TypeError: if ``step_increment`` is not float
:raise TypeError: if ``page_increment`` is not float
:raise TypeError: if ``page_size`` is not float
"""
# Exit as soon of possible
if type(value) != float:
raise TypeError('"value" must be float type')
if type(lower) != float:
raise TypeError('"lower" must be float type')
if type(upper) != float:
raise TypeError('"upper" must be float type')
if type(step_increment) != float:
raise TypeError('"step_increment" must be float type')
if type(page_increment) != float:
raise TypeError('"page_increment" must be float type')
if type(page_size) != float:
raise TypeError('"page_size" must be float type')
# The big flush, it back to default values
self.__init__()
# After init in case we set the initial value
if value != float(0.0):
self.value = value
if lower != float(0.0):
self.lower = lower
if upper != float(0.0):
self.upper = upper
if step_increment != float(0.0):
self.step_increment = step_increment
if page_increment != float(0.0):
self.page_increment = page_increment
if page_size != float(0.0):
self.page_size = page_size
# Return something , yes baby ...
return self
[docs] def get_value(self):
"""
Gets the current value of the adjustment. See set_value()
:return: A current value Adjustment
:rtype: float
"""
return self.value
[docs] def set_value(self, value):
"""
Set the :class:`Adjustment <GLXCurses.Adjustment.Adjustment>` :py:attr:`value` attribute.
The ``value`` passed as argument is clamped to lie between :py:attr:`lower` and :py:attr:`lower` attributes.
.. note:: For adjustments which are used in a :class:`Scrollbar <GLXCurses.Scrollbar.Scrollbar>`, \
the effective range of allowed values goes from \
:py:attr:`lower` to :py:attr:`upper` - :py:attr:`page_size`.
:raise TypeError: when ``value`` passed as argument is not a :py:__area_data:`float`
"""
if type(value) == float:
# Clamp Value
value = GLXCurses.clamp(
value=value, smallest=self.get_lower(), largest=self.get_upper()
)
if value != self.get_value():
self.value = value
self.emit_value_changed()
else:
raise TypeError('"value" argument must be a float')
[docs] def clamp_page(self, lower=None, upper=None):
"""
Updates the :py:attr:`value` attribute to ensure that the range between ``lower`` and ``upper`` parameters
is in the current page
(i.e. between :py:attr:`value` and :py:attr:`value` + :py:attr:`page_size`).
If the range is larger than the page size, then only the start of it will be in the current page.
A **value-changed** signal will be emitted if the value is changed.
:param lower: the lower value
:param upper: the upper value
:type lower: float
:type upper: float
:raise TypeError: when ``lower`` are not :py:__area_data:`float` type
:raise TypeError: when ``upper`` are not :py:__area_data:`float` type
"""
# Try to not execute the code
if type(upper) != float:
raise TypeError('"upper" must be a float type')
if type(lower) != float:
raise TypeError('"lower" must be a float type')
# https://github.com/GNOME/gtk/blob/master/gtk/gtkadjustment.c line 880
# control
need_emission = False
# Clamp
lower = GLXCurses.clamp(
value=lower, smallest=self.get_lower(), largest=self.get_upper()
)
upper = GLXCurses.clamp(
value=upper, smallest=self.get_lower(), largest=self.get_upper()
)
if self.get_value() + self.get_page_size() < upper:
self.set_value(upper - self.get_page_size())
need_emission = True
if self.get_value() > lower:
self.set_value(lower)
need_emission = True
if need_emission:
self.emit_value_changed()
[docs] def emit_changed(self):
"""
Emits a “changed” signal from the :class:`Adjustment <GLXCurses.Adjustment.Adjustment>`.
This is typically called by the owner of the :class:`Adjustment <GLXCurses.Adjustment.Adjustment>`,
after it has changed any of the :class:`Adjustment <GLXCurses.Adjustment.Adjustment>`
attributes other than the value.
"""
instance = {"class": self.__class__.__name__, "type": "changed", "id": self.id}
# adjustment_signals[VALUE_CHANGED] =
# g_signal_new(I_("value-changed"),
# G_OBJECT_CLASS_TYPE(class ),
# G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
# G_STRUCT_OFFSET (GtkAdjustmentClass, value_changed),
# NULL, NULL,
# NULL,
# G_TYPE_NONE, 0);
# }
# EVENT EMIT
self.emit("SIGNALS", instance)
[docs] def emit_value_changed(self):
"""
Emits a “value-changed” signal from the :class:`Adjustment <GLXCurses.Adjustment.Adjustment>`.
This is typically called by the owner of the Adjustment
after it has changed the “value” property.
"""
instance = {
"class": self.__class__.__name__,
"type": "value-changed",
"id": self.id,
}
# Example from Gtk Source
# instance = [I_("value-changed"),
# G_OBJECT_CLASS_TYPE(class ),
# G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
# G_STRUCT_OFFSET (GtkAdjustmentClass, value_changed),
# NULL, NULL,
# NULL,
# G_TYPE_NONE, 0]
# EVENT EMIT
self.emit("SIGNALS", instance)
[docs] def get_lower(self):
"""
Retrieves the minimum value of the adjustment.
:return: The current minimum value of the adjustment
:rtype: float
"""
return self.lower
[docs] def get_page_increment(self):
"""
Retrieves the page increment of the adjustment.
:return: The current page increment of the adjustment
:rtype: float
"""
return self.page_increment
[docs] def get_page_size(self):
"""
Retrieves the page size of the adjustment.
:return: The current page size of the adjustment
:rtype: float
"""
return self.page_size
[docs] def get_step_increment(self):
"""
Retrieves the step increment of the adjustment.
:return: The current step increment of the adjustment.
:rtype: float
"""
return self.step_increment
[docs] def get_minimum_increment(self):
"""
Get the smaller of step increment and page increment. Note that value is compute, then it have no need of a
set_minimum_increment() method.
:return: the minimum increment of adjustment
:rtype: float
"""
# Source: https://github.com/GNOME/gtk/blob/master/gtk/gtkadjustment.c line 931
if self.get_step_increment() != 0 and self.page_increment != 0:
if abs(self.get_step_increment()) < abs(self.get_page_increment()):
minimum_increment = self.get_step_increment()
else:
minimum_increment = self.get_page_increment()
elif self.get_step_increment() == 0 and self.get_page_increment() == 0:
minimum_increment = 0
elif self.get_step_increment() == 0:
minimum_increment = self.get_page_increment()
else:
minimum_increment = self.get_step_increment()
return minimum_increment
[docs] def get_upper(self):
"""
Retrieves the maximum value of the adjustment.
:return: The current maximum value of the adjustment
:rtype: float
"""
return self.upper
[docs] def set_lower(self, lower):
"""
Sets the minimum value of the adjustment.
When setting multiple adjustment properties via their individual setters, multiple
:func:`Adjustment.changed() <GLXCurses.Adjustment.Adjustment.changed()>` signals will be emitted. However,
since the emission of the :func:`Adjustment.changed() <GLXCurses.Adjustment.Adjustment.changed()>` signal
is tied to the emission of the ``notify`` signals of the changed properties, it’s possible to compress
the :func:`Adjustment.changed() <GLXCurses.Adjustment.Adjustment.changed()>` signals into one by calling
``object_freeze_notify()`` and ``object_thaw_notify()`` around the calls to the individual setters.
Alternatively, using :func:`Adjustment.configure() <GLXCurses.Adjustment.Adjustment.configure()>`
has the same effect of compressing :func:`Adjustment.changed() <GLXCurses.Adjustment.Adjustment.changed()>`
emissions.
.. warning:: Unfortunately ``object_freeze_notify()`` and ``object_thaw_notify()`` don't exist yet. \
then only :func:`Adjustment.configure() <GLXCurses.Adjustment.Adjustment.configure()>` will make the work.
:param lower: the new minimum value
:type lower: float
:raise TypeError: when "lower" argument is not a :py:__area_data:`float`
"""
# Exit as soon of possible
if type(lower) != float:
raise TypeError('"lower" must be a float type')
# Just in case we can do nothing :)
if lower != self.get_lower():
self.lower = lower
[docs] def set_page_increment(self, page_increment):
"""
Sets the page increment of the adjustment.
.. seealso:: :func:`Adjustment.set_lower() <GLXCurses.Adjustment.Adjustment.set_lower()>` about how to \
compress multiple emissions of the :func:`Adjustment.changed() <GLXCurses.Adjustment.Adjustment.changed()>` \
signal when setting multiple adjustment attributes.
:param page_increment: the new page increment
:type page_increment: float
:raise TypeError: when "page_increment" argument is not a :py:__area_data:`float`
"""
# Exit as soon of possible
if type(page_increment) != float:
raise TypeError('"page_increment" must be a float type')
# Just in case we can do nothing :)
if page_increment != self.get_page_increment():
self.page_increment = page_increment
# Emit a changed signal
self.emit_changed()
[docs] def set_page_size(self, page_size):
"""
Sets the page size of the adjustment.
.. seealso:: :func:`Adjustment.set_lower() <GLXCurses.Adjustment.Adjustment.set_lower()>` about how to \
compress multiple emissions of the :func:`Adjustment.changed() <GLXCurses.Adjustment.Adjustment.changed()>` \
signal when setting multiple adjustment attributes.
:param page_size: the new page size
:type page_size: float
:raise TypeError: when "page_size" argument is not a :py:__area_data:`float`
"""
# Exit as soon of possible
if type(page_size) != float:
raise TypeError('"page_size" must be a float type')
# Just in case we can do nothing :)
if page_size != self.get_page_size():
self.page_size = page_size
[docs] def set_step_increment(self, step_increment):
"""
Sets the step increment of the adjustment.
.. seealso:: :func:`Adjustment.set_lower() <GLXCurses.Adjustment.Adjustment.set_lower()>` about how to \
compress multiple emissions of the :func:`Adjustment.changed() <GLXCurses.Adjustment.Adjustment.changed()>` \
signal when setting multiple adjustment attributes.
:param step_increment: the new step increment
:type step_increment: float
:raise TypeError: when "step_increment" argument is not a :py:__area_data:`float`
"""
# Exit as soon of possible
if type(step_increment) != float:
raise TypeError('"step_increment" must be a float type')
# Just in case we can do nothing :)
if step_increment != self.get_step_increment():
self.step_increment = step_increment
[docs] def set_upper(self, upper):
"""
Sets the maximum value of the adjustment.
.. seealso:: :func:`Adjustment.set_lower() <GLXCurses.Adjustment.Adjustment.set_lower()>` about how to \
compress multiple emissions of the :func:`Adjustment.changed() <GLXCurses.Adjustment.Adjustment.changed()>` \
signal when setting multiple adjustment attributes.
:param upper: the new maximum value
:type upper: float
:raise TypeError: when "upper" argument is not a :py:__area_data:`float`
"""
# Exit as soon of possible
if type(upper) != float:
raise TypeError('"upper" must be a float type')
# Check if upper is a float before assign it or raise an error
if upper != self.get_upper():
self.upper = upper