Dock Area Example
This example demonstrates the use of the advanced DockArea widget.
The DockArea widget provides a canvas into which DockItems can be docked and undocked at will. The layout configuration of the area can be saved and restored using a layout object which can be easily pickled.
Screenshot

Example Enaml Code
#------------------------------------------------------------------------------
# Copyright (c) 2013-2024, Nucleic Development Team
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
#------------------------------------------------------------------------------
""" This example demonstrates the use of the advanced DockArea widget.
The DockArea widget provides a canvas into which DockItems can be docked
and undocked at will. The layout configuration of the area can be saved
and restored using a layout object which can be easily pickled.
<< autodoc-me >>
"""
import pickle
from atom.api import Atom, ContainerList, Str
from enaml.layout.api import (
HSplitLayout, VSplitLayout, TabLayout, InsertItem, hbox, vbox, spacer
)
from enaml.stdlib.dock_area_styles import available_styles
from enaml.stdlib.message_box import question
from enaml.widgets.api import (
Window, Container, DockArea, DockItem, PushButton, Field, Html, Slider,
ObjectCombo, CheckBox, MultilineField
)
def cap_case(name):
return ' '.join(s.capitalize() for s in name.split('-'))
def confirm_close(window, event):
button = question(
window, 'Dock item closing', 'Are you sure you want to close this dock item?'
)
if button and button.action == 'accept':
event.accept()
else:
event.ignore()
class LineCollector(Atom):
""" A simple class used to generate event logging text.
"""
#: The header to use as the first lines of the text.
HEADER = '# Item Event Type \n'\
'-----------------------------------'
#: The output text of the collector; updated when data changes.
text = Str(HEADER)
#: The data for the collector. This is a list of 2-tuples of
#: the form (str, DockItemEvent.Type).
data = ContainerList()
def _observe_data(self, change):
self.update_text()
def update_text(self):
""" Regenerate the output text from the current data.
"""
parts = []
count = len(self.data)
for index, (evt_type, name) in enumerate(reversed(self.data)):
parts.append((count - index, evt_type, name))
lines = [self.HEADER]
for item in parts:
num, name, enum = item
line = '{0!s: <4}{1: <9}{2: <19}'.format(num, name, enum.name)
lines.append(line)
self.text = '\n'.join(lines)
enamldef MyDockArea(DockArea):
layout = HSplitLayout(
VSplitLayout(
HSplitLayout(
VSplitLayout('item_1', 'item_3'),
'item_4',
),
'logger',
),
VSplitLayout(
TabLayout('item_6', 'item_7', 'item_8', 'item_9'),
'item_5',
'item_2',
),
)
DockItem:
name = 'item_1'
title = 'Item 1'
Container:
Field: pass
Field: pass
Field: pass
closing ::
confirm_close(self, change['value'])
DockItem:
name = 'item_2'
title = 'Item 2'
Container:
PushButton: text = 'foo'
PushButton: text = 'bar'
PushButton: text = 'baz'
DockItem:
name = 'item_3'
title = 'Item 3'
Container:
Html: source = '<h1><center>Hello World!</center></h1>'
DockItem:
name = 'item_4'
title = 'Item 4'
Container:
Html: source = '<h1><center>Hello Enaml!</center></h1>'
DockItem:
name = 'item_5'
title = 'Item 5'
Container:
Slider: pass
Slider: pass
Slider: pass
DockItem:
name = 'item_6'
title = 'Item 6'
Container:
Html: source = '<h1><center>Guten Tag!</center></h1>'
DockItem:
name = 'item_7'
title = 'Item 7'
Container:
Field: pass
Field: pass
Field: pass
Field: pass
DockItem:
name = 'item_8'
title = 'Item 8'
Container:
PushButton: text = 'spam'
PushButton: text = 'ham'
PushButton: text = 'green'
PushButton: text = 'eggs'
DockItem:
name = 'item_9'
title = 'Item 9'
Container:
Html: source = '<h1><center>Bonjour!</center></h1>'
DockItem:
name = 'logger'
title = 'Logger'
closable = False
Container:
MultilineField:
attr collector = LineCollector()
name = 'line-collector'
text << collector.text
font = '9pt Courier'
read_only = True
enamldef MyItem(DockItem): owner:
Container:
Field: text = owner.name
Field: text = owner.name
Field: text = owner.name
Field: text = owner.name
enamldef Main(Window):
Container:
attr stored = None
padding = (0, 0, 0, 10)
constraints = [
hbox(
vbox(10, save_b, restore_b, add_b, style_c, c_box, spacer),
area,
)
]
PushButton: save_b:
text = 'Save Layout'
clicked ::
layout = area.save_layout()
parent.stored = pickle.dumps(layout, -1)
PushButton: restore_b:
text = 'Restore Layout'
enabled << stored is not None
clicked ::
layout = pickle.loads(stored)
with area.suppress_dock_events():
area.apply_layout(layout)
PushButton: add_b:
text = 'Add Items'
clicked ::
for _ in range(3):
n = (len(area.children) + 1)
name = 'item_%d' % n
title = 'Item %d' % n
item = MyItem(area, name=name, title=title)
op = InsertItem(item=name, target='item_1')
area.update_layout(op)
ObjectCombo: style_c:
items = available_styles()
to_string = cap_case
selected = 'vs-2024'
CheckBox: c_box:
text = 'Enable Dock Events'
checked := area.dock_events_enabled
MyDockArea: area:
style << style_c.selected
dock_event ::
event = change['value']
field = area.find('line-collector')
field.collector.data.append((event.name, event.type))