Source code for GLXCurses.Container

#!/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/GtkContainer.html
[docs]class Container(GLXCurses.Widget): """ GLXCurses.Container — Base class for widgets which contain other widgets Description: A GLXCurse user interface is constructed by nesting widgets inside widgets. Container widgets are the inner nodes in the resulting tree of widgets: they contain other widgets. So, for example, you might have a GLXCurse.Window containing a GLXCurse.Frame containing a GLXCurse.Label. If you wanted an image instead of a textual label inside the frame, you might replace the GLXCurse.Label widget with a GLXCurse.Image widget. There are two major kinds of container widgets in GLXCurses. Both are subclasses of the abstract GLXCurse.Container base class. The first type of container widget has a single child widget and derives from GLXCurses.Bin. These containers are decorators, which add some kind of functionality to the child. For example, a GLXCurses.Button makes its child into a clickable button; a GLXCurses.Frame draws a frame around its child and a GLXCurses.Window places its child widget inside a top-level window. The second type of container can have more than one child; its purpose is to manage layout. This means that these containers assign sizes and positions to their children. For example, a GLXCurses.HBox arranges its children in a horizontal row, and a GLXCurses.Grid arranges the widgets it contains in a two-dimensional grid. For implementations of GLXCurses.Container the virtual method GLXCurses.Container.forall() is always required, since it's used for drawing and other internal operations on the children. If the GLXCurses.Container implementation expect to have non internal children it's needed to implement both GLXCurses.Container.add() and GLXCurses.Container.remove(). If the GLXCurses.Container implementation has internal children, they should be added widget.set_parent() on __init__() and removed with widget.unparent() in the GLXCurses.Widget.destroy() implementation. See more about implementing custom widgets at https://wiki.gnome.org/HowDoI/CustomWidgets """ def __init__(self): GLXCurses.Widget.__init__(self) # It's a GLXCurse Type self.glxc_type = "GLXCurses.Container" self.name = "{0}{1}".format(self.__class__.__name__, self.id) # Properties self.__child = None self.__border_width = None self.__resize_mode = None self.child = None self.border_width = None self.resize_mode = None # Internal Properties # The child widget that has the focus self.focus_child = None # If True the container needs resizing self.need_resize = False # if True redraw the container when a child gets reallocated self.reallocate_redraws = True # If True the container had its focus chain explicitly set self.has_focus_chain = False # Internal self._focus_vadjustment = None self._focus_hadjustment = None @property def border_width(self): """ Set the ``border_width`` property value Allowed values: <= 65535 Default value: 0 :return: The width of the empty border outside the containers children. :rtype: int """ return self.__border_width @border_width.setter def border_width(self, border_width=None): """ Get the ``border_width`` property value Allowed values: <= 65535 Default value: 0 :param border_width: The width of the empty border outside the containers children. :type border_width: int or None """ if border_width is None: border_width = 0 if type(border_width) != int: raise TypeError("'border_width' property value must be a int type or None") if not border_width <= 65535: raise ValueError("'border_width' property value must be <= to 65535") if border_width != self.border_width: self.__border_width = border_width @property def child(self): """ Set the ``child`` property value :return: Child element :rtype: GLXCurses.ChildElement or None """ return self.__child @child.setter def child(self, child=None): """ Set the ``child`` property value :param child: Child element :type child: GLXCurses.ChildElement or None :raise TypeError: when ``child`` property value must be a instance of GLXCurses.ChildElement or None """ if child is not None and not isinstance(child, GLXCurses.ChildElement): raise TypeError( "'child' property value must be a instance of GLXCurses.ChildElement or None" ) if self.child != child: self.__child = child @property def resize_mode(self): """ Set the ``resize_mode`` property value Default value: ``GLXC.RESIZE_PARENT`` :return: Specify how resize events are handled. :rtype: str """ return self.__resize_mode @resize_mode.setter def resize_mode(self, resize_mode=None): """ Get the ``resize_mode`` property value Default value: GLXCurses.GLXC.RESIZE_PARENT :param resize_mode: Specify how resize events are handled. :type resize_mode: str or None :raise TypeError: when 'resize_mode' is not a str type or None :raise ValueError; when 'resize_mode' is not in GLXC.ResizeMode valid list """ if resize_mode is None: resize_mode = GLXCurses.GLXC.RESIZE_PARENT if type(resize_mode) != str: raise TypeError("'resize_mode' must must be a str type or None") if resize_mode not in GLXCurses.GLXC.ResizeMode: raise ValueError("'resize_mode' must a GLXC.ResizeMode") if self.resize_mode != resize_mode: self.__resize_mode = resize_mode
[docs] def add(self, widget=None): """ Adds widget to container . Typically used for simple containers such as Window, Frame, or Button; For more complicated layout containers such as Box or Grid, this function will pick default packing parameters that may not be correct. So consider functions such as :func:`GLXCurses.Box.pack_start() <GLXCurses.Box.Box.pack_start>` and :func:`GLXCurses.Grid.attach() <GLXCurses.Grid.Grid.attach>` as an alternative to :func:`GLXCurses.Container.add() <GLXCurses.Container.Container.add>` in those cases. A widget may be added to only one container at a time; you (should not) place the same widget inside two different containers. :param widget: a widget to be placed inside container :type widget: GLXCurses.Widget :raise TypeError: if ``widget`` is not a instance of GLXCurses.Widget """ # Try to exit as soon of possible if not isinstance(widget, GLXCurses.Widget): raise TypeError("'widget' must be an instance of GLXCurses.Widget") # If we are here everything look ok if bool(self.child): if callable(getattr(self.child.widget, "unparent")): self.child.widget.unparent() # The added widget receive a parent widget.parent = self widget.stdscr = GLXCurses.Application().stdscr self.child = GLXCurses.ChildElement( widget=widget, widget_name=widget.name, widget_type=widget.glxc_type, widget_id=widget.id, widget_properties=GLXCurses.ChildProperty(position=0), ) if hasattr(self.child.widget, 'update_preferred_sizes'): self.child.widget.update_preferred_sizes() self.emit("add", {"widget": self.child.widget, "id": self.child.id})
[docs] def remove(self, widget=None): """ Removes widget from container . Widget must be inside container . Note that container will own a reference to widget , and that this may be the last reference held; so removing a widget from its container can destroy that widget. If you want to use widget again, you need to add a reference to it before removing it from a container, using g_object_ref(). If you don’t want to use widget again it’s usually more efficient to simply destroy it directly using Widget.destroy() since this will remove it from the container and help break any circular reference count cycles. :param widget: a current child of container :type widget: GLXCurses Widget :raise TypeError: if widget is not a instance of GLXCurses.Widget """ # Try to exit as soon of possible if not isinstance(widget, GLXCurses.Widget): raise TypeError("'widget' must be an instance of GLXCurses.Widget") # If we are here everything look ok if self.__class__.__name__ in GLXCurses.GLXC.CHILDREN_CONTAINER: if hasattr(self, "children"): if bool(self.children): count = 0 last_found = None for children in self.children: if widget == children.widget: last_found = count count += 1 if last_found is not None: self.children.pop(last_found) if callable(getattr(widget, "unparent")): widget.unparent() else: if hasattr(self, "child"): if bool(self.child): if self.child.widget == widget: self.child = None if callable(getattr(widget, "unparent")): widget.unparent()
[docs] def add_with_properties(self, widget=None, properties=None): """ Adds widget to container , setting child properties at the same time. See GLXCurses.Container.add() and GLXCurses.Container.child_set() for more details. :param widget: a widget to be placed inside container :type widget: GLXCurses.Widget :param properties: properties to set :type properties: GLXCurses.ChildProperty :raise TypeError: if ``properties`` is not a GLXCurses.ChildProperty instance :raise TypeError: if widget is not a instance of GLXCurses.Widget """ # Try to exit as soon of possible if not isinstance(widget, GLXCurses.Widget): raise TypeError("'widget' must be an instance of GLXCurses.Widget") if not isinstance(properties, GLXCurses.ChildProperty): raise TypeError("'properties' must be ChildProperty instance") # If we are here everything look ok self.add(widget) self.child_set(widget, properties)
[docs] def get_resize_mode(self): """ Returns the resize mode for the container. Allowed value: * GLXC.RESIZE_PARENT * GLXC.RESIZE_QUEUE * GLXC.RESIZE_IMMEDIATE .. seealso:: :func:`GLXCurses.Container.set_resize_mode() <GLXCurses.Constants.Constants.set_resize_mode>`. .. warning:: :func:`GLXCurses.Container.get_resize_mode() <GLXCurses.Container.Container.get_resize_mode>`\ has been deprecated since version 3.12 of GTK+, if will be remove as soon of possible. :return: the current resize mode :rtype: GLXCurses.Constants """ return self.resize_mode
[docs] def set_resize_mode(self, resize_mode=None): """ Sets the resize mode for the container. The resize mode of a container determines whether a resize request will be passed to the container’s parent, queued for later execution or executed immediately. Allowed value: * GLXC.RESIZE_PARENT * GLXC.RESIZE_QUEUE * GLXC.RESIZE_IMMEDIATE .. seealso:: :func:`GLXCurses.Container.get_resize_mode() <GLXCurses.Container.Container.get_resize_mode>`. .. warning:: :func:`GLXCurses.Container.set_resize_mode() <GLXCurses.Container.Container.set_resize_mode>`\ has been deprecated since version 3.12 of GTK+, if will be remove as soon of possible. :param resize_mode: the new resize mode :type resize_mode: GLXCurses.Constants """ self.resize_mode = resize_mode
[docs] def check_resize(self): """ The check_resize() method emits the "check-resize" signal on the container. """ if self.resize_mode == "PARENT": if self.children: for child in self.children: pass
[docs] def foreachs(self, callback, *callback_data): """ Invokes callback on each non-internal child of container . See GLXCurses.Container.forall() for details on what constitutes an “internal” child. For all practical purposes, this function should iterate over precisely those child widgets that were added to the container by the application with explicit add() calls. Most applications should use GLXCurses.Container.foreachs(), rather than GLXCurses.Container.forall(). :param callback: a callback. :param callback_data: callback user __area_data """ # Dispatch to every children and child if self.__class__.__name__ in GLXCurses.GLXC.CHILDREN_CONTAINER: if hasattr(self, "children"): if bool(self.children): for child in self.children: for detailed_signal, handler in list( child.widget.subscriptions.items() ): if handler[0] == callback: handler[0](*callback_data) else: if hasattr(self, "child"): if bool(self.child): for detailed_signal, handler in list( self.child.widget.subscriptions.items() ): if handler[0] == callback: handler[0](*callback_data)
[docs] def get_path_for_child(self, child=None): """ Returns a newly created widget path representing all the widget hierarchy from the toplevel down to and including child . :return: A newly created WidgetPath """ if child is None: return None # Try to exit as soon of possible if not GLXCurses.glxc_type(child): raise TypeError('"container" argument must be a GLXCurses object type') # If we are here everything look ok if self.__class__.__name__ in GLXCurses.GLXC.CHILDREN_CONTAINER: if bool(self.children): count = 0 last_found = None for children in self.children: if child == children.widget: last_found = count count += 1 if last_found is not None: if ( self.children[last_found].widget.__class__.__name__ in GLXCurses.GLXC.CHILDREN_CONTAINER ): return self.children[last_found].widget.glxc_type else: if not bool(self.children[last_found].widget.child): return self.children[last_found].widget.glxc_type else: # no more space in the container return None else: # the child is not found return -1 else: # the child is not found that because it have no child in the child list return -1 else: if bool(self.child): if self.child.widget == child: if ( self.child.widget.__class__.__name__ in GLXCurses.GLXC.CHILDREN_CONTAINER ): return self.child.widget.glxc_type else: if not bool(self.child.widget.child): return self.child.widget.glxc_type else: # no more space in the container return None else: # the child is not found return -1 else: # the child is not found that because it have no child in the child list return -1 parent_list = [] # parent = self._pop_last_event() if bool(parent_list): return parent_list else: return list()
[docs] def forall(self, callback, callback_data): pass
[docs] def propagate_expose(self, child, event): pass
[docs] def set_focus_chain(self, focusable_widgets): pass
[docs] def get_focus_chain(self): pass
[docs] def unset_focus_chain(self): pass
[docs] def set_reallocate_redraws(self, needs_redraws): pass
[docs] def set_focus_child(self, child): pass
[docs] def get_focus_child(self): pass
[docs] def get_focus_vadjustment(self): """ Retrieves the vertical focus adjustment for the container. See \ :func:`Container.set_focus_vadjustment() <GLXCurses.Container.Container.set_focus_vadjustment()>`. :return: the vertical focus adjustment, or :py:__area_data:`None` if none has been set. :rtype: :class:`Adjustment() <GLXCurses.Adjustment.Adjustment()>` or :py:__area_data:`None` """ return self._focus_vadjustment
[docs] def set_focus_vadjustment(self, adjustment=None): """ Hooks up an adjustment to focus handling in a container, so when a child of the container is focused, the adjustment is scrolled to show that widget. This function sets the vertical alignment. See scrolled_window_get_vadjustment() for a typical way of obtaining the adjustment and :func:`Container.set_focus_hadjustment() <GLXCurses.Container.Container.set_focus_hadjustment()>` for setting the horizontal adjustment. The adjustments have to be in character units and in the same coordinate system as the allocation for immediate children of the container. :param adjustment: an adjustment which should be adjusted when the focus is \ moved among the descendants of ``container`` :type adjustment: :class:`Adjustment() <GLXCurses.Adjustment.Adjustment()>` or :py:__area_data:`None` :raise TypeError: if ``adjustment`` is not a :class:`Adjustment() <GLXCurses.Adjustment.Adjustment()>` """ # Try to exit as soon of possible if adjustment is not None and not GLXCurses.glxc_type(adjustment): raise TypeError('"adjustment" argument must be a GLXCurses object type') if adjustment is not None and adjustment.glxc_type != "GLXCurses.Adjustment": raise TypeError('"adjustment" argument must be a GLXCurses.Adjustment') if adjustment is not None: adjustment_info = GLXCurses.ChildElement() adjustment_info.widget = adjustment adjustment_info.type = adjustment.glxc_type adjustment_info.id = adjustment.id if self._focus_vadjustment != adjustment_info: self._focus_vadjustment = adjustment_info else: if self._focus_vadjustment is not None: self._focus_vadjustment = None
[docs] def get_focus_hadjustment(self): """ Retrieves the horizontal focus adjustment for the container. See \ :func:`Container.set_focus_hadjustment() <GLXCurses.Container.Container.set_focus_hadjustment()>`. :return: the horizontal focus adjustment, or :py:__area_data:`None` if none has been set. :rtype: :class:`Adjustment() <GLXCurses.Adjustment.Adjustment()>` or :py:__area_data:`None` """ return self._focus_hadjustment
[docs] def set_focus_hadjustment(self, adjustment): """ Hooks up an adjustment to focus handling in a container, so when a child of the container is focused, the adjustment is scrolled to show that widget. This function sets the horizontal alignment. See scrolled_window_get_hadjustment() for a typical way of obtaining the adjustment and :func:`Container.set_focus_vadjustment() <GLXCurses.Container.Container.set_focus_vadjustment()>` for setting the vertical adjustment. The adjustments have to be in pixel units and in the same coordinate system as the allocation for immediate children of the container. :param adjustment: an adjustment which should be adjusted when the focus is \ moved among the descendants of ``container`` :type adjustment: :class:`Adjustment() <GLXCurses.Adjustment.Adjustment()>` or :py:__area_data:`None` :raise TypeError: if ``adjustment`` is not a :class:`Adjustment() <GLXCurses.Adjustment.Adjustment()>` """ # Try to exit as soon of possible if adjustment is not None and not GLXCurses.glxc_type(adjustment): raise TypeError('"adjustment" argument must be a GLXCurses object type') if adjustment is not None and adjustment.glxc_type != "GLXCurses.Adjustment": raise TypeError('"adjustment" argument must be a GLXCurses.Adjustment') if adjustment is not None: adjustment_info = GLXCurses.ChildElement( widget=adjustment, widget_name=adjustment.name, widget_type=adjustment.glxc_type, widget_id=adjustment.id, ) if self._focus_hadjustment != adjustment_info: self._focus_hadjustment = adjustment_info else: if self._focus_hadjustment is not None: self._focus_hadjustment = None
# def resize_children(self): # pass
[docs] def child_type(self, container): """ Returns the type of the children supported by the container. Note that this may return ``None`` to indicate that no more children can be added, e.g. for a Paned which already has two children. Note that this may return ``-1`` to indicate ``container`` is not found :param container: :return: the type of children :rtype: str , None or -1 :raise TypeError: if ``child`` is not a GLXCurses type as tested by \ :func:`glxc_type() <GLXCurses.Utils.glxc_type>` """ # Try to exit as soon of possible if not GLXCurses.glxc_type(container): raise TypeError('"container" argument must be a GLXCurses object type') # If we are here everything look ok if self.__class__.__name__ in GLXCurses.GLXC.CHILDREN_CONTAINER: if bool(self.children): count = 0 last_found = None for children in self.children: if container == children.widget: last_found = count count += 1 if last_found is not None: if ( self.children[last_found].widget.__class__.__name__ in GLXCurses.GLXC.CHILDREN_CONTAINER ): return self.children[last_found].widget.glxc_type else: if not bool(self.children[last_found].widget.child): return self.children[last_found].widget.glxc_type else: # no more space in the container return None else: # the child is not found return -1 else: # the child is not found that because it have no child in the child list return -1 else: if self.child is not None: if self.child.widget == container: if ( self.child.widget.__class__.__name__ in GLXCurses.GLXC.CHILDREN_CONTAINER ): return self.child.widget.glxc_type else: if not bool(self.child.widget.child): return self.child.widget.glxc_type else: # no more space in the container return None else: # the child is not found return -1 else: # the child is not found that because it have no child in the child list return -1
[docs] def child_set(self, child, properties=None): """ Sets one or more child properties for child and container . :param child: a GLXCurses.Widget which is a child of container :type child: A GLXCurses.Widget :param properties: properties to set :type properties: GLXCurses.ChildProperty :raise TypeError: if ``child`` is not a GLXCurses type as tested by \ :func:`glxc_type() <GLXCurses.Utils.glxc_type>` :raise TypeError: if ``properties`` is not a dict type """ # Try to exit as soon of possible if not GLXCurses.glxc_type(child): raise TypeError('"child" argument must be a GLXCurses object type') if not isinstance(properties, GLXCurses.ChildProperty): raise TypeError('"properties" argument must be a ChildProperty instance') # If we are here everything look ok if self.__class__.__name__ in GLXCurses.GLXC.CHILDREN_CONTAINER: if bool(self.children): count = 0 last_found = None for children in self.children: if child == children.widget: last_found = count count += 1 if last_found is not None: self.children[last_found].properties = properties else: if self.child is not None: if self.child.widget == child: self.child.properties = properties
[docs] def child_get(self, child): """ Gets the values of one or more child properties for child and container . :param child: a widget which is a child of container :type child: A GLXCurses object :return: properties of the child or None if child not found :rtype: dict or None :raise TypeError: if ``child`` is not a GLXCurses type as tested by \ :func:`glxc_type() <GLXCurses.Utils.glxc_type>` """ # Try to exit as soon of possible if not GLXCurses.glxc_type(child): raise TypeError('"child" argument must be a GLXCurses object type') # If we are here everything look ok if self.__class__.__name__ in GLXCurses.GLXC.CHILDREN_CONTAINER: if bool(self.children): count = 0 last_found = None for children in self.children: if child == children.widget: last_found = count count += 1 if last_found is not None: return self.children[last_found].properties else: # the child is not found return None else: if child is not None: if self.child.widget == child: return self.child.properties else: # the child is not found return None
[docs] def child_set_property(self, child, property_name=None, value=None): """ Sets a child property for child and container . :param child: a GLXCurses.Widget which is a child of GLXCurses.Container :type child: a GLXCures.Widget :param property_name: the name of the property to set :type property_name: str :param value: the value to set the property to :type value: everything except None :raise TypeError: if ``child`` is not a GLXCurses type as tested by \ :func:`glxc_type() <GLXCurses.Utils.glxc_type>` :raise TypeError: if ``property_name`` is not str type :raise TypeError: if ``value`` is None type """ # Try to exit as soon of possible if not GLXCurses.glxc_type(child): raise TypeError('"child" argument must be a GLXCurses object type') if type(property_name) != str: raise TypeError('"property_name" argument must be a str type') if value is None: raise TypeError('"value" argument cant be a None type') # If we are here everything look ok property_to_set = {property_name: value} if self.__class__.__name__ in GLXCurses.GLXC.CHILDREN_CONTAINER: if bool(self.children): count = 0 last_found = None for children in self.children: if child == children.widget: last_found = count count += 1 if last_found is not None: setattr(self.children[last_found].properties, property_name, value) else: if self.child is not None: if self.child.widget == child: setattr(self.child.properties, property_name, value)
[docs] def child_get_property(self, child, property_name=None): """ Gets the value of a child property for child and container . :param child: a widget which is a child of container :type child: a GLXCures Object :param property_name: the name of the property to set :type property_name: str :raise TypeError: if ``child`` is not a GLXCurses type as tested by \ :func:`glxc_type() <GLXCurses.Utils.glxc_type>` :raise TypeError: if ``property_name`` is not str type """ # Try to exit as soon of possible if not GLXCurses.glxc_type(child): raise TypeError('"child" argument must be a GLXCurses object type') if type(property_name) != str: raise TypeError('"property_name" argument must be a str type') # If we are here everything look ok if self.__class__.__name__ in GLXCurses.GLXC.CHILDREN_CONTAINER: if bool(self.children): count = 0 last_found = None for children in self.children: if child == children.widget: last_found = count count += 1 if last_found is not None: try: return getattr( self.children[last_found].properties, property_name ) except KeyError: # the property is not found return None else: # the child is not found return None else: if bool(self.child): if self.child.widget == child: try: return getattr(self.child.properties, property_name) except KeyError: # the property is not found return None else: # the child is not found return None
[docs] def get_border_width(self): """ Retrieves the border width of the container. See GLXCurses.Container.set_border_width(). :return: the current border width :rtype: int """ return self.border_width
[docs] def set_border_width(self, border_width=0): """ Sets the border width of the container. The border width of a container is the amount of space to leave around the outside of the container. The only exception to this is GLXCurses.Window; because toplevel windows can’t leave space outside, they leave the space inside. The border is added on all sides of the container. To add space to only one side, use a specific “margin” property on the child widget, for example “margin-top”. border_width have valid values are in the range 0-65535 chars and will be clamp to value. :param border_width: amount of blank space to leave outside the container. :type border_width: int :raise TypeError: When border_width is not a int """ # Exit as soon of possible if type(border_width) != int: raise TypeError("'border_width' must be a int type") # Clamp on range 0-65535 border_width = GLXCurses.clamp(value=border_width, smallest=0, largest=65535) # make the job if self.border_width != border_width: self.border_width = border_width