From 3e11f021e7ee96c006c476e5043e9261a00a5eea Mon Sep 17 00:00:00 2001
From: Lasse Fister
Date: Thu, 15 Oct 2015 17:26:10 +0200
Subject: enhanced layer support in glyphView
font wider layer control widget
cleaning up after first round of review #17
fix 2 typos
Place LayerSetWidget controls inside of InspectorWindow
default color swatch is a red diagonal with white background
LayerSetWidget to LayerSetList, changed the superclass as well
remove unused import
---
 Lib/defconQt/LayerSetList.py                       | 135 ++++
 Lib/defconQt/fontView.py                           |   8 +
 Lib/defconQt/glyphView.py                          | 722 +++++++++++++++++----
 Lib/defconQt/icons_db.py                           | 478 +++++++++-----
 Lib/defconQt/icons_db.qrc                          |   1 +
 Lib/defconQt/layerSetList.py                       | 135 ++++
 .../representationFactories/qPainterPathFactory.py |   2 +-
 Lib/defconQt/resources/defaultColor.svg            |  62 ++
 8 files changed, 1249 insertions(+), 294 deletions(-)
 create mode 100644 Lib/defconQt/LayerSetList.py
 create mode 100644 Lib/defconQt/layerSetList.py
 create mode 100644 Lib/defconQt/resources/defaultColor.svg
(limited to 'Lib/defconQt')
diff --git a/Lib/defconQt/LayerSetList.py b/Lib/defconQt/LayerSetList.py
new file mode 100644
index 0000000..b2d3c9f
--- /dev/null
+++ b/Lib/defconQt/LayerSetList.py
@@ -0,0 +1,135 @@
+from PyQt5.QtCore import Qt
+from PyQt5.QtGui import QKeySequence, QColor, QPixmap, QIcon
+from PyQt5.QtWidgets import QWidget, QMenu, QListWidget, QListWidgetItem, \
+                            QAbstractItemView, QVBoxLayout, QAction, QColorDialog
+from defconQt import icons_db
+from defconQt.glyphView import AddLayerDialog
+
+class LayerSetList(QListWidget):
+    def __init__(self, font, parent=None, *args, **kwds):
+        super().__init__(parent, *args, **kwds)
+
+        self._layerSet = font.layers
+
+        self.setDragDropMode(QAbstractItemView.InternalMove)
+
+        model = self.model()
+        model.rowsMoved.connect(self._reordered)
+        self.itemChanged.connect(self._itemChanged)
+
+        self.setContextMenuPolicy(Qt.ActionsContextMenu)
+
+        action = QAction("Add Layer…", self)
+        action.setShortcuts(QKeySequence.New)
+        action.triggered.connect(self._addLayer)
+        self.addAction(action)
+
+        action = QAction("Change &Name", self)
+        action.setShortcuts(QKeySequence('n'))
+        action.triggered.connect(lambda : self.editItem(self.currentItem()))
+        self.addAction(action)
+
+        action = QAction("Change &Color", self)
+        action.setShortcuts(QKeySequence('c'))
+        action.triggered.connect(self._changeColor)
+        self.addAction(action)
+
+        action = QAction("Reset Color to &Default", self)
+        action.setShortcuts(QKeySequence('d'))
+        action.triggered.connect(self._resetColor)
+        self.addAction(action)
+
+        action = QAction("Delete", self)
+        action.setShortcuts(QKeySequence.Delete)
+        action.triggered.connect(self._deleteLayer)
+        self.addAction(action)
+
+        self._layerSet.addObserver(self, '_update', 'LayerSet.Changed')
+
+        self._update()
+
+    def _update(self, *args):
+        index = self.currentRow()
+        while self.count():
+            self.takeItem(self.count()-1)
+        for i, layer in enumerate(self._layerSet):
+            item = self._makeItem(layer)
+            self.addItem(item)
+            if i == index:
+                self.setCurrentItem(item)
+
+    def _makeItem(self, layer):
+        isDefault = layer is self._layerSet.defaultLayer
+        name = layer.name
+        color = layer.color
+        item = QListWidgetItem()
+        item.setText(name)
+        if color:
+            pixmap = QPixmap(100, 100)
+            # change color
+            pixmap.fill(QColor.fromRgbF(*color))
+            icon = QIcon(pixmap)
+        else:
+            icon = QIcon(":/resources/defaultColor.svg")
+        item.setIcon(icon)
+
+        if isDefault:
+            font = item.font()
+            font.setBold(True)
+            item.setFont(font)
+
+        item.setFlags(item.flags() | Qt.ItemIsEditable)
+
+        return item;
+
+    def _getCurrentLayer(self):
+        item = self.currentItem()
+        if not item:
+            return
+        name = item.text()
+        return self._layerSet[name] if name in self._layerSet else None
+
+    def _deleteLayer(self):
+        layer = self._getCurrentLayer()
+        if not layer:
+            return
+
+        if layer is self._layerSet.defaultLayer:
+            # because I think we can't handle a font without a default layer
+            # TODO: try this
+            return
+        del self._layerSet[layer.name];
+
+    def _reordered(self, *args):
+        # get a new layer order
+        newOrder = [self.item(index).text() for index in range(self.count())]
+        self._layerSet.layerOrder = newOrder
+
+    def _itemChanged(self, item):
+        index = self.indexFromItem(item).row()
+        layerName = self._layerSet.layerOrder[index]
+        self._layerSet[layerName].name = item.text()
+
+    def _addLayer(self):
+        newLayerName, ok = AddLayerDialog.getNewLayerName(self)
+        if ok:
+            # this should cause self._layerSetLayerAdded to be executed
+            self._layerSet.newLayer(newLayerName)
+
+    def _changeColor(self):
+        layer = self._getCurrentLayer()
+        if not layer:
+            return
+
+        startColor = layer.color and QColor.fromRgbF(*layer.color) or QColor('limegreen')
+        qcolor = QColorDialog.getColor(startColor, self, options=QColorDialog.ShowAlphaChannel)
+        if not qcolor.isValid():
+            # cancelled
+            return
+        layer.color = qcolor.getRgbF()
+
+    def _resetColor(self):
+        layer = self._getCurrentLayer()
+        if not layer:
+            return
+        layer.color = None
diff --git a/Lib/defconQt/fontView.py b/Lib/defconQt/fontView.py
index 7c83d51..001d2ea 100644
--- a/Lib/defconQt/fontView.py
+++ b/Lib/defconQt/fontView.py
@@ -3,6 +3,7 @@ from defconQt.fontInfo import TabDialog
 from defconQt.glyphCollectionView import GlyphCollectionWidget
 from defconQt.glyphView import MainGfxWindow
 from defconQt.groupsView import GroupsWindow
+from defconQt.layerSetList import LayerSetList
 from defconQt.scriptingWindow import MainScriptingWindow
 from defconQt.objects.defcon import GlyphSet, TFont, TGlyph
 from defconQt.util import platformSpecific
@@ -191,9 +192,16 @@ class InspectorWindow(QWidget):
         transformLayout.addWidget(scaleXYBox, l, 5)
         transformGroup.setLayout(transformLayout)
 
+        layerSetGroup = QGroupBox("Layers", self)
+        layerSetGroup.setFlat(True)
+        layerSetLayout = QGridLayout(self)
+        layerSetLayout.addWidget(LayerSetList(app.currentFont()), 0, 0)
+        layerSetGroup.setLayout(layerSetLayout)
+
         mainLayout = QVBoxLayout()
         mainLayout.addWidget(glyphGroup)
         mainLayout.addWidget(transformGroup)
+        mainLayout.addWidget(layerSetGroup)
         self.setLayout(mainLayout)
 
     def showEvent(self, event):
diff --git a/Lib/defconQt/glyphView.py b/Lib/defconQt/glyphView.py
index c68f188..bd5779f 100644
--- a/Lib/defconQt/glyphView.py
+++ b/Lib/defconQt/glyphView.py
@@ -1,5 +1,6 @@
 from enum import Enum
 from math import copysign
+from functools import partial
 import pickle
 from defcon import Anchor, Component
 from defconQt import icons_db
@@ -8,7 +9,7 @@ from defconQt.pens.copySelectionPen import CopySelectionPen
 from defconQt.util import platformSpecific
 from fontTools.misc import bezierTools
 from PyQt5.QtCore import *#QFile, QLineF, QObject, QPointF, QRectF, QSize, Qt
-from PyQt5.QtGui import *#QBrush, QColor, QImage, QKeySequence, QPainter, QPainterPath, QPixmap, QPen
+from PyQt5.QtGui import *#QBrush, QColor, QImage, QKeySequence, QPainter, QPainterPath, QPixmap, QPen, QColorDialog
 from PyQt5.QtWidgets import *#(QAction, QActionGroup, QApplication, QFileDialog,
         #QGraphicsItem, QGraphicsEllipseItem, QGraphicsLineItem, QGraphicsPathItem, QGraphicsRectItem, QGraphicsScene, QGraphicsView,
         #QMainWindow, QMenu, QMessageBox, QStyle, QStyleOptionGraphicsItem, QWidget)
@@ -170,13 +171,116 @@ class AddLayerDialog(QDialog):
         name = dialog.layerNameEdit.text()
         return (name, result)
 
+
+class GenericSettings(object):
+    def __init__(self, title, parent, callback):
+        #super().__init__()
+        self._menuWidget = QMenu(title, parent)
+        self._actions = {}
+        self._callback = callback
+        for key, item in self._items:
+            self._addAction(key, *item)
+
+        if(self._presets):
+            self._menuWidget.addSeparator()
+            for i, presets in enumerate(self._presets):
+                self._addPresetAction(i, *presets)
+
+    _items = {}
+    _presets = tuple()
+
+    @property
+    def menuWidget(self):
+        return self._menuWidget
+
+    def _addAction(self, key, label, checked):
+        action = self._menuWidget.addAction(label, partial(self._callback, key))
+        action.setCheckable(True)
+        action.setChecked(checked)
+        self._actions[key] = action
+
+    def _addPresetAction(self, index, label, presets, **args):
+        self._menuWidget.addAction(label, partial(self._setPreset, index))
+
+    def _setPreset(self, index):
+        _, data = self._presets[index]
+        for key, value in data.items():
+            action = self._actions[key]
+            action.blockSignals(True)
+            action.setChecked(value)
+            action.blockSignals(False)
+        self._callback()
+
+    def __setattr__(self, name, value):
+        if name.startswith('_'):
+            self.__dict__[name] = value
+            return
+        raise AttributeError('It\'s not allowed to set attributes here.', name)
+
+    def __getattr__(self, name):
+        if name.startswith('_'):
+            raise AttributeError(name)
+        if name not in self._actions:
+            raise AttributeError(name)
+        return self._actions[name].isChecked()
+
+
+
+class DisplayStyleSettings(GenericSettings):
+    _presets = (
+        ('TruFont Default', dict(
+            activeLayerOnTop = True
+          , activeLayerFilled = True
+          , otherLayersFilled = False
+          , activeLayerUseLayerColor = False
+          , otherLayerUseLayerColor = True
+          , drawOtherLayers = True
+        ))
+      , ('Layer Fonts', dict(
+            activeLayerOnTop = False
+          , activeLayerFilled = True
+          , otherLayersFilled = True
+          , activeLayerUseLayerColor = True
+          , otherLayerUseLayerColor = True
+          , drawOtherLayers = True
+        ))
+    )
+
+    _items = (
+        ('activeLayerOnTop', ('Active Layer on Top', True))
+      , ('activeLayerFilled', ('Active Layer Filled', True))
+      , ('activeLayerUseLayerColor', ('Active Layer use Custom Color', False))
+      , ('otherLayersFilled', ('Other Layers Filled', False))
+      , ('otherLayerUseLayerColor', ('Other Layers use Custom Color', True))
+      , ('drawOtherLayers', ('Show Other Layers', True))
+    )
+
+
 class MainGfxWindow(QMainWindow):
     def __init__(self, glyph, parent=None):
         super(MainGfxWindow, self).__init__(parent)
         self.setAttribute(Qt.WA_DeleteOnClose)
         self.setAttribute(Qt.WA_KeyCompression)
 
-        self.view = GlyphView(glyph, self)
+        self.view = None
+
+        self._layerSet = layerSet = glyph.layerSet
+
+        self._layerSetNotifications = []
+
+        layerSet.addObserver(self, '_layerSetLayerAdded', 'LayerSet.LayerAdded')
+        layerSet.addObserver(self, '_layerSetLayerDeleted', 'LayerSet.LayerDeleted')
+        self._layerSetNotifications.append('LayerSet.LayerAdded')
+        self._layerSetNotifications.append('LayerSet.LayerDeleted')
+
+
+        for event in ('LayerSet.LayerChanged', 'LayerSet.DefaultLayerChanged'
+                                            , 'LayerSet.LayerOrderChanged'):
+            self._layerSetNotifications.append(event)
+            layerSet.addObserver(self, '_layerSetEvents',  event)
+
+
+
         menuBar = self.menuBar()
 
         fileMenu = QMenu("&File", self)
@@ -187,27 +291,39 @@ class MainGfxWindow(QMainWindow):
         glyphMenu.addAction("&Jump", self.changeGlyph, "J")
         menuBar.addMenu(glyphMenu)
 
-        toolBar = QToolBar(self)
+
+        self._displaySettings = DisplayStyleSettings("&Display", self, self._displayChanged)
+        menuBar.addMenu(self._displaySettings.menuWidget)
+
+        self._toolBar = toolBar = QToolBar(self)
         toolBar.setMovable(False)
         toolBar.setContentsMargins(2, 0, 2, 0)
-        selectionToolButton = toolBar.addAction("Selection", self.view.setSceneSelection)
+        selectionToolButton = toolBar.addAction("Selection", self._redirect('view', 'setSceneSelection'))
         selectionToolButton.setCheckable(True)
         selectionToolButton.setChecked(True)
         selectionToolButton.setIcon(QIcon(":/resources/cursor.svg"))
-        penToolButton = toolBar.addAction("Pen", self.view.setSceneDrawing)
+        penToolButton = toolBar.addAction("Pen", self._redirect('view', 'setSceneDrawing'))
         penToolButton.setCheckable(True)
         penToolButton.setIcon(QIcon(":/resources/curve.svg"))
-        rulerToolButton = toolBar.addAction("Ruler", self.view.setSceneRuler)
+        rulerToolButton = toolBar.addAction("Ruler", self._redirect('view', 'setSceneRuler'))
         rulerToolButton.setCheckable(True)
         rulerToolButton.setIcon(QIcon(":/resources/ruler.svg"))
-        knifeToolButton = toolBar.addAction("Knife", self.view.setSceneKnife)
+        knifeToolButton = toolBar.addAction("Knife", self._redirect('view', 'setSceneKnife'))
         knifeToolButton.setCheckable(True)
         knifeToolButton.setIcon(QIcon(":/resources/cut.svg"))
+
         # http://www.setnode.com/blog/right-aligning-a-button-in-a-qtoolbar/
         spacer = QWidget()
         spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
         toolBar.addWidget(spacer)
-        toolBar.addWidget(self.view.currentLayerBox())
+        self._currentLayerBox = QComboBox(self)
+        self._currentLayerBox.currentIndexChanged.connect(self._changeLayerHandler)
+        toolBar.addWidget(self._currentLayerBox)
+
+        self._layerColorButton = toolBar.addAction(
+                    "Layer Color (shift + click to remove the color)",
+                    self._chooseLayerColor)
+
         toolsGroup = QActionGroup(self)
         toolsGroup.addAction(selectionToolButton)
         toolsGroup.addAction(penToolButton)
@@ -217,21 +333,177 @@ class MainGfxWindow(QMainWindow):
 
         self.setContextMenuPolicy(Qt.ActionsContextMenu)
         createAnchorAction = QAction("Add Anchor…", self)
-        createAnchorAction.triggered.connect(self.view.createAnchor)
+        createAnchorAction.triggered.connect(self._redirect('view', 'createAnchor'))
         self.addAction(createAnchorAction)
         createComponentAction = QAction("Add Component…", self)
-        createComponentAction.triggered.connect(self.view.createComponent)
+        createComponentAction.triggered.connect(self._redirect('view', 'createComponent'))
         self.addAction(createComponentAction)
 
-        self.setCentralWidget(self.view)
+        for layer in self._layerSet:
+            self._listenToLayer(layer)
+
+        self._changeGlyph(glyph)
+        self._updateComboBox()
+
         self.setWindowTitle(glyph.name, glyph.getParent())
         self.adjustSize()
 
+    def _changeGlyph(self, glyph):
+        oldView = self.view
+        if oldView:
+            # Preserve the selected layer (by setting the glyph from that layer)
+            # Todo: If that layer is already in the glyph, it would be a little bit
+            # harder to create it here and may be better or worse. Worse becaue
+            # we'd alter the data without being explicitly asked to do so.
+            # Ask someone who does UX.
+            if oldView.layer is not glyph.layer and glyph.name in oldView.layer:
+                glyph = oldView.layer[glyph.name]
+            oldView.hide()
+            oldView.deleteLater()
+
+        self.view = GlyphView(glyph, self._displaySettings, self)
+        # Preserve the zoom level of the oldView.
+        # TODO: is there more state that we need to carry over to the next
+        # GlyphView? If yes, we should make an interface for a
+        # predecessor -> successor transformation
+        if oldView:
+            self.view.setTransform(oldView.transform())
+
+        self._setlayerColorButtonColor()
+
+        app = QApplication.instance()
+        app.setCurrentGlyph(glyph)
+        self.setWindowTitle(glyph.name, glyph.getParent())
+
+        # switch
+        self.setCentralWidget(self.view)
+
+    def _executeRemoteCommand(self, targetName, commandName, *args, **kwds):
+        """
+        Execute a method named `commandName` on the attribute named `targetName`.
+        This strongly suggest that there is always a known interface at self.{targetName}
+        See MainGfxWindow._redirect
+        """
+        target = getattr(self, targetName)
+        command = getattr(target, commandName)
+        command(*args, **kwds)
+
+    def _redirect(self, target, command):
+        """
+        This creates an indirection to permanently connect an event to a
+        property that may (will) change its identity.
+        """
+        return partial(self._executeRemoteCommand, target, command)
+
+    def _layerSetEvents(self, notification):
+        layerSet = notification.object
+        assert layerSet is self._layerSet
+        self._updateComboBox()
+
+
+    def _layerSetLayerDeleted(self, notification):
+        self._layerSetEvents(notification)
+        self._changeLayerHandler(0)
+
+    def _layerSetLayerAdded(self, notification):
+        self._layerSetEvents(notification)
+        layerName = notification.data['name']
+        layer = self._layerSet[layerName]
+        self.view.layerAdded(layer)
+        self._listenToLayer(layer)
+
+    def _listenToLayer(self, layer, remove=False):
+        if remove:
+            layer.removeObserver(self, 'Layer.ColorChanged')
+        else:
+            layer.addObserver(self, '_layerColorChange', 'Layer.ColorChanged')
+
+    def _chooseLayerColor(self):
+        if QApplication.keyboardModifiers() & Qt.ShiftModifier:
+            # reset to default color, i.e. delete the layer color
+            color = None
+        else:
+            startColor = self.view.getLayerColor() or QColor('limegreen')
+            qColor = QColorDialog.getColor(startColor, self, options=QColorDialog.ShowAlphaChannel)
+            if not qColor.isValid():
+                # cancelled
+                return
+            color = qColor.getRgbF()
+        # will trigger Layer.ColorChanged
+        self.view.layer.color = color
+
+    def _layerColorChange(self, notification):
+        layer = notification.object
+        if layer is self.view.layer:
+            self._setlayerColorButtonColor()
+
+    def _setlayerColorButtonColor(self):
+        color = self.view.getLayerColor()
+        if color is None:
+            icon = QIcon(":/resources/defaultColor.svg")
+        else:
+            # set the layer color to the button
+            pixmap = QPixmap(100, 100)
+            pixmap.fill(color)
+            icon = QIcon(pixmap)
+        self._layerColorButton.setIcon(icon)
+
+    def _updateComboBox(self):
+        comboBox = self._currentLayerBox
+        comboBox.blockSignals(True)
+        comboBox.clear()
+        for layer in self._layerSet:
+            comboBox.addItem(layer.name, layer)
+            if layer == self.view.layer:
+                comboBox.setCurrentText(layer.name)
+                continue
+        comboBox.addItem("New layer...", None)
+        comboBox.blockSignals(False)
+
+    def _setComboboxIndex(self, index):
+        comboBox = self._currentLayerBox
+        comboBox.blockSignals(True)
+        comboBox.setCurrentIndex(index)
+        comboBox.blockSignals(False)
+
+    def _makeNewLayerViaDialog(self):
+        newLayerName, ok = AddLayerDialog.getNewLayerName(self)
+        if ok:
+            # this should cause self._layerSetLayerAdded to be executed
+            self._layerSet.newLayer(newLayerName)
+            return self._layerSet[newLayerName]
+        else:
+            return None
+
+    def _changeLayerHandler(self, newLayerIndex):
+        comboBox = self._currentLayerBox
+        layer = comboBox.itemData(newLayerIndex)
+        if layer is None:
+            layer = self._makeNewLayerViaDialog()
+            if layer is None:
+                # restore comboBox to active index
+                index = self._layerSet.layerOrder.index(self.view.layer.name)
+                self._setComboboxIndex(index)
+                return
+
+        self.view.changeCurrentLayer(layer)
+        self._updateComboBox()
+        self._setlayerColorButtonColor()
+
+        app = QApplication.instance()
+        # setting the layer-glyph here
+        app.setCurrentGlyph(self.view._glyph)
+
     def changeGlyph(self):
         glyph = self.view._glyph
         newGlyph, ok = GotoDialog.getNewGlyph(self, glyph)
         if ok and newGlyph is not None:
-            self.view.setGlyph(newGlyph)
+            self._changeGlyph(newGlyph)
+            self._updateComboBox()
+
+    def _displayChanged(self, *args):
+        # redraw the view
+        self.view.redraw()
 
     def event(self, event):
         if event.type() == QEvent.WindowActivate:
@@ -240,11 +512,15 @@ class MainGfxWindow(QMainWindow):
         return super(MainGfxWindow, self).event(event)
 
     def closeEvent(self, event):
-        self.view._glyph.removeObserver(self, "Glyph.Changed")
-        event.accept()
+        for name in self._layerSetNotifications:
+            self._layerSet.removeObserver(self, name)
 
-    def _glyphChanged(self, notification):
-        self.view._glyphChanged(notification)
+        for layer in self._layerSet:
+            self._listenToLayer(layer, remove=True)
+
+        self.view = None
+
+        event.accept()
 
     def setWindowTitle(self, title, font=None):
         if font is not None: title = "%s – %s %s" % (title, font.info.familyName, font.info.styleName)
@@ -677,7 +953,6 @@ class ComponentItem(QGraphicsPathItem):
         super(ComponentItem, self).__init__(path, parent)
         self._component = component
         self.setTransform(QTransform(*component.transformation))
-        self.setBrush(QBrush(componentFillColor))
         self.setFlag(QGraphicsItem.ItemIsMovable)
         self.setFlag(QGraphicsItem.ItemIsSelectable)
         self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
@@ -784,7 +1059,7 @@ class PixmapItem(QGraphicsPixmapItem):
         return value
 
 class GlyphScene(QGraphicsScene):
-    def __init__(self, parent):
+    def __init__(self, parent, sceneAddedItems=None):
         super(GlyphScene, self).__init__(parent)
         self._editing = False
         self._integerPlane = True
@@ -796,6 +1071,10 @@ class GlyphScene(QGraphicsScene):
         self._dataForUndo = []
         self._dataForRedo = []
 
+        # if this is an array, the Glyphview will clean up all contents
+        # when redrawing the active layer
+        self._sceneAddedItems = sceneAddedItems
+
         font = self.font()
         font.setFamily("Roboto Mono")
         font.setFixedPitch(True)
@@ -809,6 +1088,12 @@ class GlyphScene(QGraphicsScene):
 
     _glyphObject = property(_get_glyphObject, doc="Get the current glyph in the view.")
 
+    def _addRegisterItem(self, item):
+        """The parent object will take care of removing these again"""
+        if self._sceneAddedItems is not None:
+            self._sceneAddedItems.append(item)
+        self.addItem(item)
+
     def dragEnterEvent(self, event):
         if event.mimeData().hasUrls():
             event.acceptProposedAction()
@@ -832,7 +1117,7 @@ class GlyphScene(QGraphicsScene):
             return
         pos = event.scenePos()
         newPix = PixmapItem(pos.x(), pos.y(), dragPix)
-        self.addItem(newPix)
+        self._addRegisterItem(newPix)
         event.acceptProposedAction()
 
     def getItemForPoint(self, point):
@@ -1023,7 +1308,7 @@ class GlyphScene(QGraphicsScene):
                 else:
                     lastContour.addPoint((x,y), "line")
                 item = OnCurvePointItem(x, y, False, lastContour, lastContour[-1], self.getViewScale())
-                self.addItem(item)
+                self._addRegisterItem(item)
                 for _ in range(2):
                     lineObj = HandleLineItem(0, 0, 0, 0, item)
                     CPObject = OffCurvePointItem(0, 0, item)
@@ -1038,7 +1323,7 @@ class GlyphScene(QGraphicsScene):
             nextC.addPoint((x,y), "move")
 
             item = OnCurvePointItem(x, y, False, self._glyphObject[-1], self._glyphObject[-1][-1], self.getViewScale())
-            self.addItem(item)
+            self._addRegisterItem(item)
             for _ in range(2):
                 lineObj = HandleLineItem(0, 0, 0, 0, item)
                 CPObject = OffCurvePointItem(0, 0, item)
@@ -1341,17 +1626,30 @@ class GlyphScene(QGraphicsScene):
         self._cachedIntersections = []
         event.accept()
 
+
 class GlyphView(QGraphicsView):
-    def __init__(self, glyph, parent=None):
+    def __init__(self, glyph, settings, parent=None):
         super(GlyphView, self).__init__(parent)
-        self._glyph = glyph
-        self._glyph.addObserver(self, "_glyphChanged", "Glyph.Changed")
-        self._glyph.layerSet.addObserver(self, "_layersChanged", "LayerSet.Changed")
+
+        # wont change during lifetime
+        self._layerSet = layerSet = glyph.layerSet
+        self._name = glyph.name
+        self._settings = settings
+
+        # we got the individual layers as keys => pathItem
+        # we got string keys => [list of scene items] like 'components'
+        self._sceneItems = {}
+
+        # will change during lifetime
+        self._layer = glyph.layer
+
         self._impliedPointSize = 1000
         self._pointSize = None
 
+        # apparently unused code
         self._inverseScale = 0.1
         self._scale = 10
+
         self._noPointSizePadding = 200
         self._drawStroke = True
         self._showOffCurvePoints = True
@@ -1359,15 +1657,12 @@ class GlyphView(QGraphicsView):
         self._showMetricsTitles = True
 
         self.setBackgroundBrush(QBrush(Qt.lightGray))
-        self.setScene(GlyphScene(self))
+        self.setScene(GlyphScene(self, self._getSceneItems('scene-added-items')))
         font = self.font()
         font.setFamily("Roboto Mono")
         font.setFixedPitch(True)
         self.setFont(font)
 
-        self._currentLayerBox = QComboBox(self)
-        self._currentLayerBox.currentIndexChanged.connect(self._currentLayerChanged)
-
         self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
         self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
         #self.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate)
@@ -1380,53 +1675,117 @@ class GlyphView(QGraphicsView):
         self.addBackground()
         self.addBlues()
         self.addHorizontalMetrics()
-        self.addOtherLayersOutlines()
-        self.addOutlines()
-        self.addComponents()
-        self.addAnchors()
-        self.addPoints()
 
-    def currentLayerBox(self):
-        return self._currentLayerBox
+        for layer in layerSet:
+            if self._name not in layer:
+                self._listenToLayer(layer)
+            else:
+                self._listenToGlyph(layer)
+        self._listenToLayerSet()
+
+        self.changeCurrentLayer(self._layer)
+
+
+    @property
+    def _glyph(self):
+        # instead of a getter we could change the glyph each time
+        # self._layer is changed. However, it might be that the glyph
+        # is not ready when the layer is set
+        return self._layer[self._name]
+
+    @property
+    def name(self):
+        return self._name
+
+    @property
+    def layer(self):
+        return self._layer
+
+    @property
+    def defaultWidth(self):
+        defaultLayer = self._layerSet[None]
+        return defaultLayer[self._name].width \
+                                    if self._name in defaultLayer else 0
+
+    def _listenToLayerSet(self):
+        self._layerSet.addObserver(self, '_layerDeleted', 'LayerSet.LayerWillBeDeleted')
+        self._layerSet.addObserver(self, '_layerGenericVisualChange', 'LayerSet.LayerOrderChanged')
+
+    def _listenToLayer(self, layer, remove=False):
+        if remove:
+            layer.removeObserver(self, 'Layer.GlyphAdded')
+        else:
+            layer.addObserver(self, '_layerGlyphAdded', 'Layer.GlyphAdded')
+
+    def _layerGenericVisualChange(self, notification):
+        self.redraw()
+
+    def _listenToGlyph(self, layer):
+        layer[self._name].addObserver(self, "_glyphChanged", "Glyph.Changed")
+        layer.addObserver(self, '_layerGenericVisualChange', 'Layer.ColorChanged')
+
+    def layerAdded(self, layer):
+        self._listenToLayer(layer)
+
+    def _layerGlyphAdded(self, notification):
+        glyphName = notification.data['name']
+        # the layer will emit this for each new glyph
+        if glyphName != self._name:
+            return
+        layer = notification.object
+        self._listenToLayer(layer, remove=True)
+        self._listenToGlyph(layer)
+        self.redraw()
+
+    def _layerDeleted(self, notification):
+        layerName = notification.data['name']
+        layer = self._layerSet[layerName]
+        self._removeLayerPath(layer)
 
     def _glyphChanged(self, notification):
         # TODO: maybe detect sidebearing changes (space center) and then only
         # translate elements rather than reconstructing them.
         # Also we lose selection when reconstructing, rf does not when changing
         # sp.center values.
-        self.redrawGlyph()
+        glyph = notification.object
+        layer = glyph.layer
+        if layer is self._layer:
+            self.activeGlyphChanged()
+        else:
+            self.updateLayerPath(layer)
+
+    def redraw(self):
+        self._getSceneItems('scene-added-items', clear=True)
+        self.updateLayerAssets()
+        self.drawAllLayers()
+        self.addAnchors()
+        self.addPoints()
 
-    # TODO: diagnose notifications count
-    def _layersChanged(self, notification):
-        self.redrawGlyph()
-        self.redrawOtherLayers()
+    def updateLayerAssets(self):
+        for item in self._getSceneItems('hMetricLabels'):
+            item.setPos(self._glyph.width, item.y())
 
-    def redrawGlyph(self):
-        path = self._glyph.getRepresentation("defconQt.NoComponentsQPainterPath")
+    def activeGlyphChanged(self):
+        # For now, we'll assume not scene._blocked == moving UI points
+        # this will not be the case anymore when drag sidebearings pops up
         scene = self.scene()
-        scene._outlineItem.setPath(path)
-        if not scene._blocked:
-            # TODO: also rewind anchors and components
-            for item in scene.items():
-                if isinstance(item, (OnCurvePointItem, ComponentItem, AnchorItem)):
-                    scene.removeItem(item)
-                elif isinstance(item, VGuidelinesTextItem):
-                    item.setPos(self._glyph.width, item.y())
+        if scene._blocked:
+            self.updateActiveLayerPath()
+            return
+        self.updateActiveLayer()
 
-            self.addComponents()
-            self.addAnchors()
-            self.addPoints()
-            # For now, we'll assume not scene._blocked == moving UI points
-            # this will not be the case anymore when drag sidebearings pops up
-            scene._widthItem.setRect(0, -1000, self._glyph.width, 3000)
+    def updateActiveLayer(self):
+        self._getSceneItems('scene-added-items', clear=True)
+        self.updateLayerAssets()
+
+        self.updateActiveLayerPath()
+        self.addComponents()
+        self.addAnchors()
+        self.addPoints()
 
-    def redrawOtherLayers(self):
+        # this is related to addBackground
         scene = self.scene()
-        for item in scene.items():
-            # XXX: discriminate better
-            if isinstance(item, QGraphicsPathItem) and item.zValue() == -997:
-                scene.removeItem(item)
-        self.addOtherLayersOutlines()
+        scene._widthItem.setRect(0, -1000, self._glyph.width, 3000)
 
     def addBackground(self):
         scene = self.scene()
@@ -1486,6 +1845,9 @@ class GlyphView(QGraphicsView):
             y = roundPosition(position)
             item = scene.addLine(-1000, y, 2000, y, QPen(metricsColor))
             item.setZValue(-997)
+
+
+        labels = self._getSceneItems('hMetricLabels', clear=True)
         # text
         if self._showMetricsTitles:# and self._impliedPointSize > 150:
             fontSize = 9# * self._inverseScale
@@ -1500,56 +1862,164 @@ class GlyphView(QGraphicsView):
                 item.setFlag(QGraphicsItem.ItemIgnoresTransformations)
                 item.setPos(width, y)
                 item.setZValue(-997)
+                labels.append(item)
                 scene.addItem(item)
 
-    def addOtherLayersOutlines(self):
-        comboBox = self._currentLayerBox
-        comboBox.blockSignals(True)
-        comboBox.clear()
-        scene = self.scene()
-        layerSet = self._glyph.layerSet
-        for layer in layerSet:
-            comboBox.addItem(layer.name, layer)
-            if layer == self._glyph.layer:
-                comboBox.setCurrentText(layer.name)
+    def getLayerColor(self, layer=None):
+        if layer is None:
+            layer = self._layer
+        if layer.color is not None:
+            return QColor.fromRgbF(*layer.color)
+        return None
+
+
+    def _getDrawingStyleForLayer(self, layer, kind=None):
+        isActive = layer is self._layer
+        isFilled = self._settings.activeLayerFilled \
+                    if isActive else self._settings.otherLayersFilled
+        isOutlined = not isFilled
+        useLayerColor = self._settings.activeLayerUseLayerColor \
+                    if isActive else self._settings.otherLayerUseLayerColor
+
+        if useLayerColor:
+            brushcolor = self.getLayerColor(layer) or Qt.black
+            pencolor = brushcolor
+        else:
+            # default app colors
+            brushcolor = fillColor if kind != 'component' else componentFillColor
+            pencolor = Qt.black
+
+        if isOutlined:
+            pen = QPen(pencolor)
+            brush = QBrush(Qt.NoBrush)
+        else:
+            pen = QPen(Qt.NoPen)
+            brush = QBrush(brushcolor)
+
+        if isActive and not useLayerColor:
+            # The originally released app did fall back to QT's default
+            #  behavior i.e. no pen defined, so I preserve this here
+            if isOutlined: brush = None # like Qt.NoBrush
+            else: pen = None # like Qt.black
+        return (pen, brush)
+
+
+
+    @property
+    def _activeLayerZValue(self):
+        return -995 if not self._settings.activeLayerOnTop else -993
+
+    def drawAllLayers(self):
+        activeLayer = self._layer
+        # all layers before the active layer are -996
+        # the active layer is -995 or -993 if self._settings.activeLayerOnTop == True
+        # all layers after the active layer are -996
+        zValue = -996
+        for layer in reversed(list(self._layerSet)):
+            if self._name not in layer:
                 continue
-            if not self._glyph.name in layer:
+            isActiveLayer = layer is activeLayer
+            if isActiveLayer:
+                zValue = self._activeLayerZValue
+            elif not self._settings.drawOtherLayers:
+                self._removeLayerPath(layer)
                 continue
-            path = layer[self._glyph.name].getRepresentation("defconQt.NoComponentsQPainterPath")
-            if layer.color is not None:
-                layerColor = QColor.fromRgbF(tuple(layer.color))
-            else:
-                layerColor = Qt.black
-            item = scene.addPath(path, QPen(layerColor))
-            item.setZValue(-997)
-        comboBox.addItem("New layer...", None)
-        comboBox.blockSignals(False)
+            self.drawLayer(layer, zValue)
+            if isActiveLayer:
+                zValue = -994
+
+    def _removeLayerPath(self, layer):
+        scene = self.scene()
+        item = self._sceneItems.get(layer, None)
+        if item is not None:
+            scene.removeItem(item)
+        if layer in self._sceneItems:
+            del self._sceneItems[layer]
+
+    def drawLayer(self, layer, zValue):
+        scene = self.scene()
+        glyph = layer[self._name]
+        self._removeLayerPath(layer)
+
+        isActiveLayer = layer is self._layer
+        if isActiveLayer:
+            representationKey = "defconQt.NoComponentsQPainterPath"
+        else:
+            representationKey = "defconQt.QPainterPath"
+
+        path = glyph.getRepresentation(representationKey)
+        item = QGraphicsPathItem()
+        item.setPath(path)
+
+        pen, brush = self._getDrawingStyleForLayer(layer)
+        if pen: item.setPen(pen)
+        if brush: item.setBrush(brush)
+
+        item.setZValue(zValue)
+
+        self._sceneItems[layer] = item
+        scene.addItem(item)
+        if isActiveLayer:
+            # FIXME: don't like this
+            scene._outlineItem = item
+            self.addComponents()
+        return item
 
-    def addOutlines(self):
+    def updateActiveLayerPath(self):
+        self.updateLayerPath(self._layer, representationKey="defconQt.NoComponentsQPainterPath")
+
+    def updateLayerPath(self, layer, representationKey="defconQt.QPainterPath"):
+        glyph = layer[self._name]
         scene = self.scene()
-        path = self._glyph.getRepresentation("defconQt.NoComponentsQPainterPath")
-        scene._outlineItem = scene.addPath(path, brush=QBrush(fillColor))
-        scene._outlineItem.setZValue(-995)
+        path = glyph.getRepresentation(representationKey)
+        self._sceneItems[layer].setPath(path)
+
+    def _getSceneItems(self, key, clear=False):
+        items = self._sceneItems.get(key, None)
+        if items is None:
+            items = []
+            self._sceneItems[key] = items
+        elif clear:
+            scene = self.scene()
+            for item in items:
+                scene.removeItem(item)
+            del items[:]
+        return items
 
     def addComponents(self):
         scene = self.scene()
-        font = self._glyph.getParent()
-        for component in self._glyph.components:
-            glyph = font[component.baseGlyph]
-            path = glyph.getRepresentation("defconQt.QPainterPath")
+        layer = self._layer
+        glyph = self._glyph
+
+        pen, brush = self._getDrawingStyleForLayer(layer, kind='component')
+        components = self._getSceneItems('components', clear=True)
+        for component in glyph.components:
+            if component.baseGlyph not in layer:
+                continue
+            componentGlyph = layer[component.baseGlyph]
+            path = componentGlyph.getRepresentation("defconQt.QPainterPath")
             item = ComponentItem(path, component)
-            item.setZValue(-996)
+            if pen: item.setPen(pen)
+            if brush: item.setBrush(brush)
+            item.setZValue(self._activeLayerZValue)
+            components.append(item)
             scene.addItem(item)
 
     def addAnchors(self):
         scene = self.scene()
+        anchors = self._getSceneItems('anchors', clear=True)
+
         for anchor in self._glyph.anchors:
             item = AnchorItem(anchor, self.transform().m11())
-            item.setZValue(-996)
+            item.setZValue(-992)
+            anchors.append(item)
             scene.addItem(item)
 
     def addPoints(self):
         scene = self.scene()
+
+        pointItems = self._getSceneItems('points', clear=True)
+
         # work out appropriate sizes and
         # skip if the glyph is too small
         pointSize = self._impliedPointSize
@@ -1582,6 +2052,7 @@ class GlyphView(QGraphicsView):
                 points.append((x, y))
                 item = OnCurvePointItem(x, y, onCurve.isSmooth, self._glyph[onCurve.contourIndex],
                     self._glyph[onCurve.contourIndex][onCurve.pointIndex], scale)
+                pointItems.append(item)
                 scene.addItem(item)
                 # off curve
                 for CP in [onCurve.prevCP, onCurve.nextCP]:
@@ -1637,7 +2108,7 @@ class GlyphView(QGraphicsView):
                 self._drawTextAtPoint(text, attributes, (posX, posY), 3)
         '''
 
-    def createAnchor(self):
+    def createAnchor(self, *args):
         scene = self.scene()
         pos = scene._rightClickPos
         if scene._integerPlane:
@@ -1651,51 +2122,42 @@ class GlyphView(QGraphicsView):
             anchor.name = newAnchorName
             self._glyph.appendAnchor(anchor)
 
-    def createComponent(self):
+    def createComponent(self, *args):
         newGlyph, ok = AddComponentDialog.getNewGlyph(self, self._glyph)
         if ok and newGlyph is not None:
             component = Component()
             component.baseGlyph = newGlyph.name
             self._glyph.appendComponent(component)
 
-    def _currentLayerChanged(self, newLayerIndex):
-        comboBox = self.sender()
-        newLayer = comboBox.itemData(newLayerIndex)
-        if newLayer is None:
-            # add a new layer
-            newLayerName, ok = AddLayerDialog.getNewLayerName(self)
-            if ok:
-                self._glyph.layerSet.newLayer(newLayerName)
-                self._currentLayerBox.blockSignals(True)
-                self._currentLayerBox.setCurrentText(newLayerName)
-                self._currentLayerBox.blockSignals(False)
-                newLayer = self._glyph.layerSet[newLayerName]
-            else:
-                return
-        if not self._glyph.name in newLayer:
-            newLayer.newGlyph(self._glyph.name)
-            # TODO: generalize this out, can’t use newStandardGlyph unfortunately
-            newLayer[self._glyph.name].width = self._glyph.width
-            newLayer[self._glyph.name].template = True
-        newGlyph = newLayer[self._glyph.name]
-        self.setGlyph(newGlyph)
-
-    def setGlyph(self, glyph):
+    def _makeLayerGlyph(self, layer):
+        name = self._name
+        layer.newGlyph(name)
+        glyph = layer[name]
+        # TODO: generalize this out, can’t use newStandardGlyph unfortunately
+        glyph.width = self.defaultWidth
+
+        # This prevents the empty glyph from being saved.
+        # TGlyph sets it to False when the glyph is marked as dirty
+        glyph.template = True
+        return glyph
+
+    def changeCurrentLayer(self, layer):
+        name = self._name
+
+        # set current layer
+        self._layer = layer
+
+        if name in layer:
+            # please redraw
+            self.redraw()
+        else:
+            # no need to redraw, will happen within _layerGlyphAdded
+            self._makeLayerGlyph(layer)
+
+        # TODO: Undo data does not keep track of different layers
         scene = self.scene()
-        self._glyph.removeObserver(self, "Glyph.Changed")
-        self._glyph.layerSet.removeObserver(self, "LayerSet.Changed")
-        # TODO: consider creating a new scene instead of zeroing things out
-        # manually
         scene._dataForUndo = []
         scene._dataForRedo = []
-        self._glyph = glyph
-        app = QApplication.instance()
-        app.setCurrentGlyph(glyph)
-        self._glyph.addObserver(self, "_glyphChanged", "Glyph.Changed")
-        self._glyph.layerSet.addObserver(self, "_layersChanged", "LayerSet.Changed")
-        self.parent().setWindowTitle(self._glyph.name, self._glyph.getParent())
-        self.redrawGlyph()
-        self.redrawOtherLayers()
 
     def showEvent(self, event):
         super(GlyphView, self).showEvent(event)
diff --git a/Lib/defconQt/icons_db.py b/Lib/defconQt/icons_db.py
index f9475a6..ac51125 100644
--- a/Lib/defconQt/icons_db.py
+++ b/Lib/defconQt/icons_db.py
@@ -2,13 +2,306 @@
 
 # Resource object code
 #
-# Created by: The Resource Compiler for PyQt5 (Qt v5.3.0)
+# Created by: The Resource Compiler for PyQt5 (Qt v5.4.1)
 #
 # WARNING! All changes made in this file will be lost!
 
 from PyQt5 import QtCore
 
 qt_resource_data = b"\
+\x00\x00\x03\x30\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\
+\x6e\x6f\x22\x3f\x3e\x3c\x73\x76\x67\x20\x78\x6d\x6c\x6e\x73\x3a\
+\x72\x64\x66\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
+\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\
+\x32\x2d\x72\x64\x66\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\
+\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\
+\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\
+\x73\x76\x67\x22\x20\x78\x6d\x6c\x6e\x73\x3a\x6f\x73\x62\x3d\x22\
+\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x6f\x70\x65\x6e\x73\
+\x77\x61\x74\x63\x68\x62\x6f\x6f\x6b\x2e\x6f\x72\x67\x2f\x75\x72\
+\x69\x2f\x32\x30\x30\x39\x2f\x6f\x73\x62\x22\x20\x68\x65\x69\x67\
+\x68\x74\x3d\x22\x32\x34\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x32\
+\x34\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\
+\x20\x78\x6d\x6c\x6e\x73\x3a\x63\x63\x3d\x22\x68\x74\x74\x70\x3a\
+\x2f\x2f\x63\x72\x65\x61\x74\x69\x76\x65\x63\x6f\x6d\x6d\x6f\x6e\
+\x73\x2e\x6f\x72\x67\x2f\x6e\x73\x23\x22\x20\x76\x69\x65\x77\x42\
+\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x34\x20\x32\x34\x22\x20\x78\
+\x6d\x6c\x6e\x73\x3a\x64\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\
+\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\
+\x65\x6e\x74\x73\x2f\x31\x2e\x31\x2f\x22\x3e\x3c\x70\x61\x74\x68\
+\x20\x64\x3d\x22\x6d\x31\x34\x2e\x34\x36\x20\x32\x31\x2e\x38\x34\
+\x34\x63\x2d\x2e\x31\x39\x31\x32\x37\x2e\x30\x39\x35\x36\x33\x2d\
+\x2e\x33\x35\x38\x36\x33\x2e\x31\x34\x33\x34\x35\x2d\x2e\x35\x32\
+\x35\x39\x39\x2e\x31\x34\x33\x34\x35\x2d\x2e\x33\x33\x34\x37\x32\
+\x20\x30\x2d\x2e\x36\x34\x35\x35\x33\x2d\x2e\x32\x33\x39\x30\x38\
+\x2d\x2e\x38\x33\x36\x38\x30\x2d\x2e\x36\x36\x39\x34\x34\x6c\x2d\
+\x32\x2e\x33\x34\x33\x2d\x35\x2e\x30\x34\x34\x37\x2d\x32\x2e\x35\
+\x31\x30\x34\x20\x32\x2e\x39\x31\x36\x38\x63\x2d\x2e\x32\x33\x39\
+\x30\x38\x2e\x32\x36\x32\x39\x39\x2d\x2e\x35\x32\x35\x39\x39\x2e\
+\x34\x30\x36\x34\x34\x2d\x2e\x38\x38\x34\x36\x31\x2e\x34\x30\x36\
+\x34\x34\x2d\x2e\x35\x30\x32\x30\x38\x20\x30\x2d\x2e\x39\x30\x38\
+\x35\x32\x2d\x2e\x33\x35\x38\x36\x33\x2d\x2e\x39\x30\x38\x35\x32\
+\x2d\x31\x2e\x30\x30\x34\x32\x76\x2d\x31\x35\x2e\x35\x38\x38\x63\
+\x30\x2d\x2e\x36\x32\x31\x36\x32\x2e\x34\x35\x34\x32\x36\x2d\x31\
+\x2e\x30\x35\x32\x20\x31\x2e\x30\x30\x34\x32\x2d\x31\x2e\x30\x35\
+\x32\x2e\x33\x35\x38\x36\x33\x20\x30\x20\x2e\x36\x36\x39\x34\x34\
+\x2e\x31\x34\x33\x34\x35\x2e\x38\x38\x34\x36\x31\x2e\x33\x38\x32\
+\x35\x34\x6c\x39\x2e\x39\x37\x30\x37\x20\x31\x30\x2e\x37\x38\x34\
+\x63\x2e\x32\x38\x36\x39\x30\x2e\x33\x33\x34\x37\x32\x2e\x35\x32\
+\x35\x39\x39\x2e\x36\x39\x33\x33\x35\x2e\x35\x32\x35\x39\x39\x20\
+\x31\x2e\x31\x32\x33\x37\x20\x30\x20\x2e\x34\x35\x34\x32\x36\x2d\
+\x2e\x33\x33\x34\x37\x32\x2e\x38\x31\x32\x38\x39\x2d\x2e\x39\x30\
+\x38\x35\x32\x2e\x38\x31\x32\x38\x39\x68\x2d\x33\x2e\x35\x38\x36\
+\x33\x6c\x32\x2e\x31\x32\x37\x39\x20\x34\x2e\x37\x31\x63\x2e\x30\
+\x39\x35\x36\x33\x2e\x32\x31\x35\x31\x38\x2e\x31\x34\x33\x34\x35\
+\x2e\x33\x38\x32\x35\x34\x2e\x31\x34\x33\x34\x35\x2e\x36\x32\x31\
+\x36\x32\x20\x30\x20\x2e\x33\x31\x30\x38\x31\x2d\x2e\x32\x36\x32\
+\x39\x39\x2e\x35\x39\x37\x37\x31\x2d\x2e\x35\x39\x37\x37\x31\x2e\
+\x37\x34\x31\x31\x36\x7a\x22\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x03\x26\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x3f\x3e\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x73\
+\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\x57\x33\
+\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\x2f\x2f\
+\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
+\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\x73\x2f\
+\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\x67\x31\
+\x31\x2e\x64\x74\x64\x22\x3e\x3c\x73\x76\x67\x20\x78\x6d\x6c\x6e\
+\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\
+\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\
+\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\
+\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\
+\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x76\x65\x72\x73\x69\x6f\
+\x6e\x3d\x22\x31\x2e\x31\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x32\
+\x34\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x32\x34\x22\x20\x76\
+\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x34\x20\x32\
+\x34\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x31\x39\x2c\
+\x33\x4c\x31\x33\x2c\x39\x4c\x31\x35\x2c\x31\x31\x4c\x32\x32\x2c\
+\x34\x56\x33\x4d\x31\x32\x2c\x31\x32\x2e\x35\x41\x30\x2e\x35\x2c\
+\x30\x2e\x35\x20\x30\x20\x30\x2c\x31\x20\x31\x31\x2e\x35\x2c\x31\
+\x32\x41\x30\x2e\x35\x2c\x30\x2e\x35\x20\x30\x20\x30\x2c\x31\x20\
+\x31\x32\x2c\x31\x31\x2e\x35\x41\x30\x2e\x35\x2c\x30\x2e\x35\x20\
+\x30\x20\x30\x2c\x31\x20\x31\x32\x2e\x35\x2c\x31\x32\x41\x30\x2e\
+\x35\x2c\x30\x2e\x35\x20\x30\x20\x30\x2c\x31\x20\x31\x32\x2c\x31\
+\x32\x2e\x35\x4d\x36\x2c\x32\x30\x41\x32\x2c\x32\x20\x30\x20\x30\
+\x2c\x31\x20\x34\x2c\x31\x38\x43\x34\x2c\x31\x36\x2e\x38\x39\x20\
+\x34\x2e\x39\x2c\x31\x36\x20\x36\x2c\x31\x36\x41\x32\x2c\x32\x20\
+\x30\x20\x30\x2c\x31\x20\x38\x2c\x31\x38\x43\x38\x2c\x31\x39\x2e\
+\x31\x31\x20\x37\x2e\x31\x2c\x32\x30\x20\x36\x2c\x32\x30\x4d\x36\
+\x2c\x38\x41\x32\x2c\x32\x20\x30\x20\x30\x2c\x31\x20\x34\x2c\x36\
+\x43\x34\x2c\x34\x2e\x38\x39\x20\x34\x2e\x39\x2c\x34\x20\x36\x2c\
+\x34\x41\x32\x2c\x32\x20\x30\x20\x30\x2c\x31\x20\x38\x2c\x36\x43\
+\x38\x2c\x37\x2e\x31\x31\x20\x37\x2e\x31\x2c\x38\x20\x36\x2c\x38\
+\x4d\x39\x2e\x36\x34\x2c\x37\x2e\x36\x34\x43\x39\x2e\x38\x37\x2c\
+\x37\x2e\x31\x34\x20\x31\x30\x2c\x36\x2e\x35\x39\x20\x31\x30\x2c\
+\x36\x41\x34\x2c\x34\x20\x30\x20\x30\x2c\x30\x20\x36\x2c\x32\x41\
+\x34\x2c\x34\x20\x30\x20\x30\x2c\x30\x20\x32\x2c\x36\x41\x34\x2c\
+\x34\x20\x30\x20\x30\x2c\x30\x20\x36\x2c\x31\x30\x43\x36\x2e\x35\
+\x39\x2c\x31\x30\x20\x37\x2e\x31\x34\x2c\x39\x2e\x38\x37\x20\x37\
+\x2e\x36\x34\x2c\x39\x2e\x36\x34\x4c\x31\x30\x2c\x31\x32\x4c\x37\
+\x2e\x36\x34\x2c\x31\x34\x2e\x33\x36\x43\x37\x2e\x31\x34\x2c\x31\
+\x34\x2e\x31\x33\x20\x36\x2e\x35\x39\x2c\x31\x34\x20\x36\x2c\x31\
+\x34\x41\x34\x2c\x34\x20\x30\x20\x30\x2c\x30\x20\x32\x2c\x31\x38\
+\x41\x34\x2c\x34\x20\x30\x20\x30\x2c\x30\x20\x36\x2c\x32\x32\x41\
+\x34\x2c\x34\x20\x30\x20\x30\x2c\x30\x20\x31\x30\x2c\x31\x38\x43\
+\x31\x30\x2c\x31\x37\x2e\x34\x31\x20\x39\x2e\x38\x37\x2c\x31\x36\
+\x2e\x38\x36\x20\x39\x2e\x36\x34\x2c\x31\x36\x2e\x33\x36\x4c\x31\
+\x32\x2c\x31\x34\x4c\x31\x39\x2c\x32\x31\x48\x32\x32\x56\x32\x30\
+\x4c\x39\x2e\x36\x34\x2c\x37\x2e\x36\x34\x5a\x22\x20\x2f\x3e\x3c\
+\x2f\x73\x76\x67\x3e\
+\x00\x00\x02\x5b\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x3f\x3e\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x73\
+\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\x57\x33\
+\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\x2f\x2f\
+\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
+\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\x73\x2f\
+\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\x67\x31\
+\x31\x2e\x64\x74\x64\x22\x3e\x3c\x73\x76\x67\x20\x78\x6d\x6c\x6e\
+\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\
+\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\
+\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\
+\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\
+\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x76\x65\x72\x73\x69\x6f\
+\x6e\x3d\x22\x31\x2e\x31\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x32\
+\x34\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x32\x34\x22\x20\x76\
+\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x34\x20\x32\
+\x34\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x31\x2e\x33\
+\x39\x2c\x31\x38\x2e\x33\x36\x4c\x33\x2e\x31\x36\x2c\x31\x36\x2e\
+\x36\x4c\x34\x2e\x35\x38\x2c\x31\x38\x4c\x35\x2e\x36\x34\x2c\x31\
+\x36\x2e\x39\x35\x4c\x34\x2e\x32\x32\x2c\x31\x35\x2e\x35\x34\x4c\
+\x35\x2e\x36\x34\x2c\x31\x34\x2e\x31\x32\x4c\x38\x2e\x31\x31\x2c\
+\x31\x36\x2e\x36\x4c\x39\x2e\x31\x37\x2c\x31\x35\x2e\x35\x34\x4c\
+\x36\x2e\x37\x2c\x31\x33\x2e\x30\x36\x4c\x38\x2e\x31\x31\x2c\x31\
+\x31\x2e\x36\x35\x4c\x39\x2e\x35\x33\x2c\x31\x33\x2e\x30\x36\x4c\
+\x31\x30\x2e\x35\x39\x2c\x31\x32\x4c\x39\x2e\x31\x37\x2c\x31\x30\
+\x2e\x35\x39\x4c\x31\x30\x2e\x35\x39\x2c\x39\x2e\x31\x37\x4c\x31\
+\x33\x2e\x30\x36\x2c\x31\x31\x2e\x36\x35\x4c\x31\x34\x2e\x31\x32\
+\x2c\x31\x30\x2e\x35\x39\x4c\x31\x31\x2e\x36\x35\x2c\x38\x2e\x31\
+\x31\x4c\x31\x33\x2e\x30\x36\x2c\x36\x2e\x37\x4c\x31\x34\x2e\x34\
+\x37\x2c\x38\x2e\x31\x31\x4c\x31\x35\x2e\x35\x34\x2c\x37\x2e\x30\
+\x35\x4c\x31\x34\x2e\x31\x32\x2c\x35\x2e\x36\x34\x4c\x31\x35\x2e\
+\x35\x34\x2c\x34\x2e\x32\x32\x4c\x31\x38\x2c\x36\x2e\x37\x4c\x31\
+\x39\x2e\x30\x37\x2c\x35\x2e\x36\x34\x4c\x31\x36\x2e\x36\x2c\x33\
+\x2e\x31\x36\x4c\x31\x38\x2e\x33\x36\x2c\x31\x2e\x33\x39\x4c\x32\
+\x32\x2e\x36\x31\x2c\x35\x2e\x36\x34\x4c\x35\x2e\x36\x34\x2c\x32\
+\x32\x2e\x36\x31\x4c\x31\x2e\x33\x39\x2c\x31\x38\x2e\x33\x36\x5a\
+\x22\x20\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x09\x0f\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\
+\x6e\x6f\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\
+\x6c\x6e\x73\x3a\x64\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\
+\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\
+\x6e\x74\x73\x2f\x31\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\
+\x6e\x73\x3a\x63\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\
+\x65\x61\x74\x69\x76\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\
+\x67\x2f\x6e\x73\x23\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\
+\x72\x64\x66\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
+\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\
+\x32\x2d\x72\x64\x66\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\
+\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\
+\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\
+\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\
+\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\
+\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\
+\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\
+\x6f\x64\x69\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\
+\x70\x6f\x64\x69\x2e\x73\x6f\x75\x72\x63\x65\x66\x6f\x72\x67\x65\
+\x2e\x6e\x65\x74\x2f\x44\x54\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\
+\x69\x2d\x30\x2e\x64\x74\x64\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\
+\x73\x3a\x69\x6e\x6b\x73\x63\x61\x70\x65\x3d\x22\x68\x74\x74\x70\
+\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\
+\x6f\x72\x67\x2f\x6e\x61\x6d\x65\x73\x70\x61\x63\x65\x73\x2f\x69\
+\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x76\x65\x72\x73\
+\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x0a\x20\x20\x20\x77\x69\x64\
+\x74\x68\x3d\x22\x32\x34\x22\x0a\x20\x20\x20\x68\x65\x69\x67\x68\
+\x74\x3d\x22\x32\x34\x22\x0a\x20\x20\x20\x76\x69\x65\x77\x42\x6f\
+\x78\x3d\x22\x30\x20\x30\x20\x32\x34\x20\x32\x34\x22\x0a\x20\x20\
+\x20\x69\x64\x3d\x22\x73\x76\x67\x32\x22\x0a\x20\x20\x20\x69\x6e\
+\x6b\x73\x63\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\
+\x30\x2e\x39\x31\x20\x72\x31\x33\x37\x32\x35\x22\x0a\x20\x20\x20\
+\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\x63\x6e\x61\x6d\x65\
+\x3d\x22\x64\x65\x66\x61\x75\x6c\x74\x43\x6f\x6c\x6f\x72\x2e\x73\
+\x76\x67\x22\x3e\x0a\x20\x20\x3c\x6d\x65\x74\x61\x64\x61\x74\x61\
+\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6d\x65\x74\x61\x64\x61\
+\x74\x61\x31\x30\x22\x3e\x0a\x20\x20\x20\x20\x3c\x72\x64\x66\x3a\
+\x52\x44\x46\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x63\x63\x3a\x57\
+\x6f\x72\x6b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\
+\x3a\x61\x62\x6f\x75\x74\x3d\x22\x22\x3e\x0a\x20\x20\x20\x20\x20\
+\x20\x20\x20\x3c\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x69\x6d\
+\x61\x67\x65\x2f\x73\x76\x67\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\
+\x66\x6f\x72\x6d\x61\x74\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\
+\x3c\x64\x63\x3a\x74\x79\x70\x65\x0a\x20\x20\x20\x20\x20\x20\x20\
+\x20\x20\x20\x20\x72\x64\x66\x3a\x72\x65\x73\x6f\x75\x72\x63\x65\
+\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\x72\
+\x67\x2f\x64\x63\x2f\x64\x63\x6d\x69\x74\x79\x70\x65\x2f\x53\x74\
+\x69\x6c\x6c\x49\x6d\x61\x67\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\
+\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x69\x74\x6c\x65\x20\x2f\
+\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x63\x63\x3a\x57\x6f\x72\
+\x6b\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x72\x64\x66\x3a\x52\x44\x46\
+\x3e\x0a\x20\x20\x3c\x2f\x6d\x65\x74\x61\x64\x61\x74\x61\x3e\x0a\
+\x20\x20\x3c\x64\x65\x66\x73\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\
+\x22\x64\x65\x66\x73\x38\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x73\x6f\
+\x64\x69\x70\x6f\x64\x69\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\
+\x0a\x20\x20\x20\x20\x20\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\
+\x22\x23\x66\x66\x66\x66\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\
+\x6f\x72\x64\x65\x72\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\
+\x36\x36\x36\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\
+\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\
+\x20\x6f\x62\x6a\x65\x63\x74\x74\x6f\x6c\x65\x72\x61\x6e\x63\x65\
+\x3d\x22\x31\x30\x22\x0a\x20\x20\x20\x20\x20\x67\x72\x69\x64\x74\
+\x6f\x6c\x65\x72\x61\x6e\x63\x65\x3d\x22\x31\x30\x22\x0a\x20\x20\
+\x20\x20\x20\x67\x75\x69\x64\x65\x74\x6f\x6c\x65\x72\x61\x6e\x63\
+\x65\x3d\x22\x31\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
+\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x6f\x70\x61\x63\x69\x74\x79\
+\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x3a\x70\x61\x67\x65\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\
+\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\
+\x77\x69\x6e\x64\x6f\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x39\
+\x32\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
+\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\
+\x22\x31\x31\x37\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\
+\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x36\x22\x0a\x20\x20\x20\x20\
+\x20\x73\x68\x6f\x77\x67\x72\x69\x64\x3d\x22\x66\x61\x6c\x73\x65\
+\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\
+\x7a\x6f\x6f\x6d\x3d\x22\x31\x33\x2e\x39\x30\x36\x34\x33\x33\x22\
+\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\
+\x78\x3d\x22\x31\x31\x2e\x37\x37\x35\x32\x31\x31\x22\x0a\x20\x20\
+\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x79\x3d\x22\
+\x37\x2e\x32\x34\x32\x33\x32\x31\x34\x22\x0a\x20\x20\x20\x20\x20\
+\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\
+\x78\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\
+\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x79\x3d\x22\x32\x22\
+\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\
+\x69\x6e\x64\x6f\x77\x2d\x6d\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\
+\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
+\x65\x3a\x63\x75\x72\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\
+\x22\x73\x76\x67\x32\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x72\x65\x63\
+\x74\x0a\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\
+\x6c\x6f\x72\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x64\x69\x73\x70\
+\x6c\x61\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\
+\x6c\x6f\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x76\x69\x73\x69\
+\x62\x69\x6c\x69\x74\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x6f\
+\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x3a\x23\x66\
+\x66\x66\x66\x66\x66\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\
+\x74\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\
+\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x6e\x6f\
+\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\
+\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\
+\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\
+\x6e\x65\x6a\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\
+\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\
+\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\
+\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\
+\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x73\x74\x72\x6f\x6b\
+\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x6d\x61\x72\x6b\
+\x65\x72\x3a\x6e\x6f\x6e\x65\x3b\x65\x6e\x61\x62\x6c\x65\x2d\x62\
+\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\x6d\x75\
+\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\
+\x65\x63\x74\x34\x31\x34\x31\x22\x0a\x20\x20\x20\x20\x20\x77\x69\
+\x64\x74\x68\x3d\x22\x32\x34\x22\x0a\x20\x20\x20\x20\x20\x68\x65\
+\x69\x67\x68\x74\x3d\x22\x32\x34\x22\x0a\x20\x20\x20\x20\x20\x78\
+\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x79\x3d\x22\x30\x22\x20\
+\x2f\x3e\x0a\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\
+\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x23\x30\x30\
+\x30\x30\x30\x30\x3b\x64\x69\x73\x70\x6c\x61\x79\x3a\x69\x6e\x6c\
+\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\x77\x3a\x76\x69\x73\
+\x69\x62\x6c\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\x79\x3a\
+\x76\x69\x73\x69\x62\x6c\x65\x3b\x6f\x70\x61\x63\x69\x74\x79\x3a\
+\x31\x3b\x66\x69\x6c\x6c\x3a\x23\x66\x66\x30\x30\x30\x30\x3b\x66\
+\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x66\x69\
+\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\
+\x73\x74\x72\x6f\x6b\x65\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\
+\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x31\x3b\x73\x74\x72\x6f\x6b\
+\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3a\x72\x6f\x75\x6e\x64\x3b\
+\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\
+\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\
+\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\x72\x6f\x6b\x65\
+\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\x3a\x6e\x6f\x6e\x65\x3b\
+\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x6f\x66\x66\x73\x65\
+\x74\x3a\x30\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\
+\x74\x79\x3a\x31\x3b\x6d\x61\x72\x6b\x65\x72\x3a\x6e\x6f\x6e\x65\
+\x3b\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\
+\x6e\x64\x3a\x61\x63\x63\x75\x6d\x75\x6c\x61\x74\x65\x22\x0a\x20\
+\x20\x20\x20\x20\x64\x3d\x22\x4d\x20\x31\x37\x2e\x35\x34\x36\x38\
+\x37\x35\x20\x30\x20\x4c\x20\x30\x20\x31\x37\x2e\x35\x34\x36\x38\
+\x37\x35\x20\x4c\x20\x30\x20\x32\x34\x20\x4c\x20\x35\x2e\x35\x36\
+\x36\x34\x30\x36\x32\x20\x32\x34\x20\x4c\x20\x32\x34\x20\x35\x2e\
+\x35\x36\x36\x34\x30\x36\x32\x20\x4c\x20\x32\x34\x20\x30\x20\x4c\
+\x20\x31\x37\x2e\x35\x34\x36\x38\x37\x35\x20\x30\x20\x7a\x20\x22\
+\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\x65\x63\x74\x34\x31\
+\x34\x35\x22\x20\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
 \x00\x01\x37\x1b\
 \x89\
 \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -4989,152 +5282,6 @@ qt_resource_data = b"\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
 \xd8\x4b\x00\x01\x06\x00\x70\x70\x21\x6a\x56\x20\xd0\xef\x00\x00\
 \x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
-\x00\x00\x02\x5b\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
-\x2d\x38\x22\x3f\x3e\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x73\
-\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\x57\x33\
-\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\x2f\x2f\
-\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
-\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\x73\x2f\
-\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\x67\x31\
-\x31\x2e\x64\x74\x64\x22\x3e\x3c\x73\x76\x67\x20\x78\x6d\x6c\x6e\
-\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\
-\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\
-\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\
-\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\
-\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x76\x65\x72\x73\x69\x6f\
-\x6e\x3d\x22\x31\x2e\x31\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x32\
-\x34\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x32\x34\x22\x20\x76\
-\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x34\x20\x32\
-\x34\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x31\x2e\x33\
-\x39\x2c\x31\x38\x2e\x33\x36\x4c\x33\x2e\x31\x36\x2c\x31\x36\x2e\
-\x36\x4c\x34\x2e\x35\x38\x2c\x31\x38\x4c\x35\x2e\x36\x34\x2c\x31\
-\x36\x2e\x39\x35\x4c\x34\x2e\x32\x32\x2c\x31\x35\x2e\x35\x34\x4c\
-\x35\x2e\x36\x34\x2c\x31\x34\x2e\x31\x32\x4c\x38\x2e\x31\x31\x2c\
-\x31\x36\x2e\x36\x4c\x39\x2e\x31\x37\x2c\x31\x35\x2e\x35\x34\x4c\
-\x36\x2e\x37\x2c\x31\x33\x2e\x30\x36\x4c\x38\x2e\x31\x31\x2c\x31\
-\x31\x2e\x36\x35\x4c\x39\x2e\x35\x33\x2c\x31\x33\x2e\x30\x36\x4c\
-\x31\x30\x2e\x35\x39\x2c\x31\x32\x4c\x39\x2e\x31\x37\x2c\x31\x30\
-\x2e\x35\x39\x4c\x31\x30\x2e\x35\x39\x2c\x39\x2e\x31\x37\x4c\x31\
-\x33\x2e\x30\x36\x2c\x31\x31\x2e\x36\x35\x4c\x31\x34\x2e\x31\x32\
-\x2c\x31\x30\x2e\x35\x39\x4c\x31\x31\x2e\x36\x35\x2c\x38\x2e\x31\
-\x31\x4c\x31\x33\x2e\x30\x36\x2c\x36\x2e\x37\x4c\x31\x34\x2e\x34\
-\x37\x2c\x38\x2e\x31\x31\x4c\x31\x35\x2e\x35\x34\x2c\x37\x2e\x30\
-\x35\x4c\x31\x34\x2e\x31\x32\x2c\x35\x2e\x36\x34\x4c\x31\x35\x2e\
-\x35\x34\x2c\x34\x2e\x32\x32\x4c\x31\x38\x2c\x36\x2e\x37\x4c\x31\
-\x39\x2e\x30\x37\x2c\x35\x2e\x36\x34\x4c\x31\x36\x2e\x36\x2c\x33\
-\x2e\x31\x36\x4c\x31\x38\x2e\x33\x36\x2c\x31\x2e\x33\x39\x4c\x32\
-\x32\x2e\x36\x31\x2c\x35\x2e\x36\x34\x4c\x35\x2e\x36\x34\x2c\x32\
-\x32\x2e\x36\x31\x4c\x31\x2e\x33\x39\x2c\x31\x38\x2e\x33\x36\x5a\
-\x22\x20\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
-\x00\x00\x03\x26\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
-\x2d\x38\x22\x3f\x3e\x3c\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x73\
-\x76\x67\x20\x50\x55\x42\x4c\x49\x43\x20\x22\x2d\x2f\x2f\x57\x33\
-\x43\x2f\x2f\x44\x54\x44\x20\x53\x56\x47\x20\x31\x2e\x31\x2f\x2f\
-\x45\x4e\x22\x20\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
-\x77\x33\x2e\x6f\x72\x67\x2f\x47\x72\x61\x70\x68\x69\x63\x73\x2f\
-\x53\x56\x47\x2f\x31\x2e\x31\x2f\x44\x54\x44\x2f\x73\x76\x67\x31\
-\x31\x2e\x64\x74\x64\x22\x3e\x3c\x73\x76\x67\x20\x78\x6d\x6c\x6e\
-\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\
-\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x20\x78\
-\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\x70\
-\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\
-\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x20\x76\x65\x72\x73\x69\x6f\
-\x6e\x3d\x22\x31\x2e\x31\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x32\
-\x34\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x32\x34\x22\x20\x76\
-\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x34\x20\x32\
-\x34\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x4d\x31\x39\x2c\
-\x33\x4c\x31\x33\x2c\x39\x4c\x31\x35\x2c\x31\x31\x4c\x32\x32\x2c\
-\x34\x56\x33\x4d\x31\x32\x2c\x31\x32\x2e\x35\x41\x30\x2e\x35\x2c\
-\x30\x2e\x35\x20\x30\x20\x30\x2c\x31\x20\x31\x31\x2e\x35\x2c\x31\
-\x32\x41\x30\x2e\x35\x2c\x30\x2e\x35\x20\x30\x20\x30\x2c\x31\x20\
-\x31\x32\x2c\x31\x31\x2e\x35\x41\x30\x2e\x35\x2c\x30\x2e\x35\x20\
-\x30\x20\x30\x2c\x31\x20\x31\x32\x2e\x35\x2c\x31\x32\x41\x30\x2e\
-\x35\x2c\x30\x2e\x35\x20\x30\x20\x30\x2c\x31\x20\x31\x32\x2c\x31\
-\x32\x2e\x35\x4d\x36\x2c\x32\x30\x41\x32\x2c\x32\x20\x30\x20\x30\
-\x2c\x31\x20\x34\x2c\x31\x38\x43\x34\x2c\x31\x36\x2e\x38\x39\x20\
-\x34\x2e\x39\x2c\x31\x36\x20\x36\x2c\x31\x36\x41\x32\x2c\x32\x20\
-\x30\x20\x30\x2c\x31\x20\x38\x2c\x31\x38\x43\x38\x2c\x31\x39\x2e\
-\x31\x31\x20\x37\x2e\x31\x2c\x32\x30\x20\x36\x2c\x32\x30\x4d\x36\
-\x2c\x38\x41\x32\x2c\x32\x20\x30\x20\x30\x2c\x31\x20\x34\x2c\x36\
-\x43\x34\x2c\x34\x2e\x38\x39\x20\x34\x2e\x39\x2c\x34\x20\x36\x2c\
-\x34\x41\x32\x2c\x32\x20\x30\x20\x30\x2c\x31\x20\x38\x2c\x36\x43\
-\x38\x2c\x37\x2e\x31\x31\x20\x37\x2e\x31\x2c\x38\x20\x36\x2c\x38\
-\x4d\x39\x2e\x36\x34\x2c\x37\x2e\x36\x34\x43\x39\x2e\x38\x37\x2c\
-\x37\x2e\x31\x34\x20\x31\x30\x2c\x36\x2e\x35\x39\x20\x31\x30\x2c\
-\x36\x41\x34\x2c\x34\x20\x30\x20\x30\x2c\x30\x20\x36\x2c\x32\x41\
-\x34\x2c\x34\x20\x30\x20\x30\x2c\x30\x20\x32\x2c\x36\x41\x34\x2c\
-\x34\x20\x30\x20\x30\x2c\x30\x20\x36\x2c\x31\x30\x43\x36\x2e\x35\
-\x39\x2c\x31\x30\x20\x37\x2e\x31\x34\x2c\x39\x2e\x38\x37\x20\x37\
-\x2e\x36\x34\x2c\x39\x2e\x36\x34\x4c\x31\x30\x2c\x31\x32\x4c\x37\
-\x2e\x36\x34\x2c\x31\x34\x2e\x33\x36\x43\x37\x2e\x31\x34\x2c\x31\
-\x34\x2e\x31\x33\x20\x36\x2e\x35\x39\x2c\x31\x34\x20\x36\x2c\x31\
-\x34\x41\x34\x2c\x34\x20\x30\x20\x30\x2c\x30\x20\x32\x2c\x31\x38\
-\x41\x34\x2c\x34\x20\x30\x20\x30\x2c\x30\x20\x36\x2c\x32\x32\x41\
-\x34\x2c\x34\x20\x30\x20\x30\x2c\x30\x20\x31\x30\x2c\x31\x38\x43\
-\x31\x30\x2c\x31\x37\x2e\x34\x31\x20\x39\x2e\x38\x37\x2c\x31\x36\
-\x2e\x38\x36\x20\x39\x2e\x36\x34\x2c\x31\x36\x2e\x33\x36\x4c\x31\
-\x32\x2c\x31\x34\x4c\x31\x39\x2c\x32\x31\x48\x32\x32\x56\x32\x30\
-\x4c\x39\x2e\x36\x34\x2c\x37\x2e\x36\x34\x5a\x22\x20\x2f\x3e\x3c\
-\x2f\x73\x76\x67\x3e\
-\x00\x00\x03\x30\
-\x3c\
-\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
-\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
-\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\
-\x6e\x6f\x22\x3f\x3e\x3c\x73\x76\x67\x20\x78\x6d\x6c\x6e\x73\x3a\
-\x72\x64\x66\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
-\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\
-\x32\x2d\x72\x64\x66\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\
-\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\
-\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\
-\x73\x76\x67\x22\x20\x78\x6d\x6c\x6e\x73\x3a\x6f\x73\x62\x3d\x22\
-\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x6f\x70\x65\x6e\x73\
-\x77\x61\x74\x63\x68\x62\x6f\x6f\x6b\x2e\x6f\x72\x67\x2f\x75\x72\
-\x69\x2f\x32\x30\x30\x39\x2f\x6f\x73\x62\x22\x20\x68\x65\x69\x67\
-\x68\x74\x3d\x22\x32\x34\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x32\
-\x34\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\
-\x20\x78\x6d\x6c\x6e\x73\x3a\x63\x63\x3d\x22\x68\x74\x74\x70\x3a\
-\x2f\x2f\x63\x72\x65\x61\x74\x69\x76\x65\x63\x6f\x6d\x6d\x6f\x6e\
-\x73\x2e\x6f\x72\x67\x2f\x6e\x73\x23\x22\x20\x76\x69\x65\x77\x42\
-\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x34\x20\x32\x34\x22\x20\x78\
-\x6d\x6c\x6e\x73\x3a\x64\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\
-\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\
-\x65\x6e\x74\x73\x2f\x31\x2e\x31\x2f\x22\x3e\x3c\x70\x61\x74\x68\
-\x20\x64\x3d\x22\x6d\x31\x34\x2e\x34\x36\x20\x32\x31\x2e\x38\x34\
-\x34\x63\x2d\x2e\x31\x39\x31\x32\x37\x2e\x30\x39\x35\x36\x33\x2d\
-\x2e\x33\x35\x38\x36\x33\x2e\x31\x34\x33\x34\x35\x2d\x2e\x35\x32\
-\x35\x39\x39\x2e\x31\x34\x33\x34\x35\x2d\x2e\x33\x33\x34\x37\x32\
-\x20\x30\x2d\x2e\x36\x34\x35\x35\x33\x2d\x2e\x32\x33\x39\x30\x38\
-\x2d\x2e\x38\x33\x36\x38\x30\x2d\x2e\x36\x36\x39\x34\x34\x6c\x2d\
-\x32\x2e\x33\x34\x33\x2d\x35\x2e\x30\x34\x34\x37\x2d\x32\x2e\x35\
-\x31\x30\x34\x20\x32\x2e\x39\x31\x36\x38\x63\x2d\x2e\x32\x33\x39\
-\x30\x38\x2e\x32\x36\x32\x39\x39\x2d\x2e\x35\x32\x35\x39\x39\x2e\
-\x34\x30\x36\x34\x34\x2d\x2e\x38\x38\x34\x36\x31\x2e\x34\x30\x36\
-\x34\x34\x2d\x2e\x35\x30\x32\x30\x38\x20\x30\x2d\x2e\x39\x30\x38\
-\x35\x32\x2d\x2e\x33\x35\x38\x36\x33\x2d\x2e\x39\x30\x38\x35\x32\
-\x2d\x31\x2e\x30\x30\x34\x32\x76\x2d\x31\x35\x2e\x35\x38\x38\x63\
-\x30\x2d\x2e\x36\x32\x31\x36\x32\x2e\x34\x35\x34\x32\x36\x2d\x31\
-\x2e\x30\x35\x32\x20\x31\x2e\x30\x30\x34\x32\x2d\x31\x2e\x30\x35\
-\x32\x2e\x33\x35\x38\x36\x33\x20\x30\x20\x2e\x36\x36\x39\x34\x34\
-\x2e\x31\x34\x33\x34\x35\x2e\x38\x38\x34\x36\x31\x2e\x33\x38\x32\
-\x35\x34\x6c\x39\x2e\x39\x37\x30\x37\x20\x31\x30\x2e\x37\x38\x34\
-\x63\x2e\x32\x38\x36\x39\x30\x2e\x33\x33\x34\x37\x32\x2e\x35\x32\
-\x35\x39\x39\x2e\x36\x39\x33\x33\x35\x2e\x35\x32\x35\x39\x39\x20\
-\x31\x2e\x31\x32\x33\x37\x20\x30\x20\x2e\x34\x35\x34\x32\x36\x2d\
-\x2e\x33\x33\x34\x37\x32\x2e\x38\x31\x32\x38\x39\x2d\x2e\x39\x30\
-\x38\x35\x32\x2e\x38\x31\x32\x38\x39\x68\x2d\x33\x2e\x35\x38\x36\
-\x33\x6c\x32\x2e\x31\x32\x37\x39\x20\x34\x2e\x37\x31\x63\x2e\x30\
-\x39\x35\x36\x33\x2e\x32\x31\x35\x31\x38\x2e\x31\x34\x33\x34\x35\
-\x2e\x33\x38\x32\x35\x34\x2e\x31\x34\x33\x34\x35\x2e\x36\x32\x31\
-\x36\x32\x20\x30\x20\x2e\x33\x31\x30\x38\x31\x2d\x2e\x32\x36\x32\
-\x39\x39\x2e\x35\x39\x37\x37\x31\x2d\x2e\x35\x39\x37\x37\x31\x2e\
-\x37\x34\x31\x31\x36\x7a\x22\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
 \x00\x00\x03\x80\
 \x3c\
 \x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
@@ -5251,22 +5398,26 @@ qt_resource_name = b"\
 \x0a\x6c\x78\x43\
 \x00\x72\
 \x00\x65\x00\x73\x00\x6f\x00\x75\x00\x72\x00\x63\x00\x65\x00\x73\
+\x00\x0a\
+\x0a\x68\x03\xe7\
+\x00\x63\
+\x00\x75\x00\x72\x00\x73\x00\x6f\x00\x72\x00\x2e\x00\x73\x00\x76\x00\x67\
 \x00\x07\
-\x08\x73\x57\x87\
-\x00\x61\
-\x00\x70\x00\x70\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\x0a\xc7\x5a\x07\
+\x00\x63\
+\x00\x75\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\
 \x00\x09\
 \x02\xc5\xa9\x47\
 \x00\x72\
 \x00\x75\x00\x6c\x00\x65\x00\x72\x00\x2e\x00\x73\x00\x76\x00\x67\
+\x00\x10\
+\x02\xf8\x99\x27\
+\x00\x64\
+\x00\x65\x00\x66\x00\x61\x00\x75\x00\x6c\x00\x74\x00\x43\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\x2e\x00\x73\x00\x76\x00\x67\
 \x00\x07\
-\x0a\xc7\x5a\x07\
-\x00\x63\
-\x00\x75\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\
-\x00\x0a\
-\x0a\x68\x03\xe7\
-\x00\x63\
-\x00\x75\x00\x72\x00\x73\x00\x6f\x00\x72\x00\x2e\x00\x73\x00\x76\x00\x67\
+\x08\x73\x57\x87\
+\x00\x61\
+\x00\x70\x00\x70\x00\x2e\x00\x70\x00\x6e\x00\x67\
 \x00\x09\
 \x09\xc8\x8f\x47\
 \x00\x63\
@@ -5279,13 +5430,14 @@ qt_resource_name = b"\
 
 qt_resource_struct = b"\
 \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
-\x00\x00\x00\x00\x00\x02\x00\x00\x00\x06\x00\x00\x00\x02\
-\x00\x00\x00\x2c\x00\x00\x00\x00\x00\x01\x00\x01\x37\x1f\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x02\
+\x00\x00\x00\x46\x00\x00\x00\x00\x00\x01\x00\x00\x06\x5e\
+\x00\x00\x00\x5e\x00\x00\x00\x00\x00\x01\x00\x00\x08\xbd\
+\x00\x00\x00\x84\x00\x00\x00\x00\x00\x01\x00\x00\x11\xd0\
+\x00\x00\x00\x98\x00\x00\x00\x00\x00\x01\x00\x01\x48\xef\
 \x00\x00\x00\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x00\x72\x00\x00\x00\x00\x00\x01\x00\x01\x3f\xdc\
-\x00\x00\x00\x58\x00\x00\x00\x00\x00\x01\x00\x01\x3c\xa8\
-\x00\x00\x00\x44\x00\x00\x00\x00\x00\x01\x00\x01\x39\x7e\
-\x00\x00\x00\x8a\x00\x00\x00\x00\x00\x01\x00\x01\x43\x60\
+\x00\x00\x00\x32\x00\x00\x00\x00\x00\x01\x00\x00\x03\x34\
+\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x01\x4c\x73\
 "
 
 def qInitResources():
diff --git a/Lib/defconQt/icons_db.qrc b/Lib/defconQt/icons_db.qrc
index 5fea427..9ec2d43 100644
--- a/Lib/defconQt/icons_db.qrc
+++ b/Lib/defconQt/icons_db.qrc
@@ -5,6 +5,7 @@
 	resources/curve.svg
 	resources/cut.svg
 	resources/ruler.svg
+	resources/defaultColor.svg
     resources/settings.svg
 
 
diff --git a/Lib/defconQt/layerSetList.py b/Lib/defconQt/layerSetList.py
new file mode 100644
index 0000000..b2d3c9f
--- /dev/null
+++ b/Lib/defconQt/layerSetList.py
@@ -0,0 +1,135 @@
+from PyQt5.QtCore import Qt
+from PyQt5.QtGui import QKeySequence, QColor, QPixmap, QIcon
+from PyQt5.QtWidgets import QWidget, QMenu, QListWidget, QListWidgetItem, \
+                            QAbstractItemView, QVBoxLayout, QAction, QColorDialog
+from defconQt import icons_db
+from defconQt.glyphView import AddLayerDialog
+
+class LayerSetList(QListWidget):
+    def __init__(self, font, parent=None, *args, **kwds):
+        super().__init__(parent, *args, **kwds)
+
+        self._layerSet = font.layers
+
+        self.setDragDropMode(QAbstractItemView.InternalMove)
+
+        model = self.model()
+        model.rowsMoved.connect(self._reordered)
+        self.itemChanged.connect(self._itemChanged)
+
+        self.setContextMenuPolicy(Qt.ActionsContextMenu)
+
+        action = QAction("Add Layer…", self)
+        action.setShortcuts(QKeySequence.New)
+        action.triggered.connect(self._addLayer)
+        self.addAction(action)
+
+        action = QAction("Change &Name", self)
+        action.setShortcuts(QKeySequence('n'))
+        action.triggered.connect(lambda : self.editItem(self.currentItem()))
+        self.addAction(action)
+
+        action = QAction("Change &Color", self)
+        action.setShortcuts(QKeySequence('c'))
+        action.triggered.connect(self._changeColor)
+        self.addAction(action)
+
+        action = QAction("Reset Color to &Default", self)
+        action.setShortcuts(QKeySequence('d'))
+        action.triggered.connect(self._resetColor)
+        self.addAction(action)
+
+        action = QAction("Delete", self)
+        action.setShortcuts(QKeySequence.Delete)
+        action.triggered.connect(self._deleteLayer)
+        self.addAction(action)
+
+        self._layerSet.addObserver(self, '_update', 'LayerSet.Changed')
+
+        self._update()
+
+    def _update(self, *args):
+        index = self.currentRow()
+        while self.count():
+            self.takeItem(self.count()-1)
+        for i, layer in enumerate(self._layerSet):
+            item = self._makeItem(layer)
+            self.addItem(item)
+            if i == index:
+                self.setCurrentItem(item)
+
+    def _makeItem(self, layer):
+        isDefault = layer is self._layerSet.defaultLayer
+        name = layer.name
+        color = layer.color
+        item = QListWidgetItem()
+        item.setText(name)
+        if color:
+            pixmap = QPixmap(100, 100)
+            # change color
+            pixmap.fill(QColor.fromRgbF(*color))
+            icon = QIcon(pixmap)
+        else:
+            icon = QIcon(":/resources/defaultColor.svg")
+        item.setIcon(icon)
+
+        if isDefault:
+            font = item.font()
+            font.setBold(True)
+            item.setFont(font)
+
+        item.setFlags(item.flags() | Qt.ItemIsEditable)
+
+        return item;
+
+    def _getCurrentLayer(self):
+        item = self.currentItem()
+        if not item:
+            return
+        name = item.text()
+        return self._layerSet[name] if name in self._layerSet else None
+
+    def _deleteLayer(self):
+        layer = self._getCurrentLayer()
+        if not layer:
+            return
+
+        if layer is self._layerSet.defaultLayer:
+            # because I think we can't handle a font without a default layer
+            # TODO: try this
+            return
+        del self._layerSet[layer.name];
+
+    def _reordered(self, *args):
+        # get a new layer order
+        newOrder = [self.item(index).text() for index in range(self.count())]
+        self._layerSet.layerOrder = newOrder
+
+    def _itemChanged(self, item):
+        index = self.indexFromItem(item).row()
+        layerName = self._layerSet.layerOrder[index]
+        self._layerSet[layerName].name = item.text()
+
+    def _addLayer(self):
+        newLayerName, ok = AddLayerDialog.getNewLayerName(self)
+        if ok:
+            # this should cause self._layerSetLayerAdded to be executed
+            self._layerSet.newLayer(newLayerName)
+
+    def _changeColor(self):
+        layer = self._getCurrentLayer()
+        if not layer:
+            return
+
+        startColor = layer.color and QColor.fromRgbF(*layer.color) or QColor('limegreen')
+        qcolor = QColorDialog.getColor(startColor, self, options=QColorDialog.ShowAlphaChannel)
+        if not qcolor.isValid():
+            # cancelled
+            return
+        layer.color = qcolor.getRgbF()
+
+    def _resetColor(self):
+        layer = self._getCurrentLayer()
+        if not layer:
+            return
+        layer.color = None
diff --git a/Lib/defconQt/representationFactories/qPainterPathFactory.py b/Lib/defconQt/representationFactories/qPainterPathFactory.py
index cb51de6..0b99b82 100644
--- a/Lib/defconQt/representationFactories/qPainterPathFactory.py
+++ b/Lib/defconQt/representationFactories/qPainterPathFactory.py
@@ -2,7 +2,7 @@ from fontTools.pens.qtPen import QtPen
 from PyQt5.QtCore import Qt
 
 def QPainterPathFactory(glyph):
-    pen = QtPen(glyph.getParent())
+    pen = QtPen(glyph.layer)
     glyph.draw(pen)
     pen.path.setFillRule(Qt.WindingFill)
     return pen.path
diff --git a/Lib/defconQt/resources/defaultColor.svg b/Lib/defconQt/resources/defaultColor.svg
new file mode 100644
index 0000000..0c343cb
--- /dev/null
+++ b/Lib/defconQt/resources/defaultColor.svg
@@ -0,0 +1,62 @@
+
+
-- 
cgit v1.2.3