Skip to content

Commit

Permalink
Use text-based 16x16 icons
Browse files Browse the repository at this point in the history
  • Loading branch information
nico authored and b4winckler committed Feb 1, 2009
1 parent 243fcce commit cca95ba
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 46 deletions.
18 changes: 16 additions & 2 deletions src/MacVim/icons/Makefile
Expand Up @@ -2,10 +2,24 @@

OUTDIR ?= .

$(OUTDIR)/MacVim-generic.icns: make_icons.py vim-noshadow-512.png
$(OUTDIR)/MacVim-generic.icns: make_icons.py vim-noshadow-512.png loadfont.so Envy\ Code\ R\ Bold.ttf
$(MAKE) -C makeicns
/usr/bin/python make_icons.py $(OUTDIR)

loadfont.so: loadfont.c
gcc -o $@ $^ -bundle \
-framework Python \
-framework CoreFoundation \
-framework ApplicationServices

Envy\ Code\ R\ Bold.ttf: EnvyCodeR.zip
unzip -jo EnvyCodeR.zip

ENVYCODE_URL=http://download.damieng.com/latest/EnvyCodeR
EnvyCodeR.zip:
curl ${ENVYCODE_URL} --location -o EnvyCodeR.zip

clean:
$(MAKE) -C makeicns clean
rm -f $(OUTDIR)/MacVim-*.icns *.pyc
rm -f $(OUTDIR)/MacVim-*.icns loadfont.so *.pyc \
EnvyCodeR.zip *.ttf *.reg *.txt
85 changes: 52 additions & 33 deletions src/MacVim/icons/docerator.py
Expand Up @@ -445,13 +445,6 @@ def saneBasename(p):
return '%s-%s.icns' % (base, textPart)


def makedocicon(**kwargs):
options, _ = getopts().parse_args([]) # get default options
for k in kwargs:
setattr(options, k, kwargs[k])
makedocicon_opts(options)


def cachedImage(filename):
absPath = os.path.abspath(filename)
if not absPath in imageCache:
Expand Down Expand Up @@ -490,41 +483,59 @@ def getBgName(options):
return options.background


class IconGenerator(object):
def __init__(self, options):
if hasattr(options, 'textrenderer') and options.textrenderer:
self.textRenderer = options.textrenderer()
else:
self.textRenderer = TextRenderer()

# Prepare input images
splitBackground = options.background == 'default-split'
self.bgIcon = cachedImage(getBgName(options))

self.testIcon = None
if options.appicon:
self.testIcon = cachedImage(options.appicon)

rects = defaultRects.copy()
rects[16] = [ 0.0000, 0.5000, -1.0000, 0.5000] # manually, better
if hasattr(options, 'rects'):
rects.update(options.rects)

bg = cachedBackground(self.bgIcon, splitBackground)

if hasattr(options, 'backgroundrenderer') and options.backgroundrenderer:
self.bgRenderer = options.backgroundrenderer(bg, self.testIcon, rects)
else:
self.bgRenderer = BackgroundRenderer(bg, self.testIcon, rects)

self.testtext = textDictFromTextList(options.text.split(','))

def createIconAtSize(self, s):
return createIcon(s, self.bgRenderer, self.textRenderer, self.testtext)


def iconGenerator(**kwargs):
return IconGenerator(optsFromDict(**kwargs))


def makedocicon_opts(options):
textRenderer = TextRenderer()

# Prepare input images
bgIcon = None
splitBackground = options.background == 'default-split'
bgIcon = cachedImage(getBgName(options))

testIcon = None
if options.appicon:
testIcon = cachedImage(options.appicon)
renderer = IconGenerator(options)

if hasattr(options, 'sizes') and options.sizes:
if isinstance(options.sizes, list):
sizes = options.sizes
else:
sizes = map(int, options.sizes.split(','))
else:
sizes = bgIcon.sizes()
if testIcon:
sizes = sizes.intersection(testIcon.sizes())
sizes = renderer.bgIcon.sizes()
if renderer.testIcon:
sizes = sizes.intersection(renderer.testIcon.sizes())
sizes = sorted(map(operator.itemgetter(0), sizes))

if not hasattr(options, 'rects') or not options.rects:
rects = defaultRects.copy()
rects[16] = [ 0.0000, 0.5000, -1.0000, 0.5000] # manually, better
else:
rects = options.rects

bg = cachedBackground(bgIcon, splitBackground)
bgRenderer = BackgroundRenderer(bg, testIcon, rects)
icons = dict([(s, renderer.createIconAtSize(s)) for s in sizes])

testtext = textDictFromTextList(options.text.split(','))
icons = dict([(s, createIcon(s, bgRenderer, textRenderer, testtext))
for s in sizes])
if options.debug:
for s, icon in icons.iteritems():
icon.save(options.debug % s)
Expand All @@ -539,11 +550,15 @@ def makedocicon_opts(options):
print 'Failed to write %s. Make sure makeicns is in your path.' % outname


def makedocicons(**kwargs):
def optsFromDict(**kwargs):
options, _ = getopts().parse_args([]) # get default options
for k in kwargs:
setattr(options, k, kwargs[k])
makedocicons_opts(options)
return options


def makedocicon(**kwargs):
makedocicon_opts(optsFromDict(**kwargs))


def makedocicons_opts(options):
Expand All @@ -555,6 +570,10 @@ def makedocicons_opts(options):
makedocicon_opts(options)


def makedocicons(**kwargs):
makedocicons_opts(optsFromDict(**kwargs))


def getopts():
parser = OptionParser(usage='%prog [options]', version='%prog 1.01')
parser.add_option('--background', '--bg', default='default-split',
Expand Down
56 changes: 56 additions & 0 deletions src/MacVim/icons/loadfont.c
@@ -0,0 +1,56 @@
// A small python module that registers a font with ATS, given the name of
// the font.

#include <Python/Python.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Carbon/Carbon.h>

static PyObject* loadfont(PyObject* self, PyObject* args) {
PyObject* result = Py_False;
const char* path = NULL;
int ok = PyArg_ParseTuple(args, "s", &path);

if (ok) {
CFStringRef componentPath = CFStringCreateWithCString(kCFAllocatorDefault,
path, kCFStringEncodingUTF8);
CFURLRef componentURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
componentPath, kCFURLPOSIXPathStyle, false);
FSRef fsref;

if (CFURLGetFSRef(componentURL, &fsref)) {
OSStatus err = noErr;
ATSFontContainerRef fontContainerRef; // we don't deactivate the font
#if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4)
err = ATSFontActivateFromFileReference(&fsref,
kATSFontContextLocal, kATSFontFormatUnspecified, NULL,
kATSOptionFlagsDefault, &fontContainerRef);
#else
FSSpec fsSpec;
FSRef fsRef;
if ((err = FSGetCatalogInfo(
&fsRef, kFSCatInfoNone, NULL, NULL, &fsSpec, NULL)) == noErr) {
err = ATSFontActivateFromFileSpecification(&fsSpec,
kATSFontContextLocal, kATSFontFormatUnspecified, NULL,
kATSOptionFlagsDefault, &fontContainerRef);
}

#endif

if (err == noErr) {
result = Py_True;
}
}
CFRelease(componentURL);
CFRelease(componentPath);
}
return result;
}

static PyMethodDef LoadfontMethods[] = {
{ "loadfont", loadfont, METH_VARARGS, "Locally activates font from file." },
{ NULL, NULL, 0, NULL }
};

PyMODINIT_FUNC initloadfont(void) {
Py_InitModule("loadfont", LoadfontMethods);
}
80 changes: 69 additions & 11 deletions src/MacVim/icons/make_icons.py
@@ -1,11 +1,24 @@
# Creates a document icon from an app icon and an optional text.

# The font is not quite right, use this script to create a document icon
# for 'PDF' and compare the D with the D in Preview's pdf.icns
# Creates all of MacVim document icons.

# http://www.macresearch.org/cocoa-scientists-part-xx-python-scriptersmeet-cocoa
try:
# Make us independent of sysprefs->appearance->antialias fonts smaller than...
# Needs to happen before docerator is imported.
from AppKit import NSUserDefaults
prefs = NSUserDefaults.standardUserDefaults()
prefs.setInteger_forKey_(4, 'AppleAntiAliasingThreshold')

import docerator

# Load Envy Code R from a file and register it under its postscript name
# Thanks to DamienG for this font (redistributed with permission):
# http://damieng.com/blog/2008/05/26/envy-code-r-preview-7-coding-font-released
import loadfont
loadfont.loadfont('Envy Code R Bold.ttf')

from Foundation import NSString
from AppKit import *

dont_create = False
except:
dont_create = True # most likely because we're on tiger
Expand Down Expand Up @@ -43,7 +56,7 @@
'MacVim-c': [u'C', SMALL],
'MacVim-m': [u'M', SMALL],
'MacVim-mm': [u'MM', SMALL],
'MacVim-cpp': [u'C\uff0b\uff0b', SMALL], # fullwidth plusses
'MacVim-cpp': [u'C\uff0b\uff0b,C++,C++', SMALL], # fullwidth plusses
'MacVim-java': [u'JAVA', SMALL],
'MacVim-f': [u'FTRAN', SMALL],
'MacVim-html': [u'HTML', SMALL],
Expand All @@ -69,7 +82,7 @@
'MacVim-dtd': [u'DTD', LINK],
'MacVim-dylan': [u'DYLAN', LINK],
'MacVim-erl': [u'ERLANG,ERL', SMALL],
'MacVim-fscript': [u'FSCPT,FSCR', SMALL],
'MacVim-fscript': [u'FSCPT,FSCR,FS', SMALL],
'MacVim-hs': [u'HS', SMALL],
'MacVim-inc': [u'INC', LINK],
'MacVim-ics': [u'ICS', SMALL],
Expand All @@ -78,7 +91,7 @@
'MacVim-bsh': [u'BSH', LINK],
'MacVim-properties': [u'PROP', LINK],
'MacVim-jsp': [u'JSP', SMALL],
'MacVim-lisp': [u'LISP', SMALL],
'MacVim-lisp': [u'LISP,LISP,LSP', SMALL],
'MacVim-log': [u'LOG', SMALL],
'MacVim-wiki': [u'WIKI', SMALL],
'MacVim-ps': [u'PS', LINK],
Expand All @@ -89,7 +102,7 @@
'MacVim-xsl': [u'XSL', LINK],
'MacVim-vcf': [u'VCARD,VCF', SMALL],
'MacVim-vb': [u'VBASIC,VB', LINK],
'MacVim-yaml': [u'YAML', SMALL],
'MacVim-yaml': [u'YAML,YAML,YML', SMALL],
'MacVim-gtd': [u'GTD', LINK],
}

Expand All @@ -103,6 +116,44 @@ def createLinks(icons, target):
os.symlink(target, icnsName)


if not dont_create:
# define a few classes to render custom 16x16 icons

class NoTextRenderer(docerator.TextRenderer):
def drawTextAtSize(self, text, s):
if s == 16: return # No text at 16x16
docerator.TextRenderer.drawTextAtSize(self, text, s)

class NoIconRenderer(docerator.BackgroundRenderer):
def drawIcon(self, s):
if s == 16: return # no "MacVim" icon on the sheet at 16x16
docerator.BackgroundRenderer.drawIcon(self, s)

class SmallTextRenderer(docerator.TextRenderer):
def _attribsAtSize(self, s):
attribs = docerator.TextRenderer._attribsAtSize(self, s)
if s == 16:
font = NSFont.fontWithName_size_('EnvyCodeR-Bold', 7.0)
assert font
attribs[NSFontAttributeName] = font
attribs[NSForegroundColorAttributeName] = \
NSColor.colorWithDeviceRed_green_blue_alpha_(
0/255.0, 82/255.0, 0/255.0, 1)
return attribs

def drawTextAtSize(self, text, s):
if s != 16:
docerator.TextRenderer.drawTextAtSize(self, text, s)
return
text = NSString.stringWithString_(text.lower()[0:3]) # at most 3 chars
attribs = self.attribsAtSize(s)
if len(text) <= 2:
attribs[NSKernAttributeName] = 0 # we have some space
else:
attribs[NSKernAttributeName] = -1 # we need all the room we can get
text.drawInRect_withAttributes_( ((1, 2), (15, 11)), attribs)


def main():
if dont_create:
print "PyObjC not found, only using a stock icon for document icons."
Expand All @@ -118,15 +169,22 @@ def main():
os.chdir(sys.argv[1])
appIcon = os.path.join(srcdir, APPICON)
makeIcns = os.path.join(srcdir, MAKEICNS)


# create LARGE and SMALL icons first...
for name, t in vimIcons.iteritems():
text, size = t
if size == LINK: continue
print name
docerator.makedocicon(outname='%s.icns' % name, appicon=appIcon, text=text,
sizes=iconsizes[size], makeicns=makeIcns)
if name == GENERIC_ICON_NAME:
# The generic icon has no text; make the appicon a bit larger
docerator.makedocicon(outname='%s.icns' % name, appicon=appIcon,
text=text, sizes=iconsizes[size], makeicns=makeIcns,
textrenderer=NoTextRenderer, rects={16:(0.0, 0.5533, 0.0, 0.5533)})
else:
# For the other icons, leave out appicon and render text in Envy Code R
docerator.makedocicon(outname='%s.icns' % name, appicon=appIcon,
text=text, sizes=iconsizes[size], makeicns=makeIcns,
textrenderer=SmallTextRenderer, backgroundrenderer=NoIconRenderer)

# ...create links later (to make sure the link targets exist)
createLinks([name for (name, t) in vimIcons.items() if t[1] == LINK],
Expand Down

0 comments on commit cca95ba

Please sign in to comment.