1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 from cache_pixbuf import CachePixbuf
24 from config import Config
25 from constant import SHADE_SIZE, COLOR_SEQUENCE
26 from draw import draw_pixbuf, draw_vlinear, draw_hlinear
27 from utils import color_hex_to_cairo, remove_file, touch_file, create_directory
28 import gobject
29 import gtk
30 import os
31 import tarfile
32 import uuid
33
35 '''
36 SkinConfig.
37
38 @undocumented: update_image_size
39 @undocumented: get_skin_file_path
40 @undocumented: is_skin_exist
41 @undocumented: get_default_skin
42 @undocumented: get_skin_dir
43 @undocumented: save_skin_name
44 @undocumented: reload_skin
45 @undocumented: load_skin
46 @undocumented: save_skin
47 @undocumented: change_theme
48 @undocumented: apply_skin
49 @undocumented: add_theme
50 @undocumented: remove_theme
51 @undocumented: wrap_skin_window
52 @undocumented: add_skin_window
53 @undocumented: remove_skin_window
54 @undocumented: reset
55 @undocumented: auto_resize
56 @undocumented: vertical_mirror_background
57 @undocumented: horizontal_mirror_background
58 @undocumented: render_background
59 @undocumented: export_skin
60 '''
61
63 '''
64 Initialize SkinConfig class.
65 '''
66
67 gobject.GObject.__init__(self)
68 self.cache_pixbuf = CachePixbuf()
69
70 self.theme_list = []
71 self.window_list = []
72
74 '''
75 Set application window with given size.
76
77 @param app_window_width: Application window width.
78 @param app_window_height: Application window height.
79 '''
80 self.app_window_width = app_window_width
81 self.app_window_height = app_window_height
82
84 '''
85 Internal function to update image size.
86 '''
87 self.x = x
88 self.y = y
89 self.scale_x = scale_x
90 self.scale_y = scale_y
91
93 '''
94 Internal function to get skin file path.
95 '''
96 skin_file_dir = None
97 for skin_dir in [self.system_skin_dir, self.user_skin_dir]:
98 if os.path.exists(skin_dir):
99 if self.skin_name in os.listdir(os.path.expanduser(skin_dir)):
100 skin_file_dir = skin_dir
101 break
102
103 if skin_file_dir:
104 return os.path.join(skin_file_dir, self.skin_name, filename)
105 else:
106 return None
107
108 - def is_skin_exist(self, skin_name, system_skin_dir, user_skin_dir):
109 '''
110 Internal function to is skin exist in skin directories.
111 '''
112 for skin_dir in [system_skin_dir, user_skin_dir]:
113 if os.path.exists(skin_dir):
114 if skin_name in os.listdir(os.path.expanduser(skin_dir)):
115 return True
116
117 return False
118
120 '''
121 Internal function to get default skin.
122 '''
123 for skin_dir in [system_skin_dir, user_skin_dir]:
124 if os.path.exists(skin_dir):
125 skin_list = os.listdir(os.path.expanduser(skin_dir))
126 if len(skin_list) > 0:
127 return skin_list[0]
128
129 return None
130
132 '''
133 Internal function to get skin dir.
134 '''
135 for skin_dir in [self.system_skin_dir, self.user_skin_dir]:
136 if os.path.exists(skin_dir):
137 if self.skin_name in os.listdir(os.path.expanduser(skin_dir)):
138 return os.path.join(skin_dir, self.skin_name)
139
140 return None
141
142 - def init_skin(self, skin_name, system_skin_dir, user_skin_dir, skin_config_file,
143 app_given_id, app_given_version):
144 '''
145 Init skin.
146
147 @param skin_name: Skin name.
148 @param system_skin_dir: Default skin directory.
149 @param user_skin_dir: User's skin directory, generic use ~/.config/project-name/skin
150 @param skin_config_file: Skin's config filepath, generic use ~/.config/project-name/skin_config.ini
151 @param app_given_id: Project name.
152 @param app_given_version: Project version.
153 '''
154 self.skin_config_file = skin_config_file
155 if os.path.exists(skin_config_file):
156
157 skin_config = Config(skin_config_file)
158 skin_config.load()
159
160
161 init_skin_name = skin_config.get("skin", "skin_name")
162 else:
163
164 touch_file(self.skin_config_file)
165
166 init_skin_name = skin_name
167
168 if self.is_skin_exist(init_skin_name, system_skin_dir, user_skin_dir):
169 self.load_skin(init_skin_name, system_skin_dir, user_skin_dir)
170 else:
171
172 default_skin_name = self.get_default_skin(system_skin_dir, user_skin_dir)
173 assert(default_skin_name != None)
174 self.load_skin(default_skin_name, system_skin_dir, user_skin_dir)
175
176 self.app_given_id = app_given_id
177 self.app_given_version = app_given_version
178
188
190 '''
191 Internal function to reload skin.
192 '''
193 if skin_name:
194 return self.load_skin(skin_name)
195 else:
196 return self.load_skin(self.skin_name)
197
198 - def load_skin(self, skin_name, system_skin_dir=None, user_skin_dir=None):
199 '''
200 Internal function to Load skin.
201
202 @return: Return True if load finish, otherwise return False.
203 '''
204 try:
205
206 self.skin_name = skin_name
207
208 if system_skin_dir:
209 self.system_skin_dir = system_skin_dir
210 create_directory(self.system_skin_dir)
211
212 if user_skin_dir:
213 self.user_skin_dir = user_skin_dir
214 create_directory(self.user_skin_dir)
215
216 self.skin_dir = self.get_skin_dir()
217
218
219 self.config = Config(self.get_skin_file_path("config.ini"))
220 self.config.load()
221
222
223 self.theme_name = self.config.get("theme", "theme_name")
224
225
226 self.app_id = self.config.get("application", "app_id")
227 self.app_version = self.config.getfloat("application", "app_version")
228
229
230 self.image = self.config.get("background", "image")
231 self.x = self.config.getfloat("background", "x")
232 self.y = self.config.getfloat("background", "y")
233 self.scale_x = self.config.getfloat("background", "scale_x")
234 self.scale_y = self.config.getfloat("background", "scale_y")
235 self.dominant_color = self.config.get("background", "dominant_color")
236
237
238 self.deletable = self.config.getboolean("action", "deletable")
239 self.editable = self.config.getboolean("action", "editable")
240 self.vertical_mirror = self.config.getboolean("action", "vertical_mirror")
241 self.horizontal_mirror = self.config.getboolean("action", "horizontal_mirror")
242
243
244 self.background_pixbuf = gtk.gdk.pixbuf_new_from_file(self.get_skin_file_path(self.image))
245
246
247 self.save_skin_name()
248
249 return True
250 except Exception, e:
251 print "load_skin error: %s" % (e)
252 return False
253
255 '''
256 Internal function to save skin.
257 '''
258 self.config.set("theme", "theme_name", self.theme_name)
259
260 self.config.set("background", "x", self.x)
261 self.config.set("background", "y", self.y)
262 self.config.set("background", "scale_x", self.scale_x)
263 self.config.set("background", "scale_y", self.scale_y)
264
265 self.config.set("action", "vertical_mirror", self.vertical_mirror)
266 self.config.set("action", "horizontal_mirror", self.horizontal_mirror)
267
268 self.config.write(given_filepath)
269
271 '''
272 Internal function to change theme.
273 '''
274 self.theme_name = theme_name
275
276 self.apply_skin()
277
279 '''
280 Internal function to apply skin.
281 '''
282
283 for theme in self.theme_list:
284 if theme.theme_name != self.theme_name:
285 theme.change_theme(self.theme_name)
286
287
288 for window in self.window_list:
289 window.queue_draw()
290
292 '''
293 Internal function to add theme.
294 '''
295 if not theme in self.theme_list:
296 self.theme_list.append(theme)
297
299 '''
300 Internal function to remove theme.
301 '''
302 if theme in self.theme_list:
303 self.theme_list.remove(theme)
304
306 '''
307 Internal function to wrap skin window.
308 '''
309 self.add_skin_window(window)
310 window.connect("destroy", lambda w: self.remove_skin_window(w))
311
313 '''
314 Internal function to add skin window.
315 '''
316 if not window in self.window_list:
317 self.window_list.append(window)
318
320 '''
321 Internal function to remove skin window.
322 '''
323 if window in self.window_list:
324 self.window_list.remove(window)
325
327 '''
328 Internal function to reset.
329 '''
330 self.x = 0
331 self.y = 0
332 self.scale_x = 1.0
333 self.scale_y = 1.0
334
335 self.vertical_mirror = False
336 self.horizontal_mirror = False
337
339 '''
340 Internal function to auto resize.
341 '''
342 self.x = 0
343 self.y = 0
344
345 pixbuf = gtk.gdk.pixbuf_new_from_file(self.get_skin_file_path(self.image))
346 if self.app_window_width > self.app_window_height:
347 self.scale_x = self.scale_y = float(self.app_window_height) / pixbuf.get_height()
348 else:
349 self.scale_x = self.scale_y = float(self.app_window_width) / pixbuf.get_width()
350
351 self.vertical_mirror = False
352 self.horizontal_mirror = False
353
355 '''
356 Internal function to vertical mirror background.
357 '''
358 self.vertical_mirror = not self.vertical_mirror
359
360 self.apply_skin()
361
363 '''
364 Internal function to horizontal mirror background.
365 '''
366 self.horizontal_mirror = not self.horizontal_mirror
367
368 self.apply_skin()
369
370 - def render_background(self, cr, widget, x, y,
371 translate_width=0,
372 translate_height=0):
373 '''
374 Internal function to render background.
375 '''
376
377 toplevel_rect = widget.get_toplevel().allocation
378 render_width = toplevel_rect.width + translate_width
379 render_height = toplevel_rect.height + translate_height
380
381
382 background_x = int(self.x * self.scale_x)
383 background_y = int(self.y * self.scale_y)
384 background_width = int(self.background_pixbuf.get_width() * self.scale_x)
385 background_height = int(self.background_pixbuf.get_height() * self.scale_y)
386 self.cache_pixbuf.scale(self.background_pixbuf, background_width, background_height,
387 self.vertical_mirror, self.horizontal_mirror)
388
389 draw_pixbuf(
390 cr,
391 self.cache_pixbuf.get_cache(),
392 x + background_x,
393 y + background_y)
394
395
396 if ((background_width + background_x) < render_width
397 and (background_height + background_y) < render_height):
398 cr.set_source_rgb(*color_hex_to_cairo(self.dominant_color))
399 cr.rectangle(
400 x + background_x + background_width,
401 y + background_y + background_height,
402 render_width - (background_width + background_x),
403 render_height - (background_height + background_y))
404 cr.fill()
405
406 if (background_width + background_x) < render_width:
407 draw_hlinear(
408 cr,
409 x + (background_width + background_x) - SHADE_SIZE,
410 y,
411 SHADE_SIZE,
412 (background_height + background_y),
413 [(0, (self.dominant_color, 0)),
414 (1, (self.dominant_color, 1))])
415
416 cr.set_source_rgb(*color_hex_to_cairo(self.dominant_color))
417 cr.rectangle(
418 x + (background_width + background_x),
419 y,
420 render_width - (background_width + background_x),
421 (background_height + background_y))
422 cr.fill()
423
424 if (background_height + background_y) < render_height:
425 draw_vlinear(
426 cr,
427 x,
428 y + (background_height + background_y) - SHADE_SIZE,
429 (background_width + background_x),
430 SHADE_SIZE,
431 [(0, (self.dominant_color, 0)),
432 (1, (self.dominant_color, 1))])
433
434 cr.set_source_rgb(*color_hex_to_cairo(self.dominant_color))
435 cr.rectangle(
436 x,
437 y + (background_height + background_y),
438 (background_width + background_x),
439 render_height - (background_height + background_y))
440 cr.fill()
441
443 '''
444 Internal function to export skin.
445 '''
446
447 config_filepath = os.path.join("/tmp/%s", str(uuid.uuid4()))
448 touch_file(config_filepath)
449 self.save_skin(config_filepath)
450
451
452 with tarfile.open("%s.tar.gz" % filepath, "w:gz") as tar:
453
454 tar.add(config_filepath, "config.ini", False)
455
456
457 tar.add(self.get_skin_file_path(self.image), self.image, False)
458
459
460 if not self.theme_name in COLOR_SEQUENCE:
461 tar.add(os.path.join(self.ui_theme_dir, self.theme_name), os.path.join("ui_theme", self.theme_name))
462 tar.add(os.path.join(self.app_theme_dir, self.theme_name), os.path.join("app_theme", self.theme_name))
463
464
465 remove_file(config_filepath)
466
468 '''
469 Load theme from given directories.
470
471 @param ui_theme: dtk.ui.theme.ui_theme.
472 @param app_theme: Theme instance, build it like below:
473
474 >>> app_theme = Theme(
475 >>> os.path.join(get_parent_dir(__file__), "app_theme"),
476 >>> os.path.expanduser("~/.config/project-name/theme")
477 >>> )
478 '''
479
480 ui_theme.load_theme()
481 app_theme.load_theme()
482
483
484 self.ui_theme_dir = ui_theme.user_theme_dir
485 self.app_theme_dir = app_theme.user_theme_dir
486
487 gobject.type_register(SkinConfig)
488
489 skin_config = SkinConfig()
490