summaryrefslogtreecommitdiff
path: root/icons/mkicons
blob: 8ecc8e2ed72e910401560803a3a7a47feb80a033 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
#!/usr/bin/python
#
# This program copyright (C) 2011 Nicolas Schodet
#
# All 'awesome' original icons generated by this program were created by
# Adrian C. (anrxc).  They are licensed under the same terms as the awesome
# distribution itself - GNU General Public License version 2.  They can be
# generated with the options:
#
# --fg trans --bg '#dcdccc' --size 12x12 --margin_top 1 --margin_right 2 \
# --margin_left -1 --too_small 3
#
# Icons generated with other parameters are inspired by those icons.
#
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Contact :
#        Web: http://ni.fr.eu.org/
#      Email: <nico at ni.fr.eu.org>
#
"""Generate a set of icons to be used with the Awesome Window Manager."""
import copy
import optparse
import ConfigParser
import Image, ImageDraw
import os, os.path
from fnmatch import fnmatch

class Params(object):
    """Parameters for icons generation, can be loaded with config file or
    command line arguments."""
    def __init__ (self, size, fg, bg,
            margin_top = 0, margin_bottom = 0, margin_left = 0, margin_right = 0,
            too_small = 0):
        """Initialize with provided default values."""
        self.size = size
        self.fg = fg
        self.bg = bg
        self.margin_top = margin_top
        self.margin_bottom = margin_bottom
        self.margin_left = margin_left
        self.margin_right = margin_right
        self.too_small = too_small

    @property
    def coords (self):
        """Get coordinates of the corner points."""
        return (self.margin_left, self.margin_top,
                self.size[0] - self.margin_right - 1,
                self.size[1] - self.margin_bottom - 1)

    def update (self, d):
        """Update from dictionary."""
        if 'size' in d and d['size'] is not None:
            w, h = d['size'].split ('x')
            self.size = (int (w) if w else None, int (h) if h else None)
        for n in ('fg', 'bg'):
            if n in d and d[n] is not None:
                color = d[n]
                if color == 'trans':
                    color = (0, 0, 0, 0)
                setattr (self, n, color)
        for n in ('margin_top', 'margin_bottom', 'margin_left',
                'margin_right', 'too_small'):
            if n in d and d[n] is not None:
                setattr (self, n, int (d[n]))

    def ratio (self, ratio):
        """Return a Params object, updating size for a given ratio."""
        if self.size[0] is None:
            p = copy.copy(self)
            p.size = ((p.size[1] * ratio[0] + ratio[1] - 1) / ratio[1],
                    p.size[1])
            return p
        elif self.size[1] is None:
            p = copy.copy(self)
            p.size = (p.size[0],
                    (p.size[0] * ratio[1] + ratio[0] - 1) / ratio[0])
            return p
        else:
            return self

def part (a, b, i, n, rounding = 'nearest'):
    """Return the ith separator position when partitioning the space between
    a and b. Rounding methods:
     - nearest: pixel nearest the real value,
     - down: pixel to the left/above the real value,
     - up: pixel to the right/below the real value,
     - center: pixel toward center,
     - edge: pixel toward edge
    """
    if rounding == 'nearest':
        offset = n / 2
    elif rounding == 'down':
        offset = 0
    elif rounding == 'up':
        offset = n - 1
    elif rounding == 'center':
        if i <= n / 2:
            offset = n - 1
        else:
            offset = 0
    elif rounding == 'edge':
        if i <= n / 2:
            offset = 0
        else:
            offset = n - 1
    return a + (i * (b - a) + offset) / n

def draw_grid (draw, (x1, y1, x2, y2), nx, ny, rounding, p):
    """Draw a grid with nx column and ny lines."""
    for xi in xrange (0, nx + 1):
        x = part (x1, x2, xi, nx, rounding)
        draw.line ((x, y1, x, y2), fill = p.fg)
    for yi in xrange (0, ny + 1):
        y = part (y1, y2, yi, ny, rounding)
        draw.line ((x1, y, x2, y), fill = p.fg)

def icon_layouts_max (icon, draw, p):
    draw.rectangle (p.coords, outline = p.fg, fill = p.bg)
    x1, y1, x2, y2 = p.coords
    draw.line ((x1, y1, x2, y2), fill = p.fg)
    draw.line ((x1, y2, x2, y1), fill = p.fg)

def icon_layouts_dwindle (icon, draw, p):
    x1, y1, x2, y2 = p.coords
    draw.rectangle ((x1, y1, x2, y2), outline = p.fg, fill = p.bg)
    x1 = (x1 + x2) / 2
    draw.rectangle ((x1, y1, x2, y2), outline = p.fg, fill = p.bg)
    y1 = (y1 + y2) / 2
    if (y2 - y1) % 2:
        y1 += 1
    draw.rectangle ((x1, y1, x2, y2), outline = p.fg, fill = p.bg)
    x1 = (x1 + x2) / 2
    draw.rectangle ((x1, y1, x2, y2), outline = p.fg, fill = p.bg)
    y1 = (y1 + y2) / 2
    draw.rectangle ((x1, y1, x2, y2), outline = p.fg, fill = p.bg)

def icon_layouts_spiral (icon, draw, p):
    x1, y1, x2, y2 = p.coords
    draw.rectangle ((x1, y1, x2, y2), outline = p.fg, fill = p.bg)
    x1 = (x1 + x2) / 2
    draw.rectangle ((x1, y1, x2, y2), outline = p.fg, fill = p.bg)
    y1 = (y1 + y2) / 2
    if (y2 - y1) % 2:
        y1 += 1
    draw.rectangle ((x1, y1, x2, y2), outline = p.fg, fill = p.bg)
    x2 = (x1 + x2 + 1) / 2
    draw.rectangle ((x1, y1, x2, y2), outline = p.fg, fill = p.bg)
    y2 = (y1 + y2) / 2
    draw.rectangle ((x1, y1, x2, y2), outline = p.fg, fill = p.bg)

def icon_layouts_fairh (icon, draw, p):
    draw.rectangle (p.coords, outline = p.fg, fill = p.bg)
    x1, y1, x2, y2 = p.coords
    y3 = part (y1, y2, 2, 3, 'nearest')
    ny = 2 if (y3 - y1) / 2 - 1 > p.too_small else 1
    draw_grid (draw, (x1, y1, x2, y3), 3, ny, 'nearest', p)
    draw_grid (draw, (x1, y3, x2, y2), 2, 1, 'nearest', p)

def icon_layouts_fairv (icon, draw, p):
    draw.rectangle (p.coords, outline = p.fg, fill = p.bg)
    x1, y1, x2, y2 = p.coords
    x3 = part (x1, x2, 2, 3, 'nearest')
    nx = 2 if (x3 - x1) / 2 - 1 > p.too_small else 1
    draw_grid (draw, (x1, y1, x3, y2), nx, 3, 'nearest', p)
    draw_grid (draw, (x3, y1, x2, y2), 1, 2, 'nearest', p)

def icon_layouts_floating (icon, draw, p):
    x1, y1, x2, y2 = p.coords
    xl = part (x1, x2, 2, 10, 'down')
    yl = part (y1, y2, 8, 10, 'up')
    xs = part (x1, x2, 1, 2, 'up')
    ys = part (y1, y2, 1, 2, 'down')
    draw.rectangle ((xl, y1, x2, yl), outline = p.fg, fill = p.bg)
    draw.rectangle ((x1, ys, xs, y2), outline = p.fg, fill = p.bg)

def icon_layouts_fullscreen (icon, draw, p):
    draw.rectangle (p.coords, outline = p.fg, fill = p.bg)
    x1, y1, x2, y2 = p.coords
    xl = part (x1, x2, 3, 10, 'down')
    xr = part (x1, x2, 7, 10, 'up')
    yt = part (y1, y2, 2, 10, 'down')
    ym = part (y1, y2, 5, 10, 'down')
    yb = part (y1, y2, 8, 10, 'up')
    draw.line ((xl, yb, xl, yt, xr, yt), fill = p.fg)
    draw.line ((xl, ym, xr, ym), fill = p.fg)

def icon_layouts_magnifier (icon, draw, p):
    draw.rectangle (p.coords, outline = p.fg, fill = p.bg)
    x1, y1, x2, y2 = p.coords
    xl = part (x1, x2, 2, 10, 'edge')
    xr = part (x1, x2, 8, 10, 'edge')
    yt = part (y1, y2, 3, 10, 'edge')
    yb = part (y1, y2, 7, 10, 'edge')
    ny = 2 if xl - x1 > p.too_small else 1
    nx = 2 if yt - y1 > p.too_small else 1
    draw_grid (draw, p.coords, nx, ny, 'nearest', p)
    draw.rectangle ((xl, yt, xr, yb), outline = p.fg, fill = p.bg)

def icon_layouts_tilebottom (icon, draw, p):
    draw.rectangle (p.coords, outline = p.fg, fill = p.bg)
    x1, y1, x2, y2 = p.coords
    ym = part (y1, y2, 1, 2, 'up')
    draw_grid (draw, (x1, ym, x2, y2), 3, 1, 'nearest', p)

def icon_layouts_tileleft (icon, draw, p):
    draw.rectangle (p.coords, outline = p.fg, fill = p.bg)
    x1, y1, x2, y2 = p.coords
    xm = part (x1, x2, 1, 2, 'down')
    draw_grid (draw, (x1, y1, xm, y2), 1, 3, 'nearest', p)

def icon_layouts_tile (icon, draw, p):
    draw.rectangle (p.coords, outline = p.fg, fill = p.bg)
    x1, y1, x2, y2 = p.coords
    xm = part (x1, x2, 1, 2, 'up')
    draw_grid (draw, (xm, y1, x2, y2), 1, 3, 'nearest', p)

def icon_layouts_tiletop (icon, draw, p):
    draw.rectangle (p.coords, outline = p.fg, fill = p.bg)
    x1, y1, x2, y2 = p.coords
    ym = part (y1, y2, 1, 2, 'down')
    draw_grid (draw, (x1, y1, x2, ym), 3, 1, 'nearest', p)

def icon_taglist_sel (icon, draw, p):
    x1, y1, x2, y2 = p.coords
    y2 = y1 + x2 - x1
    draw.rectangle ((x1, y1, x2, y2), outline = p.fg, fill = p.bg)
icon_taglist_sel.ratio = (1, 4)

def icon_taglist_unsel (icon, draw, p):
    x1, y1, x2, y2 = p.coords
    y2 = y1 + x2 - x1
    draw.line ((x1, y2, x1, y1, x2, y1), fill = p.fg)
icon_taglist_unsel.ratio = (1, 4)

def icon_awesome (icon, draw, p):
    draw.rectangle (p.coords, outline = p.bg, fill = p.bg)
    x0, y0, x3, y3 = p.coords
    x1 = part (x0 - 1, x3 + 1, 1, 3, 'center')
    x2 = part (x0 - 1, x3 + 1, 2, 3, 'center')
    y1 = part (y0 - 1, y3 + 1, 1, 3, 'center')
    y2 = part (y0 - 1, y3 + 1, 2, 3, 'center')
    draw.line ((x0, y1, x2, y1), fill = p.fg)
    draw.line ((x1, y2, x2, y2, x2, y3), fill = p.fg)

icons = dict((f[5:].replace ('_', '/'), globals ()[f])
    for f in dir () if f.startswith ('icon_'))
for name, func in icons.iteritems ():
    if not hasattr (func, 'ratio'):
        func.ratio = (1, 1)

parser = optparse.OptionParser (description = __doc__)
parser.add_option ('-c', '--config', metavar = 'FILE', action = 'append',
        help = "generate for all configurations read from config FILE, if"
        " given, other options will override values from config file")
parser.add_option ('-O', '--output-dir', metavar = 'DIR',
        help = "generate icons below given directory")
parser.add_option ('-f', '--fg', metavar = 'COLOR',
        help = "use COLOR as foreground color")
parser.add_option ('-b', '--bg', metavar = 'COLOR',
        help = "use COLOR as background color")
parser.add_option ('-i', '--include', metavar = 'PATTERN', action = 'append',
        help = 'only include icons matching given shell PATTERN')
parser.add_option ('-s', '--size', metavar = 'WIDTHxHEIGHT',
        help = "use specified size for icons (one length can be missing)")
parser.add_option ('--margin-top', metavar = 'PIXELS', type = 'int',
        help = "keep a margin, define y1")
parser.add_option ('--margin-bottom', metavar = 'PIXELS', type = 'int',
        help = "keep a margin, define y2")
parser.add_option ('--margin-left', metavar = 'PIXELS', type = 'int',
        help = "keep a margin, define x1")
parser.add_option ('--margin-right', metavar = 'PIXELS', type = 'int',
        help = "keep a margin, define x2")
parser.add_option ('-S', '--too-small', metavar = 'PIXELS', type = 'int',
        help = "do not draw some details smaller than a number of PIXELS")
parser.add_option ('--list', action = 'store_true',
        help = "instead of generating icons, print a list of available icons")
parser.add_option ('-q', '--quiet', action = 'store_true',
        help = "suppress verbose messages")
(options, args) = parser.parse_args ()
if args:
    parser.error ('no argument expected')
if options.list:
    print "\n".join (icons.keys())
else:
    configs = options.config or [ None ]
    for config in configs:
        # Get sections from configuration file, or use dummy section.
        if config is not None:
            cp = ConfigParser.SafeConfigParser ()
            cp.readfp (open (config))
            sections = cp.sections ()
        else:
            sections = [ None ]
        # Output icons for every sections.
        for section in sections:
            p = Params ((None, 12), 'white', 'black')
            output_dir = '.'
            include = [ '*' ]
            # Merge config and command line.
            if section is not None:
                p.update (dict (cp.items (section)))
                if cp.has_option (section, 'output_dir'):
                    output_dir = cp.get (section, 'output_dir')
                if cp.has_option (section, 'include'):
                    include = cp.get (section, 'include').split ()
            p.update (options.__dict__)
            if options.output_dir is not None:
                output_dir = options.output_dir
            if options.include is not None:
                include = options.include
            # Generate matching icons.
            for name, func in icons.iteritems():
                for pattern in include:
                    if fnmatch (name, pattern):
                        lp = p.ratio (func.ratio)
                        icon = Image.new ('RGBA', lp.size, (0, 0, 0, 0))
                        draw = ImageDraw.Draw (icon)
                        if not options.quiet:
                            print "Generating %s..." % name
                        func (icon, draw, lp)
                        del draw
                        filename = os.path.join (output_dir, name + '.png')
                        try:
                            os.makedirs (os.path.dirname (filename))
                        except OSError:
                            pass
                        icon.save (filename)
                        break