Add icon composition support, add several combined new icons, switch to icon base64 redering
This commit is contained in:
@@ -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('<img style="vertical-align: middle;" src="%sicons/%s" />' % (settings.STATIC_URL, self.get_url(size)))
|
||||
#return mark_safe('<img style="vertical-align: middle;" src="%s" />' % self.get_url(size))
|
||||
#return mark_safe('<img style="vertical-align: middle;" src="%s" />' % self.get_as_base64(size))
|
||||
#return mark_safe('<img style="vertical-align: middle;" src="%s" />' % self.process(size))
|
||||
#return mark_safe('<img style="vertical-align: middle;" src="%s" />' % 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('<img style="vertical-align: middle;" src="%s" />' % 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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user