This document outlines how Editra's icon theme system works and how create a custom theme for Editra. The theme system has been designed to provide an interface that emphasizes ease of creation, distribution, and usage. This means that creating a theme requires little to no programming, distribution is only a single file, and installation/usage is completely automated from Editra's interface.
The theme system described in this document is available for all versions of Editra > 0.2.0
Themes are part of Editra's plugin framework in order to provide an easy to customize and easy to install object. Typically programs that are theme-able require downloading and untarring dozens of files/directories and copying them to some configuration folder for the program to make use of them. Editra simplifies this whole process by making themes be a single binary file that requires no unpacking, and the whole installation system is also automated through the PluginManager. This means that themes are easily installed/updated/uninstalled with very little effort required from the user.
Since themes are part of the plugin framework the layout for creating a theme is very similar to that of a plugin. The layout described below outlines a typical setup for creating a theme and the components that are required. The description of actions and layout in this document will follow what is used by the current themes (Tango, Nuovo) and will allow you to create a complete theme without requiring any programming, if you wish to make customizations above and beyond what is shown here that is also possible.
Folders are indicated by [] and files are written plainly with each level of indentation indicating a child directory
[mytheme]
|
setup.py
[mytheme]
|
__init__.py
[pixmaps]
|
[menu]
[mime]
[toolbar]
With this layout now in mind we will walk step by step through what each of the items in the layout is and how to put it all together.
Included below is the full source for a setup.py file that can be used with a theme that is laid out as described in the above section. All that requires is changing all instances of MyTheme/mytheme to the name of what you want to call your theme and change and fill out any other of the entries about the plugin and yourself.
# -*- coding: utf-8 -*- # Setup script to build the MyTheme Theme. To build the plugin # just run 'python setup.py bdist_egg' and an egg will be built and put into # a directory called dist in the same folder as this script. """ """ __author__ = "Your Name" import sys try: from setuptools import setup except ImportError: print "You must have setup tools installed in order to build this plugin" setup = None if setup is not None: setup( name='MyTheme', version='0.1', description=__doc__, author=__author__, author_email="your@email.com", license="GPLv2", url="http://editra.org", platforms=["Linux", "OS X", "Windows"], packages=['mytheme'], package_data={'mytheme' : ['pixmaps/menu/*.png', 'pixmaps/toolbar/*.png', 'pixmaps/mime/*.png',]}, entry_points=''' [Editra.plugins] MyTheme = mytheme:MyThemeTheme ''' )
The theme file is a simple python script called __init__.py. This file is responsible for providing the icons from your theme to Editra. How the theme file is written is completely up to you but included below are the required elements of the interface as well as a complete theme file that can be used that only requires changing the name of theme in the file.
class ThemeI(plugin.Interface): """Interface for defining an icon theme in Editra When a icon theme is active Editra's ArtProvider will ask the active theme that implements this interface to give it a bitmap. The requests for bitmaps will be numerical ID values that come from ed_glob. These ID's are associated with different objects in the interface. The names are descriptive of the object they represent, for reference however see the implementation of the two main themes (Tango and Nuovo). @see: L{ed_glob.py} @see: L{syntax.synglob.py} """ def GetName(self): """Return the name of this theme. This is used to identify the theme when the provider looks for resources based on user preferences @return: name string """ def GetMenuBitmap(self, bmp_id): """Get the menu bitmap associated with the object id If this theme does not have a resource to provide for this object return a wx.NullBitmap. @return: 16x16 pixel bitmap """ return wx.NullBitmap def GetFileBitmap(self, bmp_id): """Get the filetype bitmap associated with the object id, the valid object ids are defined in the module syntax.synglob and are used to request images for menu's and page tabs. The theme implimenting this interface should at least be able to provide an image for plain text files and return that for any unmapped types. If this theme does not have a resource to provide for this object return a wx.NullBitmap. @return: 16x16 pixel bitmap """ return wx.NullBitmap def GetToolbarBitmap(self, bmp_id): """Get the toolbar bitmap associated with the object id. The toolbar icons must be returned as a 32x32 pixel bitmap any scaling that is needed will be handled by the art provider that requests the resource. If this theme does not have a resource to provide for this object return a wx.NullBitmap. @return: 32x32 pixel bitmap """ return wx.NullBitmap
Included below is a complete theme file that can be used if your theme uses the default icon file names defined in ed_theme.py (more on this later). The only change that is again needed is to change all instances of MyTheme to match the name of your theme.
############################################################################### # Name: __init__.py # # Purpose: Provides the MyTheme based icon theme for Editra # # Author: Cody Precord <cprecord@editra.org> # # Copyright: (c) 2007 Cody Precord <cprecord@editra.org> # # Licence: wxWindows Licence # ############################################################################### """MyTheme icon theme for Editra""" __author__ = "Cody Precord" __version__ = "0.1" import wx import os import cStringIO import ed_glob import plugin import ed_theme import syntax.synglob as synglob import syntax.syntax as syntax #-----------------------------------------------------------------------------# # Paths MENU_PATH = os.path.join('pixmaps', 'menu') + os.sep MIME_PATH = os.path.join('pixmaps', 'mime') + os.sep TOOL_PATH = os.path.join('pixmaps', 'toolbar') + os.sep #-----------------------------------------------------------------------------# class MyThemeTheme(plugin.Plugin): """Represents the MyTheme Icon theme for Editra""" plugin.Implements(ed_theme.ThemeI) def __LoadBitmapData(self, path): """Loads image data into a bitmap, returns None if there is a failure""" try: data = __loader__.get_data(os.path.join(__path__[0], path)) except IOError: pass else: bmp = wx.ImageFromStream(cStringIO.StringIO(data), wx.BITMAP_TYPE_PNG) return bmp.ConvertToBitmap() def GetName(self): return u'MyTheme' def GetMenuBitmap(self, bmp_id): if ed_theme.ART.has_key(bmp_id): path = MENU_PATH + ed_theme.ART[bmp_id] bmp = self.__LoadBitmapData(path) if bmp is not None: return bmp else: return self.GetFileBitmap(bmp_id) return wx.NullBitmap def GetFileBitmap(self, bmp_id): bmp = None if ed_theme.MIME_ART.has_key(bmp_id): path = MIME_PATH + ed_theme.MIME_ART[bmp_id] bmp = self.__LoadBitmapData(path) if bmp is not None: return bmp if bmp is None and bmp_id in syntax.SyntaxIds(): # Fail back to plain text bitmap bkup = MIME_PATH + ed_theme.MIME_ART[synglob.ID_LANG_TXT] bmp = self.__LoadBitmapData(bkup) if bmp is not None: return bmp return wx.NullBitmap def GetToolbarBitmap(self, bmp_id): if ed_theme.ART.has_key(bmp_id): path = TOOL_PATH + ed_theme.ART[bmp_id] bmp = self.__LoadBitmapData(path) if bmp is not None: return bmp return wx.NullBitmap
The icon files are looked up upon request by the theme file. The theme file shown in this document uses the default icon file names that are defined in ed_theme.py. These names can be added to and/or changed at runtime by your theme file but using the default names is the easiest method. Included below is a list of the default items that are available from ed_theme to reference when naming the icon files.
ART = { ed_glob.ID_ABOUT : u'about.png', # Used for About menu item ed_glob.ID_ADD_BM : u'bmark_add.png', # Add Bookmark menu item ed_glob.ID_BIN_FILE : u'bin_file.png', # Execute command/binary files icon ed_glob.ID_CDROM : u'cdrom.png', ed_glob.ID_CONTACT : u'mail.png', ed_glob.ID_COPY : u'copy.png', # Copy menu icon ed_glob.ID_COMPUTER : u'computer.png', ed_glob.ID_CUT : u'cut.png', ed_glob.ID_DELETE : u'delete.png', ed_glob.ID_DOCPROP : u'doc_props.png', # Prefdialog document button ed_glob.ID_DOWN : u'down.png', ed_glob.ID_EXIT : u'quit.png', ed_glob.ID_FILE : u'file.png', ed_glob.ID_FIND : u'find.png', ed_glob.ID_FIND_REPLACE : u'findr.png', ed_glob.ID_FLOPPY : u'floppy.png', ed_glob.ID_FOLDER : u'folder.png', ed_glob.ID_FONT : u'font.png', ed_glob.ID_HARDDISK : u'harddisk.png', ed_glob.ID_HOMEPAGE : u'web.png', ed_glob.ID_HTML_GEN : u'html_gen.png', ed_glob.ID_KWHELPER : u'kw_help.png', ed_glob.ID_NEW : u'new.png', ed_glob.ID_NEW_WINDOW: u'newwin.png', ed_glob.ID_NEXT_MARK : u'bmark_next.png', ed_glob.ID_OPEN : u'open.png', ed_glob.ID_PACKAGE : u'package.png', ed_glob.ID_PASTE : u'paste.png', ed_glob.ID_PLUGMGR : u'plugin.png', # image to represent plugins ed_glob.ID_PRE_MARK : u'bmark_pre.png', ed_glob.ID_PREF : u'pref.png', ed_glob.ID_PRINT : u'print.png', ed_glob.ID_PRINT_PRE : u'printpre.png', ed_glob.ID_REDO : u'redo.png', ed_glob.ID_RTF_GEN : u'rtf_gen.png', ed_glob.ID_SAVE : u'save.png', ed_glob.ID_SAVEAS : u'saveas.png', ed_glob.ID_STYLE_EDIT : u'style_edit.png', ed_glob.ID_TEX_GEN : u'tex_gen.png', ed_glob.ID_THEME : u'theme.png', ed_glob.ID_UNDO : u'undo.png', ed_glob.ID_UP : u'up.png', ed_glob.ID_USB : u'usb.png', ed_glob.ID_WEB : u'web.png', # Used for downloading/web related actions ed_glob.ID_ZOOM_IN : u'zoomi.png', ed_glob.ID_ZOOM_OUT : u'zoomo.png', ed_glob.ID_ZOOM_NORMAL : u'zoomd.png' }
MIME_ART = { synglob.ID_LANG_BASH : u'shell.png', synglob.ID_LANG_BOURNE : u'shell.png', synglob.ID_LANG_C : u'c.png', synglob.ID_LANG_CPP : u'cpp.png', synglob.ID_LANG_CSH : u'shell.png', synglob.ID_LANG_CSS : u'css.png', synglob.ID_LANG_HTML : u'html.png', synglob.ID_LANG_JAVA : u'java.png', synglob.ID_LANG_KSH : u'shell.png', synglob.ID_LANG_LATEX : u'tex.png', synglob.ID_LANG_MAKE : u'makefile.png', synglob.ID_LANG_PERL : u'perl.png', synglob.ID_LANG_PHP : u'php.png', synglob.ID_LANG_PYTHON : u'python.png', synglob.ID_LANG_RUBY : u'ruby.png', synglob.ID_LANG_TCL : u'tcl.png', synglob.ID_LANG_TEX : u'tex.png', synglob.ID_LANG_TXT : u'text.png', synglob.ID_LANG_XML : u'xml.png' }
As can be seen there are allot of resources and these are only a list of the most common ones, as mapping icons to any of the ID_* values defined in ed_glob.py is possible with the theme system and will enable it to automatically associate icons where necessary. The good news is that for a theme to be usable you only need to define and provide a small subset of items shown above.
This is a list of the required icon mappings that a theme needs to provide in order to keep the editor working smoothly.
Ideally a theme should define all of these toolbar icons. All toolbar icons must be 32x32 pixels in size and reside in the toolbar folder.
ed_glob.ID_COPY : u'copy.png' # Copy Text ed_glob.ID_CUT : u'cut.png' # Cut Text ed_glob.ID_DOCPROP : u'doc_props.png' # Preferences Dialog Document button ed_glob.ID_FIND : u'find.png' # Find button ed_glob.ID_FIND_REPLACE : u'findr.png' # Find and Replace button ed_glob.ID_NEW : u'new.png' # New Document button ed_glob.ID_OPEN : u'open.png' # Open Document (usually a folder opening image) ed_glob.ID_PACKAGE : u'package.png' # PluginManager Install button ed_glob.ID_PASTE : u'paste.png' # Paste Text ed_glob.ID_PREF : u'pref.png' # Pref Dialog General/PluginManager Config button ed_glob.ID_PRINT : u'print.png' # Print button ed_glob.ID_REDO : u'redo.png' # Redo button ed_glob.ID_SAVE : u'save.png' # Save button ed_glob.ID_THEME : u'theme.png' # Pref Dialog Appearance button ed_glob.ID_UNDO : u'undo.png' # Undo button ed_glob.ID_WEB : u'web.png' # Download/Update button
No menu icons are actually required but here is a list of some of the important ones that a good theme should provide as a minimum. All menu icons must be 16x16 pixels in size and reside in the menu folder.
ed_glob.ID_BIN_FILE : u'bin_file.png' # Represent binary files ed_glob.ID_CDROM : u'cdrom.png' # Cdrom image ed_glob.ID_COMPUTER : u'computer.png' # Computer image ed_glob.ID_DOWN : u'down.png' # Down arrow ed_glob.ID_FILE : u'file.png' # Generic file icon ed_glob.ID_FLOPPY : u'floppy.png' # Floppy disk ed_glob.ID_FOLDER : u'folder.png' # Generic folder icon ed_glob.ID_HARDDISK : u'harddisk.png' # Hardisk image ed_glob.ID_OPEN : u'open.png' # Open folder icon ed_glob.ID_PLUGMGR : u'plugin.png' # Plugin image ed_glob.ID_PREF : u'pref.png' # Prefrences/config icon (used in many places) ed_glob.ID_UP : u'up.png' # Up arrow ed_glob.ID_USB : u'usb.png' # Removable device icon ed_glob.ID_WEB : u'web.png' # Represent web related items (usually a globe)
Just as with the menu icons none of these are actually required but a good theme should be able to at least provide an icon to represent a plain text file as it is used as the default when a more specific one cannot be found. These icons must be 16x16 pixels in size and reside in the mime folder.
synglob.ID_LANG_TXT : u'text.png' # Plain Text File