/[drupal]/contributions/modules/icontheme/icontheme.module
ViewVC logotype

Contents of /contributions/modules/icontheme/icontheme.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1.1.1 - (show annotations) (download) (as text) (vendor branch)
Fri Mar 30 16:06:07 2007 UTC (2 years, 7 months ago) by ray007
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5
Changes since 1.1: +0 -0 lines
File MIME type: text/x-php
Imported using TkCVS
1 <?php
2 // $Id$
3
4 /**
5 * @file
6 * TODO: Enter file description here.
7 */
8
9 /**
10 * Implementation of hook_help().
11 */
12 function icontheme_help($section) {
13 switch ($section) {
14 case 'admin/help#icontheme':
15 return t('Provide an api for other modules to show named icons, and provide a gui to install additional icon themes.
16 More information about icon-themes see http://tango.freedesktop.org/Tango_Icon_Library
17 Of special interest may be http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
18 and http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html');
19 case 'admin/modules#description':
20 return t('api module to manage named icons');
21 // OPTIONAL: Add additional cases for other paths that should display help text.
22 }
23 }
24
25 /**
26 * Implementation of hook_menu().
27 */
28 function icontheme_menu($may_cache) {
29 $items = array();
30
31 if ($may_cache) {
32 $items[] = array(
33 'path' => 'admin/settings/icontheme/add',
34 'title' => t('Add a new icon-theme to the site'),
35 );
36 // TODO: add / list / rebuild cache / ...
37 }
38
39 return $items;
40 }
41
42 /** =========================================================================
43 * ICONTHEME public API
44 *
45 * this is just a first suggestion for now - let's dicuss what we want/need!
46 */
47
48 /**
49 * get the path for a named icon
50 */
51 function icontheme_get_icon($iconname, $size = 0, $theme = NULL) {
52
53 }
54
55
56
57 /**
58 * get the currently active theme
59 * TODO: extend so drupal-themes can have default icon themes
60 */
61 function icontheme_get_default_theme() {
62 // get from variables or db
63 return variable_get('icontheme_theme_default', 'default');
64 }
65
66 function icontheme_set_default_theme($theme_name) {
67 variable_set('icontheme_theme_default', $theme_name);
68 }
69
70 function icontheme_get_theme_by_name($name) {
71 return new stdClass();
72 }
73
74 /**
75 * named sizes - instead of requiring the called to know size-numbers,
76 * let them use aliases
77 */
78 function _icontheme_get_named_size($name = NULL) {
79 static $def_sizes = array(
80 'x-small' => 8,
81 'small' => 12,
82 'medium' => 16,
83 'large' => 22,
84 'x-large' => 22,
85 'xx-large' => 22,
86 );
87 $sizes = variable_get('icontheme_size_names', $def_sizes);
88 if(!$name) return $sizes;
89 return (isset($sizes[$name]) ? $sizes[$name] : -1);
90 }
91
92 /**
93 * parse an index.theme file and return a theme-object from it
94 *
95 * @param $themefile - path to the file
96 */
97 function icontheme_parse_index_theme($themefile) {
98 $theme = new stdClass();
99 $theme->themedir = dirname($themefile);
100
101 $lines = file($themefile);
102 $lines['nrof'] = count($lines);
103
104 $i = 0;
105 do {
106 $line = trim($lines[$i]);
107
108 if (!$line || ($line[0] == '#')) { // ignore empty lines and comments
109 ++$i;
110 continue;
111 }
112
113 // initial section [Icon Theme]
114 if (strncmp('[Icon Theme]', $line, 12)) {
115 $i = _icontheme_indexfile_baseprops($theme, $lines, ++$i);
116 continue;
117 }
118 // directory section
119 else if (preg_match('!\[((\w+)/(\w+))\]!', $line, $matches)) {
120 $dirname = $matches[1];
121 $dir = new stdClass();
122 $dir->size_str = $matches[2];
123 $dir->context = $matches[3];
124 $theme->dirs[$dirname] = $dir;
125 $i = _icontheme_indexfile_dirprops($theme->dirs[$dirname], $lines, ++$i);
126 continue;
127 }
128 else { // ERROR
129 return NULL;
130 }
131 } while (($i < $lines['nrof']) && ($i > 0));
132 return $theme;
133 }
134
135 function _icontheme_indexfile_baseprops(&$theme, &$lines, $i) {
136 while($i < $lines['nrof']) {
137 $line = trim($lines[$i]);
138 if ($line[0] == '[') return $i; // begin of dir-section
139 if (!$line || ($line[0] == '#')) continue; // ignore empty lines and comments
140
141 if (preg_match('!^(\w+)(\[\w\w\])?=(.*)$!', $line, $matches)) {
142 $key = $matches[1];
143 $value = trim($matches[3]);
144 if(($key == 'Name') || ($key == 'Comment')) {
145 $locale = substr($matches[2], 1, 2);
146 $lkey = strtolower($key);
147 if ($locale) {
148 $theme->$lkey[$locale ? $locale : 'en'] = $value;
149 }
150 else {
151 $lkey .= '_def';
152 $theme->$lkey = $value;
153 }
154 }
155 else if ($key == 'Inherits') {
156 $theme->inherits = explode(',', $value);
157 }
158 else if ($key == 'Directories') {
159 $dirs = explode(',', $value);
160 foreach ($dirs as $dirname) {
161 $theme->dirs[$dirname] = 1;
162 }
163 }
164 else if ($key == 'Hidden') {
165 $theme->hidden = preg_match('/^yes|true|1$/i', $value);
166 }
167 else if ($key == 'Example') {
168 $theme->example = $value;
169 }
170 else { // ERROR
171 return -1;
172 }
173 }
174 ++$i;
175 }
176 return $i;
177 }
178
179 function _icontheme_indexfile_dirprops(&$dir, &$lines, $i) {
180 static $dirkeys = array('Size', 'Context', 'Type', 'MaxSize', 'MinSize', 'Threshold');
181 $dir->type = 'threshold';
182 $dir->threshold = 2;
183 while($i < $lines['nrof']) {
184 $line = trim($lines[$i]);
185 if ($line[0] == '[') return $i; // begin of dir-section
186 if (!$line || ($line[0] == '#')) continue; // ignore empty lines and comments
187
188 if (preg_match('!^(\w+)=(.*)$!', $line, $matches)) {
189 $key = $matches[1];
190 $value = trim($matches[2]);
191 if (in_array($key, $dirkeys)) {
192 $lkey = strtolower($key);
193 $dir->$lkey = $value;
194 }
195 else { // ERROR
196 return -1;
197 }
198 }
199 ++$i;
200 }
201 // TODO: if (!$dir->size) ... error
202 return $i;
203 }
204
205 /**
206 * ICON Lookup - modeled after pseudocode at
207 * http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
208 *
209 * The icon lookup mechanism has two global settings, the list of base
210 * directories and the internal name of the current theme. Given these we need
211 * to specify how to look up an icon file from the icon name and the nominal size.
212 *
213 * The lookup is done first in the current theme, and then recursively in each
214 * of the current theme's parents, and finally in the default theme called
215 * "hicolor" (implementations may add more default themes before "hicolor",
216 * but "hicolor" must be last). As soon as there is an icon of any size that
217 * matches in a theme, the search is stopped. Even if there may be an icon with
218 * a size closer to the correct one in an inherited theme, we don't want to use
219 * it. Doing so may generate an inconsistant change in an icon when you change
220 * icon sizes (e.g. zoom in).
221 *
222 * The lookup inside a theme is done in three phases. First all the directories
223 * are scanned for an exact match, e.g. one where the allowed size of the icon
224 * files match what was looked up. Then all the directories are scanned for any
225 * icon that matches the name. If that fails we finally fall back on unthemed
226 * icons. If we fail to find any icon at all it is up to the application to
227 * pick a good fallback, as the correct choice depends on the context.
228 */
229
230 function icontheme_find_icon($icon, $size) {
231
232 $filename = icontheme_find_icon_helper($icon, $size, icontheme_get_default_theme());
233 if ($filename) return $filename;
234
235 return icontheme_lookup_fallback_icon ($icon);
236 }
237
238 function icontheme_find_icon_helper($icon, $size, $theme) {
239
240 $filename = icontheme_lookup_icon ($icon, $size, $theme);
241 if ($filename) return $filename;
242
243 if ($theme->parents) {
244 $parents = $theme->parents;
245 }
246 else if ($theme->name != 'hicolor') { // TODO: ??? 'hicolor' -> fallback theme
247 $parents[] = icontheme_get_theme_by_name('hicolor');
248 }
249
250 if (!$parents) return NULL;
251
252 foreach ($parents as $parent) {
253 $filename = icontheme_find_icon_helper($icon, $size, $parent);
254 if ($filename) return $filename;
255 }
256 return NULL;
257 }
258
259 /** -------------------------------------------------------------------------
260 * lookup helper functions
261 */
262
263 /**
264 * LookupIcon
265 */
266 function icontheme_lookup_icon($iconname, $size, $theme_name) {
267 $icon_exts = icontheme_get_icon_extensions();
268 $theme = icontheme_get_theme_by_name($theme_name);
269 $basedirs = icontheme_get_theme_basedirs($theme_name);
270
271 //for each subdir in $(theme subdir list) {
272 foreach ($theme->dirs as $subdirname => $subdir) {
273 //for each directory in $(basename list) {
274 foreach ($basedirs as $directory) {
275 //for extension in ("png", "svg", "xpm") {
276 foreach ($icon_exts as $extension) {
277 if (icontheme_directory_matches_size($subdir, $size)) {
278 $filename = "$directory/$theme->name/$subdir/$iconname.$extension";
279 if (file_exists($filename)) return $filename;
280 }
281 }
282 }
283 }
284
285 $minimal_size = 0x7fffffff; // constant PHP_INT_MAX ... only php 4.4+
286
287 $closest_filename = NULL;
288 foreach ($theme->dirs as $subdir) {
289 foreach ($basedirs as $directory) {
290 foreach ($icon_exts as $extension) {
291 $filename = "$directory/$theme->name/$subdir/$iconname.$extension";
292 if (file_exists($filename) && (icontheme_directory_size_distance($subdir, $size) < $minimal_size)) {
293 $closest_filename = $filename;
294 $minimal_size = icontheme_directory_size_distance($subdir, $size);
295 }
296 }
297 }
298 }
299 return $closest_filename;
300 }
301
302 function icontheme_lookup_fallback_icon ($iconname) {
303
304 $icon_exts = icontheme_get_icon_extensions();
305 $basedirs = icontheme_get_theme_basedirs(NULL); // directories for fallback icons
306
307 foreach ($basedirs as $directory) {
308 foreach ($icon_exts as $extension) {
309 $filename = "$directory/$iconname.$extension";
310 if (file_exists($filename)) return $filename;
311 }
312 }
313
314 return NULL;
315 }
316
317 /**
318 * @param $subdir - reference to directory object in theme
319 * @param $iconsize - size (number or TODO: named)
320 */
321 function icontheme_directory_matches_size(&$subdir, $iconsize) {
322 //read Type and size data from subdir
323 if ($subdir->type == 'Fixed') {
324 return ($subdir->size == $iconsize);
325 }
326 if ($subdir->type == 'Scaled') {
327 return (($subdir->minsize <= $iconsize) && ($subdir->maxdir >= $iconsize));
328 }
329 if ($subdir->type == 'Threshold') {
330 return (($subdir->size - $subdir->threshold) <= $iconsize) &&
331 (($subdir->size + $subdir->threshold) >= $iconsize);
332 }
333 return false; // unknown type -> ERROR ?
334 }
335
336 /**
337 * @param $subdir - reference to subdir object in theme
338 * @param $iconsize - size (number or TODO: named)
339 */
340 function icontheme_directory_size_distance(&$subdir, $iconsize) {
341 //read Type and size data from subdir
342 if ($subdir->type == 'Fixed') {
343 return abs($subdir->size - $iconsize);
344 }
345 if ($subdir->type == 'Scaled') {
346 if ($iconsize < $subdir->minsize) {
347 return $subdir->minsize - $iconsize;
348 }
349 if ($iconsize > $subdir->maxsize) {
350 return $iconsize - $subdir->maxsize;
351 }
352 return 0;
353 }
354 if ($subdir->type == 'Scaled') {
355 if ($iconsize < $subdir->minsize) {
356 return $subdir->minsize - $iconsize;
357 }
358 if ($iconsize > $subdir->maxsize) {
359 return $iconsize - $subdir->maxsize;
360 }
361 return 0;
362 }
363 if ($subdir->type == 'Threshold') {
364 if ($iconsize < ($subdir->size - $subdir->threshold)) {
365 return $subdir->minsize - $iconsize;
366 }
367 if ($iconsize > ($subdir->size + $subdir->threshold)) {
368 return $iconsize - $subdir->maxsize;
369 }
370 return 0;
371 }
372 return 0x7fffffff; // unknown type -> ERROR ?
373 }
374
375 /**
376 * In some cases you don't always want to fall back to an icon in an inherited
377 * theme. For instance, sometimes you look for a set of icons, prefering any of
378 * them before using an icon from an inherited theme. To support such operations
379 * implementations can contain a function that finds the first of a list of icon
380 * names in the inheritance hierarchy. I.E. It would look something like this:
381 */
382
383 function icontheme_find_best_icon($icon_list, $size) {
384 $cur_theme = icontheme_get_default_theme();
385
386 $filename = icontheme_find_best_icon_helper($icon_list, $size, $cur_theme);
387 if ($filename) return $filename;
388
389 //for $icon in $icon_list {
390 foreach ($icon_list as $icon) {
391 $filename = icontheme_lookup_fallback_icon($icon);
392 if ($filename) return $filename;
393 }
394 return NULL;
395 }
396
397 function icontheme_find_best_icon_helper(&$icon_list, $size, $theme) {
398 //for $icon in $icon_list {
399 foreach ($icon_list as $icon) {
400 $filename = icontheme_lookup_icon($icon, $size, $theme);
401 if ($filename) return $filename;
402 }
403
404 if ($theme->parents) {
405 $parents = $theme->parents;
406 }
407 else if ($theme->name != 'hicolor') { // TODO: fix check and set of fallback theme
408 $parents = array('hicolor');
409 }
410
411 //for parent in parents {
412 foreach ($parents as $parent) {
413 $filename = icontheme_find_best_icon_helper($icon_list, $size, $parent);
414 if ($filename) return $filename;
415 }
416 return NULL;
417 }
418
419 /** -------------------------------------------------------------------------
420 * some helper function so needed by the pseudo-code to php conversion
421 * --------------------------------------------------------------------------
422 */
423
424 /**
425 * the extensions specified in the spec are: "png", "svg", "xpm"
426 * for web-use we change that to: "png", "gif", "jpg"
427 */
428 function icontheme_get_icon_extensions() {
429 static $icon_exts = array('gif', 'png', 'jpg');
430 return $icon_exts;
431 }
432
433 function _icontheme_parse_subdir($subdir) {
434 $parts = explode('/', $subdir);
435 if (count($parts) != 2) return NULL;
436 }
437
438 /**
439 * @param $theme_name - the name of the theme to get the basedirs for
440 * NULL to get directories for fallback icons
441 */
442 function icontheme_get_theme_basedirs($theme_name) {
443 // TODO: if(!$theme_name) ... get dirs for fallback icons
444 $theme = icontheme_get_theme_by_name($theme_name);
445 return array(dirname($theme->themedir));
446 }

  ViewVC Help
Powered by ViewVC 1.1.2