Editor:Redesign

From FIFE development wiki
Jump to: navigation, search

This article is outdated and is just stored for archive purposes. Archived.png

This article became outdated and is just stored for archive purposes in this wiki. There are several reasons why an article could become outdated. The development team may have decided to use a different concept or even the author itself felt that the article is not really up-to-date with the current development status of the project anymore.

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

Fifedit mockup.png

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.

  1. TODO: This probably needs some work. Suggestions are welcome.
Examples

UnrealEd toolbar.

Unrealed toolbar.png

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.