Editor:Redesign
This article is part of design documentation.
Design documentation describes how software is implemented or is about to be implemented. It focuses on system structure (e.g. dependencies), module interactions and relevant algorithms. Concepts described in these articles should form the terminology that is used when discussing about the software that forms FIFE.
This article is currently only a proposal
The features or design guidelines described in this article are only a proposal made by one or some persons. It has not been reviewed and ratified by the core development team yet. Feel free to add your personal opinion about them or make counter proposals.
Contents |
Introduction
Proposals for the redesign of the editor.
You can find the editor rewrite branch in Trac.
Core
UndoManager
Main article: Editor:Proposal:UndoManager
UndoManager provides an easy way to keep track of the actions the user has done, and allow the user to undo/redo those actions.
PluginManager
TODO: Write a short summary of the plugin manager here
Main article: Editor:Proposal:Plugin format
Editor
This class is the main window for FIFEdit. It sets up the GUI and initializes the FIFE engine. Tools and plugins use this class to get access to the subsystems.
Editor interface
# Global function to return the editor instance Editor getEditor()
class Editor extends ApplicationBase object getStatusBar() object getMenuBar() object getToolBar() object getToolbox() object getPluginManager() Engine getEngine() list getMapViews() object getActiveMapView() EventMapper getEventListener() EventMapper createListener() object openFile(string path) void saveAll() # Used by getEditor() Editor editor #--- Inherited methods ---# # ApplicationBase void loadSettings() void initLogging() ExitEventListener createListener() # This one is overridden unknown run() unknown mainLoop() void breakFromMainLoop(unknown returnValue) void _pump() void quit() #--- Inherited attributes ---# # ApplicationBase Engine engine
Event handling
We will use Django's signal class with minor modifications. As Django is licensed under the BSD License, this should not be a problem.
EventListener listens for events from the Engine, and sends signals (quit, showconsole, etc).
Changes to Signal class, compared to django version:
- Remove django specific imports
- Receivers aren't needed to accept any arguments, through the use of pychan.tools.applyOnlySuitable
- send works on a copy of an array to avoid problems when connecting/disconnecting listeners
Interface
class Signal:
"""Base class for all signals
Internal attributes:
receivers -- { receiverkey(id) : weakref(receiver) }
"""
Signal(providing_args=None):
"""providing_args -- A list of the arguments this signal can pass along in
a send() call.
"""
void connect(receiver, sender=None, weak=True, dispatch_uid=None):
"""Connect receiver to sender for signal
receiver -- a function or an instance method which is to
receive signals. Receivers must be
hashable objects.
if weak is True, then receiver must be weak-referencable
(more precisely saferef.safeRef() must be able to create
a reference to the receiver).
If receivers have a dispatch_uid attribute, the receiver will
not be added if another receiver already exists with that
dispatch_uid.
sender -- the sender to which the receiver should respond
Must either be of type Signal, or None to receive events
from any sender.
weak -- whether to use weak references to the receiver
By default, the module will attempt to use weak
references to the receiver objects. If this parameter
is false, then strong references will be used.
dispatch_uid -- an identifier used to uniquely identify a particular
instance of a receiver. This will usually be a string, though it
may be anything hashable.
returns None
"""
void disconnect(receiver=None, sender=None, weak=True, dispatch_uid=None):
"""Disconnect receiver from sender for signal
receiver -- the registered receiver to disconnect. May be none if
dispatch_uid is specified.
sender -- the registered sender to disconnect
weak -- the weakref state to disconnect
dispatch_uid -- the unique identifier of the receiver to disconnect
disconnect reverses the process of connect.
If weak references are used, disconnect need not be called.
The receiver will be remove from dispatch automatically.
returns None
"""
list send(sender, **named):
"""Send signal from sender to all connected receivers.
sender -- the sender of the signal
Either a specific object or None.
named -- named arguments which will be passed to receivers.
Returns a list of tuple pairs [(receiver, response), ... ].
If any receiver raises an error, the error propagates back
through send, terminating the dispatch loop, so it is quite
possible to not have all receivers called if a raises an
error.
"""
list send_robust(sender, **named):
"""Send signal from sender to all connected receivers catching errors
sender -- the sender of the signal
Can be any python object (normally one registered with
a connect if you actually want something to occur).
named -- named arguments which will be passed to receivers.
These arguments must be a subset of the argument names
defined in providing_args.
Return a list of tuple pairs [(receiver, response), ... ],
may raise DispatcherKeyError
if any receiver raises an error (specifically any subclass of Exception),
the error instance is returned as the result for that receiver.
"""
class EventListener extends
IKeyListener,
ICommandListener,
IMouseListener,
LayerChangeListener,
MapChangeListener,
ConsoleExecuter:
#--- Inherited methods ---#
# IKeyListener
void keyPressed (KeyEvent evt)
void keyReleased (KeyEvent evt)
# ICommandListener
void onCommand (Command command)
# IMouseListener
void mouseEntered(MouseEvent evt)
void mouseExited(MouseEvent evt)
void mousePressed(MouseEvent evt)
void mouseReleased(MouseEvent evt)
void mouseClicked(MouseEvent evt)
void mouseWheelMovedUp(MouseEvent evt)
void mouseWheelMovedDown(MouseEvent evt)
void mouseMoved(MouseEvent evt)
void mouseDragged(MouseEvent evt)
# LayerChangeListener
void onLayerChanged(Layer layer, vector<Instance> changedInstances)
void onInstanceCreate(Layer layer, Instance instance)
void onInstanceDelete(Layer layer, Instance instance)
# MapChangeListener
void onMapChanged(Map map, vector<Layer> changedLayers)
void onLayerCreate(Map map, Layer layer)
void onLayerDelete(Map map, Layer layer)
# ConsoleExecuter
void onToolsClick()
string onConsoleCommand(string command)
MapView
MapView represents an open map.
Interface
class MapView: MapView(object Map) object getUndoManager() object getMap() object getCamera() void undo() void redo() void importFile(string path) void importDir(string path, bool recursive=False void show() void save() void saveAs(string filename) void close()
MapController
MapController provides an interface plugins and utilities can use if they need to edit a map. They may also choose to ignore this, and manipulate the map directly.
This is extracted from the old MapEdit plugin, and will need some work:
class MapController:
MapController(map) void setMap(mapid) void selectLayer(layerid) void selectObject(object) void selectCell(screenx, screeny, preciseCoords=False) list getInstancesFromPosition(position, top_only) void undo() void placeInstance(position,object) void removeInstances(position) void moveInstances() void rotateInstances() void changeRotation() void moveCamera(screen_x, screen_y)
GUI
Mock-up
Inspired by Adobe CS3 and mock-up.
The dock widgets can be docked in any of the four sides of the screen. If the widget is docked on the top, it will be placed under the toolbar or menubar. Dock widgets can also be floating windows. If the toolbox is docked, and there are dockwidgets in that side, the toolbox will be placed nearest the mapview.
Dockwidgets can be added to, removed from and reordered in tab widgets by using drag and drop.
This is the way the Adobe Creative Suite interface works.
Widgets for pychan
These widgets may be added to pychan. See this forum thread.
StatusBar
The StatusBar class provides a horizontal bar suitable for presenting status information.
Interface
class StatusBar extends pychan.HBox: void setText(string text) string getText() text = property(getText, setText) # Shows a text which is visible until hideTooltip is called void showTooltip(string text) # Removes the text set by showTooltip. Whatever text previously set by setText is then displayed. void hideTooltip()
Toolbar
The toolbar is a horisontal panel with buttons that provides quick access to commonly used tools.
- TODO: This probably needs some work. Suggestions are welcome.
Examples
UnrealEd toolbar.
Interface
ORIENTATION = {
"Horizontal" : 0,
"Vertical" : 1
}
BUTTON_STYLE = {
"IconOnly" : 0,
"TextOnly" : 1,
"TextUnderIcon" : 2,
"TextBesideIcon" : 3
}
class ToolbarButton extends pychan.VBox: ToolbarButton(Action action, int button_style=0) void setAction(Action action, int button_style=0) Action getAction() action = property(getAction, setAction) void setButtonStyle(int button_style) int getButtonStyle() button_style = property(getButtonStyle, setButtonStyle) def update()
class ToolBar extends pychan.HBox: ToolBar(int button_style=0, int orientation=0, bool auto_expand=True, int panel_size=30) void addSeparator(object separator=None): void insertSeparator(object separator=None, int position=0, object before=None) void addAction(object action) void hasAction(object action) void insertAction(object action, int position=0, object before=None) void removeAction(object action) void hasAction(object action) void setButtonStyle(int button_style) int getButtonStyle() button_style = property(getButtonStyle, setButtonStyle) int getOrientation() void setOrientation(int orientation) orientation = property(getOrientation, setOrientation) bool getAutoExpand() void setAutoExpand(bool auto_expand) void setPanelSize(int size) int getPanelSize() panel_size = property(getPanelSize, setPanelSize) void setDocked(bool docked) bool isFloating() void clear()
Toolbox
The toolbox is a floating toolbar and contains only buttons to manipulate the current document (draw, move, zoom, etc)
Examples
Toolbox in Photoshop and UnrealEd.
MenuBar
Interface
class Menu extends pychan.VBox: Menu(string title, string icon=None) void addItem(object item) void insertItem(object item, object before) void insertItemAt(object item, int index) void removeItem( object item ) void clear() void show() void hide() void setPosition(int x, int y)
class MenuBar extends pychan.HBox: void insertItem(object item, object before) void insertItemAt(object item, int index) void removeItem(object item) void clear()
Menubar, toolbar and toolbox data
Something like this would be nice: QAction.
Action
class Action: Action(string text="", string icon="", bool separator=False, bool checkable=False, checked=False) void activate() void setSeparator() bool isSeparator() void _setText(string text) string _getText() text = property(_getText, _setText) void _setIcon(string icon) string _getIcon() icon = property(_getIcon, _setIcon) void _setShortcut(string keysequence) string _getShortcut() shortcut = property(_getShortcut, _setShortcut) void _setHelpText(string helptext) string _getHelpText() helptext = property(_getHelpText, _setHelpText) void setEnabled(bool enabled) bool isEnabled() void setChecked(bool checked) bool isChecked() void setCheckable(bool checkable) bool isCheckable() # Emits signals: # changed() # toggled(bool) # activated()
class ActionGroup: ActionGroup(exclusive=False, name="ActionGroup") void setEnabled(bool enabled) bool isEnabled () enabled = property(isEnabled, setEnabled) void setExclusive(bool exclusive) bool isExclusive() void addAction(object action) void addSeparator() void removeAction(object action) list getActions() void clear() bool hasAction(object action) object getChecked() # Emits signals: # changed()
InputDialog
InputDialog shows a dialog with a textfield, a cancel button and an OK button.
SelectionDialog
SelectionDialog shows a dialog with a list of options to choose from. When the user clicks the OK button the dialog is hidden, and the supplied callback function is called. This dialog can also be configured to fire the callback when an item is selected.
Editor-specific widgets
Map wizard
New map wizard.
ObjectSelector
Allows you to choose which object to paint on the map.
ObjectEditor
Edits instance properties.
LayerTool
A dialog to show the layers on the map and allows you hide layers and choose the layer to edit.
HistoryBrowser
A tool to browse undo history.
See the undo manager article.
Plugin manager dialog
A dialog to browse plugins.
See the pluginmanager article.
