
ddc           @` s   d  Z  d d l m Z m Z m Z m Z d d l Td d l Z d d l	 Z	 d d l
 m Z d d l
 m Z d	 d
 g Z d e f d     YZ d e j j e j e  f d     YZ d e f d     YZ d S(   uC   Classes to keep settings and their associated GUI elements in sync.i    (   t   absolute_importt   divisiont   print_functiont   unicode_literals(   t   *Ni   (   t   utilsi   (   t   metau	   Presenteru   NullPresentert   SettingValueSynchronizerc           B` s   e  Z d  Z d   Z RS(   u[   Helper class allowing `Setting` and `Presenter` instance to keep their
  values in sync.
  c         C` s   t  j |  _ t  j |  _ d  S(   N(   t   pgutilst
   empty_funct   apply_setting_value_to_guit   apply_gui_value_to_setting(   t   self(    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyt   __init__   s    (   t   __name__t
   __module__t   __doc__R   (    (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR      s   t	   Presenterc           B` s+  e  Z d  Z e Z d Z d d d e d  Z e d    Z	 e d    Z
 e d    Z e j d    Z e j d    Z e j d    Z e j d    Z d	   Z d
   Z d   Z e j d    Z e j d    Z d   Z d   Z e j d    Z e j d    Z d   Z d   Z RS(   u  Wrapper of a GUI element (widget, dialog, etc.) for settings.
  
  Various GUI elements have different attributes or methods to access their
  properties. This class wraps some of these attributes/methods so that they can
  be accessed with the same name.
  
  Subclasses can wrap any attribute of a GUI element into their `_get_value()`
  and `_set_value()` methods. The value does not have to be a 'direct' value,
  e.g. the checked state of a check button, but also e.g. the label of the
  check button.
  
  Instances of this class should not be created directly. Instead, use
  `Setting.gui` to access a setting's `Presenter` instance.
  
  Attributes:
  
  * `setting (read-only)` - Setting object.
  
  * `element (read-only)` - GUI element object.
  
  * `_VALUE_CHANGED_SIGNAL` - Object that indicates the type of event to
    connect to the GUI element. Once the event is triggered, it assigns the GUI
    element value to the setting value. If this attribute is `None`, no event
    can be connected.
  c         C` s   | |  _  | |  _ | |  _ | r0 |  j |  _ n	 d |  _ |  j |  j _ |  j d k r |  j |  |  _ |  j d k r t	 d j
 t |   j    q n  | d k	 r |  j |  n |  j j |  j  j  |  j d k	 r |  j   n  d S(   u=  
    Parameters:
    
    * `element` - A GUI element.
      
      If `element` is `None`, create a new GUI element automatically. If the
      specific `Presenter` class does not support creating a GUI element, pass
      an existing GUI element.
    
    * `setting_value_synchronizer` - `SettingValueSynchronizer` instance to
      synchronize values between `setting` and this object.
    
    * `old_presenter` - `Presenter` object that was previously assigned to
      `setting` (as the `setting.gui` attribute). The state from that
      `Presenter` object will be copied to this object. If `old_presenter` is
      `None`, only `setting.value` will be copied to this object.
    
    * `auto_update_gui_to_setting` - If `True`, automatically update the setting
      value if the GUI value is updated. This parameter does not have any effect
      if:
        
        * the `Presenter` class cannot provide automatic GUI-to-setting update,
        
        * `old_presenter` is not `None` and the automatic GUI-to-setting update
          was disabled in that presenter.
    ux   cannot instantiate class "{}": attribute "element" is None and this class does not support the creation of a GUI elementN(   t   _settingt   _elementt   _setting_value_synchronizert   _VALUE_CHANGED_SIGNALt   _value_changed_signalt   Nonet   _apply_setting_value_to_guiR
   t   _create_gui_elementt
   ValueErrort   formatt   typeR   t   _copy_statet   valuet   _connect_value_changed_event(   R   t   settingt   elementt   setting_value_synchronizert   old_presentert   auto_update_gui_to_setting(    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR   >   s$    !				c         C` s   |  j  S(   N(   R   (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR    |   s    c         C` s   |  j  S(   N(   R   (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR!      s    c         C` s   |  j  d  k	 S(   N(   R   R   (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyt   gui_update_enabled   s    c         C` s   d S(   u/   Returns the sensitive state of the GUI element.N(    (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyt   get_sensitive   s    c         C` s   d S(   u,   Sets the sensitive state of the GUI element.N(    (   R   t	   sensitive(    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyt   set_sensitive   s    c         C` s   d S(   u-   Returns the visible state of the GUI element.N(    (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyt   get_visible   s    c         C` s   d S(   u*   Sets the visible state of the GUI element.N(    (   R   t   visible(    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyt   set_visible   s    c         C` s/   |  j  d k s |  j j   r+ |  j   n  d S(   u   Manually assigns the GUI element value, entered by the user, to the
    setting value.
    
    This method will not have any effect if this object updates its setting
    value automatically.
    N(   R   R   R   t   is_value_emptyt   _update_setting_value(   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyt   update_setting_value   s    	c         C` sl   | r6 |  j  d k r6 t d j t |   j    n  | rU |  j  |  _ |  j   n d |  _ |  j   d S(   u   Enables or disables automatic GUI update.
    
    If `value` is `True` and the `Presenter` class does not support automatic
    GUI update, `ValueError` is raised.
    u0   class "{}" does not support automatic GUI updateN(	   R   R   R   R   R   R   R   R   t   _disconnect_value_changed_event(   R   t   enabled(    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR$      s    	c         C` s   d S(   u   Instantiates and returns a new GUI element using the attributes in the
    specified `Setting` instance (e.g. display name as GUI label).
    
    `None` is returned if the `Presenter` subclass does not support GUI element
    creation.
    N(   R   (   R   R    (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR      s    c         C` s   d S(   u%   Returns the value of the GUI element.N(    (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyt
   _get_value   s    c         C` s   d S(   u  Sets the value of the GUI element.
    
    If the value passed is one of the empty values allowed for the corresponding
    setting and the GUI element cannot handle the value, this method must wrap
    the empty value into a safe value (that the GUI element can handle).
    N(    (   R   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyt
   _set_value   s    c         C` sR   |  j  | j    |  j | j    |  j | j    | j sN d  |  _ n  d  S(   N(	   R2   R1   R(   R&   R+   R)   R%   R   R   (   R   R#   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR      s
    	c         C` s   |  j  j |  j    d S(   uN   Assigns the GUI element value, entered by the user, to the setting value.
    N(   R   R   R1   (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR-      s    c         C` s   d S(   u  Connects the `_on_value_changed` event handler to the GUI element using
    the `_value_changed_signal` attribute.
    
    Because the way event handlers are connected varies in each GUI framework,
    subclass this class and override this method for the GUI framework you use.
    N(    (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR      s    c         C` s   d S(   u   Disconnects the `_on_value_changed` event handler from the GUI element.
    
    Because the way event handlers are disconnected varies in each GUI framework,
    subclass this class and override this method for the GUI framework you use.
    N(    (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR/      s    c         G` s   |  j    d S(   u   Event handler that automatically updates the value of the setting.
    
    The event is triggered when the user changes the value of the GUI element.
    N(   R-   (   R   t   args(    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyt   _on_value_changed   s    c         C` s   |  j  |  d S(   us   Assigns the setting value to the GUI element. Used by the setting when
    its `set_value()` method is called.
    N(   R2   (   R   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR      s    N(   R   R   R   t   Truet	   _ABSTRACTR   R   R   t   propertyR    R!   R%   t   abct   abstractmethodR&   R(   R)   R+   R.   R$   R   R1   R2   R   R-   R   R/   R4   R   (    (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR      s2   8				
		
		t   NullPresenterc           B` s   e  Z d  Z d Z e d d i     Z d   Z d   Z d   Z d   Z	 d   Z
 d   Z d	   Z d
   Z d   Z d   Z RS(   uF  Empty `Presenter` class whose methods do nothing.
  
  This class is attached to `Setting` objects with no `Presenter` object
  specified upon its instantiation.
  
  This class also records the GUI state. In case a proper `Presenter` instance
  is assigned to the setting, the GUI state is copied over to the new instance.
  u   null_signalt   NullGuiElementc         O` s;   d |  _ t |  _ t |  _ t j |  | |  j | |  d S(   uD   
    `element` is ignored - its attributes are not read or set.
    N(   R   t   _valueR5   t
   _sensitivet   _visibleR   R   t   _NULL_GUI_ELEMENT(   R   R    R!   R3   t   kwargs(    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR     s    			c         C` s   |  j  S(   N(   R=   (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR&     s    c         C` s   | |  _  d  S(   N(   R=   (   R   R'   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR(     s    c         C` s   |  j  S(   N(   R>   (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR)     s    c         C` s   | |  _  d  S(   N(   R>   (   R   R*   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR+      s    c         C` s   d  S(   N(    (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR.   #  s    c         C` s   |  j  S(   N(   R<   (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR1   &  s    c         C` s   | |  _  d  S(   N(   R<   (   R   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR2   )  s    c         C` s   d  S(   N(    (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR   ,  s    c         C` s   d  S(   N(    (   R   (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR/   /  s    (    (   R   R   R   R   R   R?   R   R&   R(   R)   R+   R.   R1   R2   R   R/   (    (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyR:      s   	
								(   R   t
   __future__R    R   R   R   t   future.builtinst   future.utilst   futureR8   t    R   R   R   t   meta_t   __all__t   objectR   t   with_metaclasst   PresenterMetaR   R:   (    (    (    sS   /home/josie/.config/GIMP/2.10/plug-ins/export_layers/pygimplib/setting/presenter.pyt   <module>   s   "
	
(                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            # -*- coding: utf-8 -*-

"""`setting.presenter.Presenter` subclasses for GTK GUI elements."""

from __future__ import absolute_import, division, print_function, unicode_literals
from future.builtins import *

import inspect
import sys

import pygtk
pygtk.require('2.0')
import gtk

import gimp
import gimpui

from .. import gui as pggui
from .. import utils as pgutils

from . import presenter as presenter_


class GtkPresenter(presenter_.Presenter):
  """Abstract `Presenter` subclass for GTK GUI elements."""
  
  _ABSTRACT = True
  
  def __init__(self, *args, **kwargs):
    self._event_handler_id = None
    
    presenter_.Presenter.__init__(self, *args, **kwargs)
  
  def get_sensitive(self):
    return self._element.get_sensitive()
  
  def set_sensitive(self, sensitive):
    self._element.set_sensitive(sensitive)
  
  def get_visible(self):
    return self._element.get_visible()
  
  def set_visible(self, visible):
    self._element.set_visible(visible)
  
  def _connect_value_changed_event(self):
    self._event_handler_id = self._element.connect(
      self._VALUE_CHANGED_SIGNAL, self._on_value_changed)
  
  def _disconnect_value_changed_event(self):
    self._element.disconnect(self._event_handler_id)
    self._event_handler_id = None


class IntSpinButtonPresenter(GtkPresenter):
  """`Presenter` subclass for `gtk.SpinButton` elements.
  
  Value: Integer value of the spin button.
  """
  
  _VALUE_CHANGED_SIGNAL = 'value-changed'
  
  def _create_gui_element(self, setting):
    return _create_spin_button(setting)
  
  def _get_value(self):
    return self._element.get_value_as_int()
  
  def _set_value(self, value):
    self._element.set_value(value)


class FloatSpinButtonPresenter(GtkPresenter):
  """`Presenter` subclass for `gtk.SpinButton` elements.
  
  Value: Floating point value of the spin button.
  """
  
  _VALUE_CHANGED_SIGNAL = 'value-changed'
  
  def _create_gui_element(self, setting):
    return _create_spin_button(setting, digits=1)
  
  def _get_value(self):
    return self._element.get_value()
  
  def _set_value(self, value):
    self._element.set_value(value)


class CheckButtonPresenter(GtkPresenter):
  """`Presenter` subclass for `gtk.CheckButton` elements.
  
  Value: Checked state of the check button (checked/unchecked).
  """
  
  _VALUE_CHANGED_SIGNAL = 'clicked'
  
  def _create_gui_element(self, setting):
    return gtk.CheckButton(setting.display_name, use_underline=False)
  
  def _get_value(self):
    return self._element.get_active()
  
  def _set_value(self, value):
    self._element.set_active(value)


class CheckButtonNoTextPresenter(CheckButtonPresenter):
  """`Presenter` subclass for `gtk.CheckButton` elements without text next to
  the checkbox.
  
  Value: Checked state of the check button (checked/unchecked).
  """
  
  def _create_gui_element(self, setting):
    return gtk.CheckButton(None, use_underline=False)


class CheckButtonLabelPresenter(GtkPresenter):
  """`Presenter` subclass for `gtk.CheckButton` elements.
  
  Value: Label of the check button.
  """
  
  def _get_value(self):
    return pgutils.safe_decode_gtk(self._element.get_label())
  
  def _set_value(self, value):
    self._element.set_label(pgutils.safe_encode_gtk(value))


class CheckMenuItemPresenter(GtkPresenter):
  """`Presenter` subclass for `gtk.CheckMenuItem` elements.
  
  Value: Checked state of the menu item (checked/unchecked).
  """
  
  _VALUE_CHANGED_SIGNAL = 'toggled'
  
  def _create_gui_element(self, setting):
    return gtk.CheckMenuItem(setting.display_name)
  
  def _get_value(self):
    return self._element.get_active()
  
  def _set_value(self, value):
    self._element.set_active(value)


class ExpanderPresenter(GtkPresenter):
  """`Presenter` subclass for `gtk.Expander` elements.
  
  Value: `True` if the expander is expanded, `False` if collapsed.
  """
  
  _VALUE_CHANGED_SIGNAL = 'notify::expanded'
  
  def _create_gui_element(self, setting):
    expander = gtk.Expander(label=setting.display_name)
    expander.set_use_underline(True)
    return expander
  
  def _get_value(self):
    return self._element.get_expanded()
  
  def _set_value(self, value):
    self._element.set_expanded(value)


class ComboBoxPresenter(GtkPresenter):
  """`Presenter` subclass for `gimpui.IntComboBox` elements.
  
  Value: Item selected in the combo box.
  """
  
  _VALUE_CHANGED_SIGNAL = 'changed'
  
  def _create_gui_element(self, setting):
    labels_and_values = setting.get_item_display_names_and_values()
    
    for i in range(0, len(labels_and_values), 2):
      labels_and_values[i] = pgutils.safe_encode_gtk(labels_and_values[i])
    
    return gimpui.IntComboBox(tuple(labels_and_values))
  
  def _get_value(self):
    return self._element.get_active()
  
  def _set_value(self, value):
    self._element.set_active(value)
  

class EntryPresenter(GtkPresenter):
  """`Presenter` subclass for `gtk.Entry` elements.
  
  Value: Text in the entry.
  """
  
  def _create_gui_element(self, setting):
    return gtk.Entry()
  
  def _get_value(self):
    return pgutils.safe_decode_gtk(self._element.get_text())
  
  def _set_value(self, value):
    self._element.set_text(pgutils.safe_encode_gtk(value))
    # Place the cursor at the end of the text entry.
    self._element.set_position(-1)


class ImageComboBoxPresenter(GtkPresenter):
  """`Presenter` subclass for `gimpui.ImageComboBox` elements.
  
  Value: `gimp.Image` selected in the combo box.
  """
  
  _VALUE_CHANGED_SIGNAL = 'changed'
  
  def _create_gui_element(self, setting):
    return gimpui.ImageComboBox()
  
  def _get_value(self):
    return self._element.get_active_image()
  
  def _set_value(self, value):
    """Sets a `gimp.Image` instance to be selected in the combo box.
    
    Passing `None` has no effect.
    """
    if value is not None:
      self._element.set_active_image(value)


class ItemComboBoxPresenter(GtkPresenter):
  """`Presenter` subclass for `gui.GimpItemComboBox` elements.
  
  If the setting references a `gimp.Image`, only drawables from that image will
  be displayed.
  
  Value: `gimp.Item` selected in the combo box.
  """
  
  _VALUE_CHANGED_SIGNAL = 'changed'
  
  def _create_gui_element(self, setting):
    return _create_item_combo_box(pggui.GimpItemComboBox, setting)
  
  def _get_value(self):
    return self._element.get_active_item()
  
  def _set_value(self, value):
    """Sets a `gimp.Item` instance to be selected in the combo box.
    
    Passing `None` has no effect.
    """
    if value is not None:
      self._element.set_active_item(value)


class DrawableComboBoxPresenter(GtkPresenter):
  """`Presenter` subclass for `gimpui.DrawableComboBox` elements.
  
  If the setting references a `gimp.Image`, only drawables from that image will
  be displayed.
  
  Value: `gimp.Drawable` selected in the combo box.
  """
  
  _VALUE_CHANGED_SIGNAL = 'changed'
  
  def _create_gui_element(self, setting):
    return _create_item_combo_box(gimpui.DrawableComboBox, setting)
  
  def _get_value(self):
    return self._element.get_active_drawable()
  
  def _set_value(self, value):
    """Sets a `gimp.Drawable` instance to be selected in the combo box.
    
    Passing `None` has no effect.
    """
    if value is not None:
      self._element.set_active_drawable(value)


class LayerComboBoxPresenter(GtkPresenter):
  """`Presenter` subclass for `gimpui.LayerComboBox` elements.
  
  If the setting references a `gimp.Image`, only layers from that image will be
  displayed.
  
  Value: `gimp.Layer` selected in the combo box.
  """
  
  _VALUE_CHANGED_SIGNAL = 'changed'
  
  def _create_gui_element(self, setting):
    return _create_item_combo_box(gimpui.LayerComboBox, setting)
  
  def _get_value(self):
    return self._element.get_active_layer()
  
  def _set_value(self, value):
    """Sets a `gimp.Layer` instance to be selected in the combo box.
    
    Passing `None` has no effect.
    """
    if value is not None:
      self._element.set_active_layer(value)


class ChannelComboBoxPresenter(GtkPresenter):
  """`Presenter` subclass for `gimpui.ChannelComboBox` elements.
  
  If the setting references a `gimp.Image`, only channels from that image will
  be displayed.
  
  Value: `gimp.Channel` selected in the combo box.
  """
  
  _VALUE_CHANGED_SIGNAL = 'changed'
  
  def _create_gui_element(self, setting):
    return _create_item_combo_box(gimpui.ChannelComboBox, setting)
  
  def _get_value(self):
    return self._element.get_active_channel()
  
  def _set_value(self, value):
    """Sets a `gimp.Channel` instance to be selected in the combo box.
    
    Passing `None` has no effect.
    """
    if value is not None:
      self._element.set_active_channel(value)


class VectorsComboBoxPresenter(GtkPresenter):
  """`Presenter` subclass for `gimpui.VectorsComboBox` elements.
  
  If the setting references a `gimp.Image`, only vectors from that image will
  be displayed.
  
  Value: `gimp.Vectors` selected in the combo box.
  """
  
  _VALUE_CHANGED_SIGNAL = 'changed'
  
  def _create_gui_element(self, setting):
    return _create_item_combo_box(gimpui.VectorsComboBox, setting)
  
  def _get_value(self):
    return self._element.get_active_vectors()
  
  def _set_value(self, value):
    """Sets a `gimp.Vectors` instance to be selected in the combo box.
    
    Passing `None` has no effect.
    """
    if value is not None:
      self._element.set_active_vectors(value)
  

class ColorButtonPresenter(GtkPresenter):
  """`Presenter` subclass for `gimpui.ColorButton` elements.
  
  Value: `gimpcolor.RGB` instance representing color in RGB.
  """
  
  _VALUE_CHANGED_SIGNAL = 'color-changed'
  
  def _create_gui_element(self, setting):
    return gimpui.ColorButton(
      setting.display_name, 100, 20, setting.value, gimpui.COLOR_AREA_FLAT)
  
  def _get_value(self):
    return self._element.get_color()
  
  def _set_value(self, value):
    self._element.set_color(value)


class ParasiteBoxPresenter(GtkPresenter):
  """`Presenter` subclass for `gui.ParasiteBox` elements.
  
  Value: `gimp.Parasite` instance.
  """
  
  _VALUE_CHANGED_SIGNAL = 'parasite-changed'
  
  def _create_gui_element(self, setting):
    return pggui.ParasiteBox(setting.value)
  
  def _get_value(self):
    return self._element.get_parasite()
  
  def _set_value(self, value):
    self._element.set_parasite(value)


class DisplaySpinButtonPresenter(GtkPresenter):
  """`Presenter` subclass for `gtk.SpinButton` elements.
  
  Value: `gimp.Display` instance, represented by its integer ID in the spin
  button.
  """
  
  _VALUE_CHANGED_SIGNAL = 'value-changed'
  
  def _create_gui_element(self, setting):
    display_id = getattr(setting.value, 'ID', 0)
    
    spin_button = gtk.SpinButton(
      gtk.Adjustment(
        value=display_id,
        lower=0,
        upper=2**32,
        step_incr=1,
        page_incr=10,
      ),
      digits=0)
    
    spin_button.set_numeric(True)
    spin_button.set_value(display_id)
    
    return spin_button
  
  def _get_value(self):
    return gimp._id2display(self._element.get_value_as_int())
  
  def _set_value(self, value):
    self._element.set_value(value.ID)


class ExtendedEntryPresenter(GtkPresenter):
  """`Presenter` subclass for `gui.ExtendedEntry` elements.
  
  Value: Text in the entry.
  """
  
  def _get_value(self):
    return pgutils.safe_decode_gtk(self._element.get_text())
  
  def _set_value(self, value):
    self._element.assign_text(pgutils.safe_encode_gtk(value))


class FileExtensionEntryPresenter(ExtendedEntryPresenter):
  """`Presenter` subclass for `gui.FileExtensionEntry` elements.
  
  Value: Text in the entry.
  """
  
  def _create_gui_element(self, setting):
    return pggui.FileExtensionEntry()


class FolderChooserWidgetPresenter(GtkPresenter):
  """`Presenter` subclass for `gtk.FileChooserWidget` elements used as folder
  choosers.
  
  Value: Current folder.
  """
  
  def __init__(self, *args, **kwargs):
    GtkPresenter.__init__(self, *args, **kwargs)
    
    self._location_toggle_button = self._get_location_toggle_button()

  def _create_gui_element(self, setting):
    return gtk.FileChooserWidget(action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
  
  def _get_value(self):
    if not self._is_location_entry_active():
      dirpath = self._element.get_current_folder()
    else:
      dirpath = self._element.get_filename()
    
    if dirpath is not None:
      return pgutils.safe_decode_gtk(dirpath)
    else:
      return None
  
  def _set_value(self, dirpath):
    self._element.set_current_folder(pgutils.safe_encode_gtk(dirpath))
  
  def _get_location_toggle_button(self):
    return (
      self._element.get_children()[0].get_children()[0].get_children()[0]
      .get_children()[0].get_children()[0])
  
  def _is_location_entry_active(self):
    return self._location_toggle_button.get_active()


class FolderChooserButtonPresenter(GtkPresenter):
  """`Presenter` subclass for `gtk.FileChooserButton` elements used as folder
  choosers.
  
  Value: Current folder.
  """

  def _create_gui_element(self, setting):
    button = gtk.FileChooserButton(title=setting.display_name)
    button.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
    return button
  
  def _get_value(self):
    dirpath = self._element.get_filename()
    
    if dirpath is not None:
      return pgutils.safe_decode_gtk(dirpath)
    else:
      return None
  
  def _set_value(self, dirpath):
    self._element.set_current_folder(pgutils.safe_encode_gtk(dirpath))


class BrushSelectButtonPresenter(GtkPresenter):
  """`Presenter` subclass for `gimpui.BrushSelectButton` elements.
  
  Value: Tuple representing a brush.
  """
  
  _VALUE_CHANGED_SIGNAL = 'brush-set'
  _BRUSH_PROPERTIES = ['brush-name', 'brush-opacity', 'brush-spacing', 'brush-paint-mode']
  
  def _create_gui_element(self, setting):
    return gimpui.BrushSelectButton(setting.display_name, *setting.value)
  
  def _get_value(self):
    return self._element.get_brush()
  
  def _set_value(self, value):
    for property_name, property_value in zip(self._BRUSH_PROPERTIES, value):
      self._element.set_property(property_name, property_value)


class FontSelectButtonPresenter(GtkPresenter):
  """`Presenter` subclass for `gimpui.FontSelectButton` elements.
  
  Value: String representing a font.
  """
  
  _VALUE_CHANGED_SIGNAL = 'font-set'
  
  def _create_gui_element(self, setting):
    return gimpui.FontSelectButton(setting.display_name, setting.value)
  
  def _get_value(self):
    return self._element.get_font()
  
  def _set_value(self, value):
    self._element.set_font(value)


class GradientSelectButtonPresenter(GtkPresenter):
  """`Presenter` subclass for `gimpui.GradientSelectButton` elements.
  
  Value: String representing a gradient.
  """
  
  _VALUE_CHANGED_SIGNAL = 'gradient-set'
  
  def _create_gui_element(self, setting):
    return gimpui.GradientSelectButton(setting.display_name, setting.value)
  
  def _get_value(self):
    return self._element.get_gradient()
  
  def _set_value(self, value):
    self._element.set_gradient(value)


class PaletteSelectButtonPresenter(GtkPresenter):
  """`Presenter` subclass for `gimpui.PaletteSelectButton` elements.
  
  Value: String representing a color palette.
  """
  
  _VALUE_CHANGED_SIGNAL = 'palette-set'
  
  def _create_gui_element(self, setting):
    return gimpui.PaletteSelectButton(setting.display_name, setting.value)
  
  def _get_value(self):
    return self._element.get_palette()
  
  def _set_value(self, value):
    self._element.set_palette(value)


class PatternSelectButtonPresenter(GtkPresenter):
  """`Presenter` subclass for `gimpui.PatternSelectButton` elements.
  
  Value: String representing a pattern.
  """
  
  _VALUE_CHANGED_SIGNAL = 'pattern-set'
  
  def _create_gui_element(self, setting):
    return gimpui.PatternSelectButton(setting.display_name, setting.value)
  
  def _get_value(self):
    return self._element.get_pattern()
  
  def _set_value(self, value):
    self._element.set_pattern(value)


class ArrayBoxPresenter(GtkPresenter):
  """`Presenter` subclass for `gui.ArrayBox` elements.
  
  Value: Tuple of values of type `element_type` specified in the passed
  `gui.ArraySetting` instance.
  """
  
  _VALUE_CHANGED_SIGNAL = 'array-box-changed'
  _ITEM_CHANGED_SIGNAL = 'array-box-item-changed'
  
  def __init__(self, *args, **kwargs):
    self._item_changed_event_handler_id = None
    self._array_elements_with_events = set()
    
    GtkPresenter.__init__(self, *args, **kwargs)
  
  def update_setting_value(self):
    GtkPresenter.update_setting_value(self)
    
    for array_element in self._setting.get_elements():
      array_element.gui.update_setting_value()
  
  def _connect_value_changed_event(self):
    GtkPresenter._connect_value_changed_event(self)
    
    self._item_changed_event_handler_id = self._element.connect(
      self._ITEM_CHANGED_SIGNAL, self._on_item_changed)
  
  def _disconnect_value_changed_event(self):
    GtkPresenter._disconnect_value_changed_event(self)
    
    self._element.disconnect(self._item_changed_event_handler_id)
    self._item_changed_event_handler_id = None
  
  def _create_gui_element(self, setting):
    def _add_existing_element(array_element_value, index):
      return self._add_array_element(setting[index], array_box)
    
    def _add_new_element(array_element_value, index):
      array_element = setting.add_element(value=array_element_value)
      return self._add_array_element(array_element, array_box)
    
    def _reorder_element(orig_position, new_position):
      setting.reorder_element(orig_position, new_position)
    
    def _remove_element(position):
      self._array_elements_with_events.remove(setting[position])
      del setting[position]
    
    array_box = pggui.ArrayBox(
      setting.element_default_value, setting.min_size, setting.max_size)
    
    array_box.on_add_item = _add_existing_element
    
    for element_index in range(len(setting)):
      array_box.add_item(setting[element_index].value, element_index)
    
    array_box.on_add_item = _add_new_element
    array_box.on_reorder_item = _reorder_element
    array_box.on_remove_item = _remove_element
    
    return array_box
  
  def _get_value(self):
    return tuple(array_element.value for array_element in self._setting.get_elements())
  
  def _set_value(self, value):
    def _add_existing_element(array_element_value, index):
      return self._add_array_element(self._setting[index], self._element)
    
    orig_on_add_item = self._element.on_add_item
    self._element.on_add_item = _add_existing_element
    
    self._element.set_values(value)
    
    self._element.on_add_item = orig_on_add_item
  
  def _on_item_changed(self, *args):
    self._setting_value_synchronizer.apply_gui_value_to_setting(self._get_value())
  
  def _add_array_element(self, array_element, array_box):
    def _on_array_box_item_changed(array_element):
      array_box.emit('array-box-item-changed')
    
    array_element.set_gui()
    
    if array_element not in self._array_elements_with_events:
      array_element.connect_event('value-changed', _on_array_box_item_changed)
      self._array_elements_with_events.add(array_element)
    
    return array_element.gui.element


class WindowPositionPresenter(GtkPresenter):
  """`Presenter` subclass for window or dialog elements
  (`gtk.Window`, `gtk.Dialog`) to get/set its position.
  
  Value: Current position of the window as a tuple with 2 integers.
  """
  
  def _get_value(self):
    return self._element.get_position()
  
  def _set_value(self, value):
    """Sets a new position of the window (i.e. move the window).
    
    The window is not moved if `value` is `None` or empty.
    """
    if value:
      self._element.move(*value)


class WindowSizePresenter(GtkPresenter):
  """`Presenter` subclass for window or dialog elements
  (`gtk.Window`, `gtk.Dialog`) to get/set its size.
  
  Value: Current size of the window as a tuple with 2 integers.
  """
  
  def _get_value(self):
    return self._element.get_size()
  
  def _set_value(self, value):
    """Sets a new size of the window.
    
    The window is not resized if `value` is `None` or empty.
    """
    if value:
      self._element.resize(*value)


class PanedPositionPresenter(GtkPresenter):
  """`Presenter` subclass for `gtk.Paned` elements.
  
  Value: Position of the pane.
  """
  
  def _get_value(self):
    return self._element.get_position()
  
  def _set_value(self, value):
    self._element.set_position(value)


def _create_spin_button(setting, digits=0):
  if hasattr(setting, 'min_value') and setting.min_value is not None:
    min_value = setting.min_value
  else:
    min_value = -2**32
  
  if hasattr(setting, 'max_value') and setting.max_value is not None:
    max_value = setting.max_value
  else:
    max_value = 2**32
  
  spin_button = gtk.SpinButton(
    gtk.Adjustment(
      value=setting.value,
      lower=min_value,
      upper=max_value,
      step_incr=1,
      page_incr=10,
    ),
    digits=digits)
  
  spin_button.set_numeric(True)
  spin_button.set_value(setting.value)
  
  return spin_button


def _create_item_combo_box(item_combo_box_type, setting):
  if hasattr(setting.value, 'image'):
    def _image_matches_setting_image(image, item, setting_image):
      return image == setting_image
    
    return item_combo_box_type(
      constraint=_image_matches_setting_image, data=setting.value.image)
  else:
    return item_combo_box_type()


__all__ = [
  'GtkPresenter',
]

for name, class_ in inspect.getmembers(sys.modules[__name__], inspect.isclass):
  if issubclass(class_, GtkPresenter) and class_ is not GtkPresenter:
    __all__.append(name)
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   