#! /usr/bin/python
# -*- coding: UTF-8 -*-
"""
 Visual with Variable TK components.
 These elements extend the widgets in Tkinter to include their variables
 in one pythonic object.

 (C) 2012-2014 Martin Süfke
 License: GPLv3 or newer: http://www.gnu.org/licenses/gpl.html
"""
try:
  from ttk import BooleanVar, IntVar, DoubleVar, StringVar
  from ttk import Checkbutton, Label, Scale, Entry, OptionMenu, Text, Frame
except:
  from Tkinter import BooleanVar, IntVar, DoubleVar, StringVar
  from Tkinter import Checkbutton, Label, Scale, Entry, OptionMenu, Text, Frame
#from Tkconstants import *
import types
import io

def _setifunset(d,n,v):
  if not n in d:
    d[n]=v

class Vget():
  @property
  def value(self):
    return self.variable.get()
  def get(self):
    return self.variable.get()

class Vset():
  #TODO: make a setter property on ""value" ?
  def set(self,val):
    self.variable.set(val)

class Vvalue(Vget):
  @property
  def value(self):
    return self.variable.get()
  @value.setter
  def value_setter(self,newvalue):
    return self.variable.set(newvalue)


class VsetFmt(Vset):
  def set(self,msg,*arg):
    #msg = msg
    #if len(arg)>0:
    #  self.variable.set(msg % arg)
    #else:
    Vset.set(self,msg%arg)

class VCheckbutton(Checkbutton,Vget,Vset,Vvalue,Vvalue):
  """Checkbutton with Boolean value"""
  def __init__(self, *arg, **kw):
    # this is an inherited __init__ using "classic" style without super()
    self.variable=BooleanVar(value=kw.pop("value",False))
    _setifunset(kw,"offvalue",False)
    _setifunset(kw,"onvalue",True)
    _setifunset(kw,"variable",self.variable)
    Checkbutton.__init__(self, *arg, **kw)

class VDLabel(Label,Vget,Vset,Vvalue):
  """Label with DoubleVar() Value"""
  def __init__(self, *arg, **kw):
    # this is an inherited __init__ using "classic" style without super()
    self.variable=DoubleVar(value=kw.pop("value",0.0))
    _setifunset(kw,"textvariable",self.variable)
    Label.__init__(self, *arg, **kw)

class VSLabel(Label,Vget,VsetFmt):
  """Label with StringVar() Value"""
  def __init__(self, *arg, **kw):
    # this is an inherited __init__ using "classic" style without super()
    self.variable=StringVar(value=kw.pop("value",""))
    _setifunset(kw,"textvariable",self.variable)
    Label.__init__(self, *arg, **kw)

class VIScale(Scale,Vget,Vset,Vvalue):
  """Scale with IntVar() Value"""
  def __init__(self, *arg, **kw):
    # this is an inherited __init__ using "classic" style without super()
    self.variable=IntVar(value=kw.pop("value",0))
    _setifunset(kw,"variable",self.variable)
    Scale.__init__(self, *arg, **kw)

class VSEntry(Entry,Vget,VsetFmt):
  """Entry with StringVar() Value"""
  def __init__(self, *arg, **kw):
    # this is an inherited __init__ using "classic" style without super()
    self.variable=StringVar(value=kw.pop("value",0))
    _setifunset(kw,"textvariable",self.variable)
    Entry.__init__(self, *arg, **kw)

class VIOptionMenu(OptionMenu,Vget,Vset,Vvalue):
  """OptionMenu with IntVar() Value"""
  def __init__(self, master, *arg, **kw):
    # this is an inherited __init__ using "classic" style without super()
    value=kw.pop("value",0)
    self.variable=IntVar(value=value)
    var=kw.pop("variable",self.variable)
    OptionMenu.__init__(self, master, var, value, *arg, **kw) # this is a mess in TKinter

class VSOptionMenu(OptionMenu,Vget,Vset,Vvalue):
  """OptionMenu with StringVar() Value"""
  def __init__(self, master, *arg, **kw):
    # this is an inherited __init__ using "classic" style without super()
    value=kw.pop("value",0)
    self.variable=StringVar(value=value)
    var=kw.pop("variable",self.variable)
    OptionMenu.__init__(self, master, var, value, *arg, **kw) # this is a mess in TKinter

class VText(Text):
  """A Text widget with a more spohisticated interface"""
  def __init__(self, *arg, **kw):
    Text.__init__(self, *arg, **kw)

  def FromList(self,list):
    """Put all text from list into Text Widget"""
    self.delete('1.0','end')
    for line in list:
      self.insert('end',line+"\n")

  def FromString(self,input):
    """convert input string with line breaks (cr, lf, cr/lf) into Text Widget"""
    sio=io.StringIO(unicode(input))
    self.delete('1.0','end')
    line=sio.readline()
    while ""<line:
      self.insert('end',line)
      line=sio.readline()
    sio.close()

class VGridFrame(Frame):
  """A Frame widget with a more spohisticated grid layout interface"""

  nextCol="col"
  nextRow="row"

  def __init__(self, *arg, **kw):
    self.set_next(kw.pop('next', self.nextCol)) # put in colum or row
    Frame.__init__(self, *arg, **kw)
    self._col=0  # next position to grid into
    self._row=0
    self._sticky=None # no stickyness

  def colconfig(self,**kw):
    """Apply columnconfigure() to the current column.
    Usually used before grid_next()"""
    self.columnconfigure(self._col,**kw)

  def rowconfig(self,**kw):
    """Apply rowconfigure() to the current row.
    Usually used before grid_next()"""
    self.rowconfigure(self._row,**kw)

  def set_next(self,next):
    """set next step direction to 'col' or 'row'"""
    if next:
      if next == self.nextCol:
        self._next=self.nextCol
      elif next == self.nextRow:
        self._next=self.nextRow
      else:
        assert False, "Need next='%s' or next='%s' but got %s"%(self.nextCol,self.nextRow,next)

  def grid_next(self,widget_or_list,**kw):
    """apply widget.grid() with increasing colum= or row= values
    grid_next( (A, B, ..), opt) is a shortcurt for
    grid_next( A, opt)
    grid_next( B, opt)
    grid_next( .., opt)
    """

    def _grid(widget):
      widget.grid(column=self._col, row=self._row, **kw)
      if self._next == self.nextCol:
        self._col+=colinc
      elif self._next == self.nextRow:
        self._row+=rowinc

    self._col=kw.pop('column', self._col)
    self._row=kw.pop('row', self._row)
    colinc=kw.get('columnspan',1)
    rowinc=kw.get('rowspan',1)

    self.set_next(kw.pop('next',None))
    try:
      sticky=kw.pop('sticky')
      self._sticky=sticky # save stickyness for next time
    except KeyError:
      sticky=self._sticky # get last value (may be None if sticky unset)
    if sticky:
      kw['sticky']=sticky

    if isinstance( widget_or_list, (types.TupleType,types.ListType) ):
      for w in widget_or_list:
        _grid(w)
    else:
      _grid(widget_or_list) # is a widget

  def step(self,**kw):
    """ Step a column or a row forward, resetting column or row
    usage:
      step(column=0) resets to column 0, advancing row
      step(row=2) resets to row 2, advancing column
      step(column=3, row=4) sets to coulmn 3 and row 4"""
    col=kw.get("column",None)
    row=kw.get("row",None)
    if col is not None:
      self._col=col
      self._row=row or self._row+1
    elif row is not None:
      self._row=row
      self._col=col or self._col+1
    else:
      assert False, "You need either 'column=...' or 'row=...' in step() %r"%(kw)

## check not running as main
assert '__main__' != __name__ , "You should not run this, but [import] it"

#end;