Skip to content

Commit

Permalink
Merge pull request #17 from nucleic/feature-dock-area
Browse files Browse the repository at this point in the history
Feature dock area
  • Loading branch information
sccolbert committed Apr 25, 2013
2 parents 76c474c + b1bc737 commit 3ed122b
Show file tree
Hide file tree
Showing 34 changed files with 5,367 additions and 3 deletions.
4 changes: 2 additions & 2 deletions enaml/core/object.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from collections import deque
import re

from atom.api import Atom, Str, Value, List, Event
from atom.api import Atom, Unicode, Value, List, Event


def flag_generator():
Expand Down Expand Up @@ -54,7 +54,7 @@ class Object(Atom):
#: in the tree (see . the 'find' method. There is no guarantee of
#: uniqueness for an object `name`. It is left to the developer to
#: choose an appropriate name.
name = Str()
name = Unicode()

#: The read-only property which returns the object parent. This will
#: be an Object or None. Use 'set_parent()' or pass the parent to
Expand Down
4 changes: 3 additions & 1 deletion enaml/layout/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
#
# The full license is in the file COPYING.txt, distributed with this software.
#------------------------------------------------------------------------------
from .dock_layout import (
dockitem, docktabs, docksplit, hdocksplit, vdocksplit, dockarea, docklayout
)
from .layout_helpers import (
align, hbox, vbox, horizontal, vertical, grid, spacer,
)
from .geometry import Box, BoxF, Pos, PosF, Rect, RectF, Size, SizeF

353 changes: 353 additions & 0 deletions enaml/layout/dock_layout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,353 @@
#------------------------------------------------------------------------------
# Copyright (c) 2013, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#------------------------------------------------------------------------------
from atom.api import Atom, Int, Bool, Coerced, Enum, List, Unicode, Value

from .geometry import Rect


class dockitem(Atom):
""" A layout node for declaring a dock layout item.
"""
#: The name of the item referenced in the layout.
name = Unicode()

@classmethod
def from_dict(cls, dct):
""" Create a dockitem from a layout dictionary.
Parameters
----------
dct : dict
A layout dictionary of 'dockitem' type generated by a
previous call to 'as_dict'.
"""
return cls(dct['name'])

def __init__(self, name):
""" Initialize an item.
Parameters
----------
name : unicode
The unicode name of the dock item to include in the layout.
"""
self.name = name

def as_dict(self):
""" Convert the dock item layout into a layout dictionary.
"""
return {'type': 'dockitem', 'name': self.name}


class docktabs(Atom):
""" A layout node for declaring a tabbed layout item.
"""
#: The index of the selected tab.
index = Int(0)

#: The position of the tabs in the widget.
tab_position = Enum('top', 'bottom', 'left', 'right')

#: The child dock item nodes to add to the tab layout.
children = List()

@classmethod
def from_dict(cls, dct):
""" Create a docktabs layout from a layout dictionary.
Parameters
----------
dct : dict
A layout dictionary of 'docktabs' type generated by a
previous call to 'as_dict'.
"""
children = (dockitem.from_dict(d) for d in dct['children'])
self = cls(*children)
self.index = dct['index']
self.tab_position = dct['tab_position']
return self

def __init__(self, *children, **kwargs):
""" Initialize a docktabs layout.
Parameters
----------
*children
The children to add to the layout. The allowed child types
are 'basestring' and 'dockitem'.
**kwargs
Additional configuration data for the layout.
"""
super(docktabs, self).__init__(**kwargs)
valid = []
for child in children:
if isinstance(child, basestring):
child = dockitem(child)
if not isinstance(child, dockitem):
msg = "'s' is an invalid type for a docktabs child"
raise TypeError(msg % type(child).__name__)
valid.append(child)
self.children = valid

def as_dict(self):
""" Convert the docktabs layout into a layout dictionary.
"""
layout = {
'type': 'docktabs',
'index': self.index,
'tab_position': self.tab_position,
'children': [c.as_dict() for c in self.children],
}
return layout


class docksplit(Atom):
""" A layout node for declaring a splitter layout item.
"""
#: The orientation of the splitter.
orientation = Enum('horizontal', 'vertical')

#: The default sizes to apply to the splitter. The length should
#: be equal to the number of children declared for the splitter.
sizes = List(int)

#: The child layout nodes to add to the splitter.
children = List()

@classmethod
def from_dict(cls, dct):
""" Create a split layout from a layout dictionary.
Parameters
----------
dct : dict
A layout dictionary of 'docksplit' type generated by a
previous call to 'as_dict'.
"""
children = []
for child in dct['children']:
t = child['type']
if t == 'dockitem':
c = dockitem.from_dict(child)
elif t == 'docktabs':
c = docktabs.from_dict(child)
elif t == 'docksplit':
c = docksplit.from_dict(child)
else:
raise TypeError("invalid child type '%s'" % t)
children.append(c)
self = cls(*children)
self.sizes = dct['sizes']
self.orientation = dct['orientation']
return self

def __init__(self, *children, **kwargs):
""" Initialize a split layout.
Parameters
----------
*children
The children to add to the layout. The allowed child types
are 'basestring', 'docksplit', 'docktabs', and 'dockitem'.
**kwargs
Additional configuration data for the layout.
"""
super(docksplit, self).__init__(**kwargs)
valid = []
allowed = (docksplit, docktabs, dockitem)
for child in children:
if isinstance(child, basestring):
child = dockitem(child)
if not isinstance(child, allowed):
msg = "'s' is an invalid type for a docksplit child"
raise TypeError(msg % type(child).__name__)
valid.append(child)
self.children = valid

def as_dict(self):
""" Convert the split layout into a layout dictionary.
"""
layout = {
'type': 'docksplit',
'orientation': self.orientation,
'sizes': list(self.sizes),
'children': [c.as_dict() for c in self.children],
}
return layout


def hdocksplit(*args, **kwargs):
""" A convenience function for creating a horizontal docksplit.
"""
kwargs.setdefault('orientation', 'horizontal')
split = docksplit(*args, **kwargs)
return split


def vdocksplit(*args, **kwargs):
""" A convenience function for creating a vertical docksplit.
"""
kwargs.setdefault('orientation', 'vertical')
split = docksplit(*args, **kwargs)
return split


def coerce_rect(value):
""" Coerce a value to a Rect object.
"""
if isinstance(value, (list, tuple)):
return Rect(*value)
msg = "unable to coerce '%s' to a Rect"
raise TypeError(msg % type(value).__name__)


class dockarea(Atom):
""" A layout node for declaring a dock layout area.
"""
#: Whether or not the area is floating.
floating = Bool(False)

#: The geometry to apply to the area if it is floating.
geometry = Coerced(Rect, (-1, -1, -1, -1), coercer=coerce_rect)

#: The child layout node for the area.
child = Value()

@classmethod
def from_dict(cls, dct):
""" Create a dockarea layout from a layout dictionary.
Parameters
----------
dct : dict
A layout dictionary of 'dockarea' type generated by a
previous call to 'as_dict'.
"""
child = dct['child']
t = child['type']
if t == 'dockitem':
c = dockitem.from_dict(child)
elif t == 'docktabs':
c = docktabs.from_dict(child)
elif t == 'docksplit':
c = docksplit.from_dict(child)
else:
raise TypeError("invalid child type '%s'" % t)
self = cls(c)
self.floating = dct['floating']
self.geometry = dct['geometry']
return self

def __init__(self, child, **metadata):
""" Initialize a floatarea.
Parameters
----------
child : basestring, docksplit, docktabs, or dockitem
The primary child layout to use for the float area.
**metadata
Additional configuration data for the layout.
"""
super(dockarea, self).__init__(**metadata)
if isinstance(child, basestring):
child = dockitem(child)
if not isinstance(child, (docksplit, docktabs, dockitem)):
msg = "'s' is an invalid type for an area child"
raise TypeError(msg % type(child).__name__)
self.child = child

def as_dict(self):
""" Convert the area layout into a layout dictionary.
"""
layout = {
'type': 'dockarea',
'floating': self.floating,
'geometry': list(self.geometry),
'child': self.child.as_dict(),
}
return layout


class docklayout(Atom):
""" The toplevel layout node for declaring dock layouts.
"""
#: The child layout areas to use with the dock layout.
children = List()

@classmethod
def from_dict(cls, dct):
""" Create a docklayout from a layout dictionary.
Parameters
----------
dct : dict
A layout dictionary of 'docklayout' type generated by a
previous call to 'as_dict'.
"""
children = [dockarea.from_dict(d) for d in dct['children']]
return cls(*children)

def __init__(self, *children):
""" Initialize a docklayout.
Parameters
----------
*children
The child layout areas to use in the layout. These must
be instances of 'dockarea', only one of which may be a
non-floating area.
"""
valid = []
nonfloating = False
for child in children:
if not isinstance(child, dockarea):
msg = "'s' is an invalid type for a docklayout child"
raise TypeError(msg % type(child).__name__)
if not child.floating:
if nonfloating:
msg = "a docklayout can have at most 1 non-floating "
msg += "dock area"
raise TypeError(msg)
nonfloating = True
valid.append(child)
self.children = valid

def as_dict(self):
""" Convert the dock layout into a layout dictionary.
"""
layout = {
'type': 'docklayout',
'children': [c.as_dict() for c in self.children],
}
return layout
7 changes: 7 additions & 0 deletions enaml/qt/docking/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#------------------------------------------------------------------------------
# Copyright (c) 2013, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#------------------------------------------------------------------------------
Loading

0 comments on commit 3ed122b

Please sign in to comment.