Package dtk :: Package ui :: Module skin_config

Source Code for Module dtk.ui.skin_config

  1  #! /usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3   
  4  # Copyright (C) 2011 ~ 2012 Deepin, Inc. 
  5  #               2011 ~ 2012 Wang Yong 
  6  #  
  7  # Author:     Wang Yong <lazycat.manatee@gmail.com> 
  8  # Maintainer: Wang Yong <lazycat.manatee@gmail.com> 
  9  #  
 10  # This program is free software: you can redistribute it and/or modify 
 11  # it under the terms of the GNU General Public License as published by 
 12  # the Free Software Foundation, either version 3 of the License, or 
 13  # any later version. 
 14  #  
 15  # This program is distributed in the hope that it will be useful, 
 16  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 17  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 18  # GNU General Public License for more details. 
 19  #  
 20  # You should have received a copy of the GNU General Public License 
 21  # along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 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   
34 -class SkinConfig(gobject.GObject):
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
62 - def __init__(self):
63 ''' 64 Initialize SkinConfig class. 65 ''' 66 # Init. 67 gobject.GObject.__init__(self) 68 self.cache_pixbuf = CachePixbuf() 69 70 self.theme_list = [] 71 self.window_list = []
72
73 - def set_application_window_size(self, app_window_width, app_window_height):
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
83 - def update_image_size(self, x, y, scale_x, scale_y):
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
92 - def get_skin_file_path(self, filename):
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
119 - def get_default_skin(self, system_skin_dir, user_skin_dir):
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
131 - def get_skin_dir(self):
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 # Read skin name from config file. 157 skin_config = Config(skin_config_file) 158 skin_config.load() 159 160 # Load skin. 161 init_skin_name = skin_config.get("skin", "skin_name") 162 else: 163 # Create skin config if it not exists. 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 # Try load default skin if user's select skin not exists. 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
179 - def save_skin_name(self):
180 ''' 181 Internal function to save skin name. 182 ''' 183 skin_config = Config(self.skin_config_file) 184 skin_config.load() 185 if skin_config.get("skin", "skin_name") != self.skin_name: 186 skin_config.set("skin", "skin_name", self.skin_name) 187 skin_config.write(self.skin_config_file)
188
189 - def reload_skin(self, skin_name=None):
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 # Save skin dir. 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 # Load config file. 219 self.config = Config(self.get_skin_file_path("config.ini")) 220 self.config.load() 221 222 # Get theme config. 223 self.theme_name = self.config.get("theme", "theme_name") 224 225 # Get application config. 226 self.app_id = self.config.get("application", "app_id") 227 self.app_version = self.config.getfloat("application", "app_version") 228 229 # Get background config. 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 # Get action config. 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 # Generate background pixbuf. 244 self.background_pixbuf = gtk.gdk.pixbuf_new_from_file(self.get_skin_file_path(self.image)) 245 246 # Save skin name. 247 self.save_skin_name() 248 249 return True 250 except Exception, e: 251 print "load_skin error: %s" % (e) 252 return False
253
254 - def save_skin(self, given_filepath=None):
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
270 - def change_theme(self, theme_name):
271 ''' 272 Internal function to change theme. 273 ''' 274 self.theme_name = theme_name 275 276 self.apply_skin()
277
278 - def apply_skin(self):
279 ''' 280 Internal function to apply skin. 281 ''' 282 # Change theme. 283 for theme in self.theme_list: 284 if theme.theme_name != self.theme_name: 285 theme.change_theme(self.theme_name) 286 287 # Redraw application. 288 for window in self.window_list: 289 window.queue_draw()
290
291 - def add_theme(self, theme):
292 ''' 293 Internal function to add theme. 294 ''' 295 if not theme in self.theme_list: 296 self.theme_list.append(theme)
297
298 - def remove_theme(self, theme):
299 ''' 300 Internal function to remove theme. 301 ''' 302 if theme in self.theme_list: 303 self.theme_list.remove(theme)
304
305 - def wrap_skin_window(self, window):
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
312 - def add_skin_window(self, window):
313 ''' 314 Internal function to add skin window. 315 ''' 316 if not window in self.window_list: 317 self.window_list.append(window)
318
319 - def remove_skin_window(self, window):
320 ''' 321 Internal function to remove skin window. 322 ''' 323 if window in self.window_list: 324 self.window_list.remove(window)
325
326 - def reset(self):
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
338 - def auto_resize(self):
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 # Init. 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 # Draw background. 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 # Draw dominant color if necessarily. 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
442 - def export_skin(self, filepath):
443 ''' 444 Internal function to export skin. 445 ''' 446 # Build temp config file. 447 config_filepath = os.path.join("/tmp/%s", str(uuid.uuid4())) 448 touch_file(config_filepath) 449 self.save_skin(config_filepath) 450 451 # Build skin package. 452 with tarfile.open("%s.tar.gz" % filepath, "w:gz") as tar: 453 # Add config file. 454 tar.add(config_filepath, "config.ini", False) 455 456 # Add background image file. 457 tar.add(self.get_skin_file_path(self.image), self.image, False) 458 459 # Copy theme files is theme is not standard theme. 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 # Remove temp config file. 465 remove_file(config_filepath)
466
467 - def load_themes(self, ui_theme, app_theme):
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 # Load theme. 480 ui_theme.load_theme() 481 app_theme.load_theme() 482 483 # Init theme directories. 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