diff --git a/apps/icons/classes.py b/apps/icons/classes.py index e3efeb1139..8c88ec732d 100644 --- a/apps/icons/classes.py +++ b/apps/icons/classes.py @@ -2,26 +2,60 @@ from __future__ import absolute_import import os +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + +import PIL + from django.utils.safestring import mark_safe from django.conf import settings -from .literals import ERROR, SIZE_SMALL, SIZE_BIG +from .literals import (ERROR, SIZE_SMALL, SIZE_BIG, ICONSETS_STATIC_DIRECTORY) class Icon(object): _registry = {} + _cache = {} def __init__(self, id, icon_set=None): self.id = id self.icon_set = icon_set self.__class__._registry[id] = self - def get_url(self, size): + def get_iconset(self): from .settings import ICON_SET - return IconSetBase.get_by_name(self.icon_set or ICON_SET).get_url(self, size) + return IconSetBase.get_by_name(self.icon_set or ICON_SET) + + #def get_url(self, size): + # #from .settings import ICON_SET + # #return IconSetBase.get_by_name(self.icon_set or ICON_SET).get_url_of_icon(self, size) + # return self.get_iconset().get_url_of_icon(self, size) + + #def get_as_base64(self, size): + # from .settings import ICON_SET + # return IconSetBase.get_by_name(self.icon_set or ICON_SET).get_as_base64(self, size) + + #def get_as_filename(self, size): + # #from .settings import ICON_SET + # #return IconSetBase.get_by_name(self.icon_set or ICON_SET).get_filename_of_icon(self, size) + # return self.get_iconset().get_filename_of_icon(self, size) def display(self, size): # TODO: move to widgets? - return mark_safe('' % (settings.STATIC_URL, self.get_url(size))) + #return mark_safe('' % self.get_url(size)) + #return mark_safe('' % self.get_as_base64(size)) + #return mark_safe('' % self.process(size)) + #return mark_safe('' % self.get_iconset().compose(self, size)) + + # Cache a composed icon result for a specific size + try: + result = self.__class__._cache['%d_%s' % (id(self), size)] + except KeyError: + result = self.get_iconset().compose(self, size) + self.__class__._cache['%d_%s' % (id(self), size)] = result + + return mark_safe('' % result) def display_small(self): return self.display(SIZE_SMALL) @@ -29,12 +63,6 @@ class Icon(object): def display_big(self): return self.display(SIZE_BIG) - #def get_filepath(self): - # if settings.DEVELOPMENT: - # return os.path.join(settings.PROJECT_ROOT, 'apps', 'icons', 'static', 'icons', self.get_file_name(SIZE_BIG)) - # else: - # return os.path.join(settings.STATIC_ROOT, self.get_file_name(SIZE_BIG)) - class IconSetBase(object): _registry = {} @@ -50,9 +78,74 @@ class IconSetBase(object): def __init__(self): self.__class__._registry[self.name] = self - def get_filename(self, icon, size): - return os.path.join([self.path, size, self.dictionary.get(icon.id, ERROR)]) - - def get_url(self, icon, size): - return '%s/%s/%s' % (self.path, size, self.dictionary.get(icon.id, ERROR)) + #def get_filename_of_icon(self, icon, size): + # if settings.DEVELOPMENT: + # return os.path.join(settings.PROJECT_ROOT, 'apps', 'icons', 'static', ICONSETS_STATIC_DIRECTORY, self.directory, size, self.dictionary.get(icon.id, ERROR)) + # else: + # return os.path.join(settings.STATIC_ROOT, ICONSETS_STATIC_DIRECTORY, self.directory, size, self.dictionary.get(icon.id, ERROR)) + + def get_filename_of_image(self, image_name, size): + if settings.DEVELOPMENT: + return os.path.join(settings.PROJECT_ROOT, 'apps', 'icons', 'static', ICONSETS_STATIC_DIRECTORY, self.directory, size, image_name) + else: + return os.path.join(settings.STATIC_ROOT, ICONSETS_STATIC_DIRECTORY, self.directory, size, image_name) + + #def get_url_of_icon(self, icon, size): + # return '%s%s/%s/%s/%s' % (settings.STATIC_URL, ICONSETS_STATIC_DIRECTORY, self.directory, size, self.dictionary.get(icon.id, ERROR)) + + def get_major_minor(self, icon): + return self.dictionary.get(icon.id, ERROR) + + def compose(self, icon, size): + try: + major, minor = self.get_major_minor(icon) + except ValueError: + major = self.get_major_minor(icon) + minor = None + + major_image = PIL.Image.open(self.get_filename_of_image(major, size)) + if minor: + major_width, major_height = major_image.size + minor_image = PIL.Image.open(self.get_filename_of_image(minor, size)) + minor_image.thumbnail((major_width / 1.6, major_height / 1.6))#, PIL.Image.ANTIALIAS) + minor_width, minor_height = minor_image.size + major_image.paste(minor_image, (major_width - minor_width, major_height - minor_height), minor_image) + + output = StringIO() + major_image.save(output, 'PNG') + contents = output.getvalue().encode('base64') + output.close() + return 'data:image/png;base64,%s' % contents + + +class Verb(object): + pass + + +class Load(Verb): + def __init__(self, filename): + self.filename = filename + def execute(self): + return PIL.Image.open(self.filename) + + +class Resize(Verb): + def __init__(self, image, size, antialias=False): + self.image = image + self.size = size + self.antialias = antialias + + def execute(self): + if self.antialias: + self.image.thumbnail(self.size, PIL.Image.ANTIALIAS) + else: + self.image.thumbnail(self.size) + + +class Rotate(Verb): + def __init__(self, degrees): + self.degrees = degrees + + def execute(self): + pass diff --git a/apps/icons/iconsets/custom.py b/apps/icons/iconsets/custom.py index e15ef371d4..8a2ad00fcd 100644 --- a/apps/icons/iconsets/custom.py +++ b/apps/icons/iconsets/custom.py @@ -8,6 +8,7 @@ class IconSet(IconSetBase): path = 'custom' name = 'custom' label = _(u'Custom') + directory='custom' dictionary = { FILE_EXTENSION_ERROR: 'file_extension_error.png', FILE_EXTENSION_UNKNOWN: 'file_extension_unknown.png' diff --git a/apps/icons/iconsets/fat_cow.py b/apps/icons/iconsets/fat_cow.py index 9079981a30..d057b317ad 100644 --- a/apps/icons/iconsets/fat_cow.py +++ b/apps/icons/iconsets/fat_cow.py @@ -7,20 +7,25 @@ from icons.classes import IconSetBase class IconSet(IconSetBase): name='fat_cow' label=_(u'Fat cow') - path='fat_cow' + directory='fat_cow' + available_sizes=['32x32', '16x16'] dictionary={ ADD: 'add.png', APPLICATION_VIEW_ICONS: 'application_view_icons.png', ARROW_TURN_RIGHT: 'arrow_turn_right.png', ARROW_TURN_LEFT: 'arrow_turn_left.png', ARROW_UP: 'arrow_up.png', - BIN_CLOSED: 'bin_closed.png', BIN: 'bin.png', + BIN_CLOSED: 'bin_closed.png', BIN_EMPTY: 'bin_empty.png', + BIN_EMPTY_OUT: ['bin_empty.png', 'arrow_turn_right.png'], + BIN_MULTIPLE: ['bin_closed.png', 'bin_closed.png'], + BIN_RECYCLE: ['bin.png', 'recycle.png'], BLACKBOARD_SUM: 'blackboard_sum.png', BOOK: 'book.png', BOOK_GO: 'book_go.png', BOOK_OPEN: 'book_open.png', + BULLET_GO: 'bullet_go.png', CAMERA_DELETE: 'camera_delete.png', CD_BURN: 'cd_burn.png', COG: 'cog.png', @@ -59,6 +64,7 @@ class IconSet(IconSetBase): GROUP_DELETE: 'group_delete.png', GROUP_KEY: 'group_key.png', GROUP_LINK: 'group_link.png', + GROUP_MEMBERS: ['group.png', 'arrow_refresh.png'], HOURGLASS: 'hourglass.png', HOUSE: 'house.png', INDEX: 'index.png', @@ -86,8 +92,12 @@ class IconSet(IconSetBase): MAGNIFIER: 'magnifier.png', MEDAL_GOLD: 'medal_gold_1.png', MEDAL_GOLD_ADD: 'medal_gold_add.png', + MEDAL_GOLD_EDIT: ['medal_gold_1.png', 'pencil.png'], MEDAL_GOLD_DELETE: 'medal_gold_delete.png', - NODE: 'node.png', + NODE_TREE: 'node-tree.png', + NODE_TREE_ADD: ['node-tree.png', 'add.png'], + NODE_TREE_EDIT: ['node-tree.png', 'pencil.png'], + NODE_TREE_DELETE: ['node-tree.png', 'delete.png'], PACKAGE: 'package.png', PAGE: 'page.png', PAGE_COPY: 'page_copy.png', @@ -126,7 +136,7 @@ class IconSet(IconSetBase): TAB_ADD: 'tab_add.png', TAB_DELETE: 'tab_delete.png', TAB_EDIT: 'tab_edit.png', - TAB_VIEW: 'tab_view.png', + TAB_GO: 'tab_go.png', TABLE: 'table.png', TABLE_ADD: 'table_add.png', TABLE_EDIT: 'table_edit.png', @@ -154,12 +164,17 @@ class IconSet(IconSetBase): VCARD: 'vcard.png', VCARD_EDIT: 'vcard_edit.png', WIZARD: 'wizard.png', + WIZARD_ADD: ['wizard.png', 'add.png'], + WIZARD_DELETE: ['wizard.png', 'delete.png'], + WIZARD_EDIT: ['wizard.png', 'pencil.png'], + WIZARD_LIGHTNING: ['wizard.png', 'lightning.png'], WORLD_GO: 'world_go.png', WRENCH: 'wrench.png', XHTML: 'xhtml.png', XHTML_GO: 'xhtml_go.png', XHTML_ADD: 'xhtml_add.png', XHTML_DELETE: 'xhtml_delete.png', + XHTML_EDIT: ['xhtml.png', 'pencil.png'], ZOOM: 'zoom.png', ZOOM_IN: 'zoom_in.png', ZOOM_OUT: 'zoom_out.png', diff --git a/apps/icons/literals.py b/apps/icons/literals.py index 63a4d6c31e..42718b06c8 100644 --- a/apps/icons/literals.py +++ b/apps/icons/literals.py @@ -2,6 +2,7 @@ SIZE_SMALL = '16x16' SIZE_BIG = '32x32' DEFAULT_ICON_SET = 'fat_cow' +ICONSETS_STATIC_DIRECTORY = 'icons' ADD = 'add' APPLICATION_VIEW_ICONS = 'application_view_icons' @@ -11,10 +12,14 @@ ARROW_UP = 'arrow_up' BIN_CLOSED = 'bin_closed' BIN = 'bin' BIN_EMPTY = 'bin_empty' +BIN_EMPTY_OUT = 'bin_empty_out' +BIN_MULTIPLE = 'bin_multiple' +BIN_RECYCLE = 'bin_recyle' BLACKBOARD_SUM = 'blackboard_sum' BOOK = 'book' BOOK_GO = 'book_go' BOOK_OPEN = 'book_open' +BULLET_GO = 'bullet_go' CAMERA_DELETE = 'camera_delete' CD_BURN = 'cd_burn' COG = 'cog' @@ -49,12 +54,13 @@ FOLDER_DELETE = 'folder_delete' FOLDER_GO = 'folder_go' FOLDER_PAGE = 'folder_page' FOLDER_USER = 'folder_user' -GROUP = 'user' +GROUP = 'group' GROUP_ADD = 'group_add' GROUP_EDIT = 'group_edit' GROUP_DELETE = 'group_delete' GROUP_KEY = 'group_key' GROUP_LINK = 'group_link' +GROUP_MEMBERS = 'group_members' HOURGLASS = 'hourglass' HOUSE = 'house' INDEX = 'index' @@ -82,8 +88,12 @@ MAGIC_WAND_2 = 'magic_wand_2' MAGNIFIER = 'magnifier' MEDAL_GOLD = 'medal_gold' MEDAL_GOLD_ADD = 'medal_gold_add' +MEDAL_GOLD_EDIT = 'medal_gold_edit' MEDAL_GOLD_DELETE = 'medal_gold_delete' -NODE = 'node' +NODE_TREE = 'node_tree' +NODE_TREE_ADD = 'node_tree_add' +NODE_TREE_EDIT = 'node_tree_edit' +NODE_TREE_DELETE = 'node_tree_delete' PACKAGE = 'package' PAGE = 'page' PAGE_COPY = 'page_copy' @@ -122,7 +132,7 @@ TAB = 'tab' TAB_ADD = 'tab_add' TAB_DELETE = 'tab_delete' TAB_EDIT = 'tab_edit' -TAB_VIEW = 'tab_view' +TAB_GO = 'tab_go' TABLE = 'table' TABLE_ADD = 'table_add' TABLE_EDIT = 'table_edit' @@ -150,12 +160,17 @@ USER_SILHOUETTE = 'user_silhouette' VCARD = 'vcard' VCARD_EDIT = 'vcard_edit' WIZARD = 'wizard' +WIZARD_ADD = 'wizard_add' +WIZARD_DELETE = 'wizard_delete' +WIZARD_EDIT = 'wizard_edit' +WIZARD_LIGHTNING = 'wizard_lightning' WORLD_GO = 'world_go' WRENCH = 'wrench' XHTML = 'xhtml' XHTML_GO = 'xhtml_go' XHTML_ADD = 'xhtml_add' XHTML_DELETE = 'xhtml_delete' +XHTML_EDIT = 'xhtml_edit' ZOOM = 'zoom' ZOOM_IN = 'zoom_in' ZOOM_OUT = 'zoom_out'