Chicago95/Plus/PlusGUI.py

1286 lines
56 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
from pluslib import ChicagoPlus
import logging
import sys
from pathlib import Path
from PIL import Image, ImageFont, ImageDraw, ImageEnhance, ImageOps
from pprint import pprint
import struct
import subprocess
import os
from shutil import copyfile
import textwrap
import numpy as np
import array
import argparse
import time
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GdkPixbuf, GLib
running_folder = os.path.dirname(os.path.abspath(__file__))
#print("Font List...", end=' ', flush=True)
fonts_output = subprocess.check_output(['convert', '-list', 'font'])
fonts = fonts_output.decode().split('\n')
installed_fonts = {}
for index, font in enumerate(fonts):
if "Font:" in font:
installed_fonts[fonts[index].split(":")[1].strip()] = {
fonts[index+1].split(":")[0].strip() : fonts[index+1].split(":")[1].strip(),
fonts[index+2].split(":")[0].strip() : fonts[index+2].split(":")[1].strip(),
fonts[index+3].split(":")[0].strip() : fonts[index+3].split(":")[1].strip(),
fonts[index+4].split(":")[0].strip() : fonts[index+4].split(":")[1].strip(),
fonts[index+5].split(":")[0].strip() : fonts[index+5].split(":")[1].strip()
}
#print("OK", end='\n', flush=True)
sys.stdout.flush()
pointers = {
#windows theme # Name
"arrow" : "Normal select",
"help" : "Help select",
"appstarting" : "Working in background",
"wait" : "Busy",
"crosshair" : "Precision select",
"ibeam" : "Text Select",
"nwpen" : "Handwriting",
"no" : "NO",
"sizens" : "Vertical resize",
"sizewe" : "Horizontal resize",
"sizenwse" : "Diagonal resize 1",
"sizenesw" : "Diagonal resize 2",
"sizeall" : "Move",
"uparrow" : "Alternate select"
}
icons = {
# Windows Themes : #Name
"my_computer" : "My Computer icon",
"network_neighborhood" : "Network Neighborhood icon",
"recycle_bin_full" : "Recycle Bin full icon",
"recycle_bin_empty" : "Recycle Bin empty icon",
"my_documents" : "My Documents icon"
}
sounds = {
'SystemAsterisk' : 'Asterisk',
'Close' : 'Close program',
'SystemHand' : 'Critical stop',
'.Default' : 'Default beep',
'SystemDefault' : 'Default sound',
'EmptyRecycleBin' : 'Empty Recylcle Bin',
'SystemExclamation' : 'Exclamation',
'SystemExit' : 'Exit Windows',
'Maximize' : 'Maximize',
'MenuCommand' : 'Menu command',
'MenuPopup' : 'Menu popup',
'Minimize' : 'Minimize',
'Open' : 'Open program',
'AppGPFault' : 'Program error',
'SystemQuestion' : 'Question',
'RestoreDown' : 'Restore down',
'RestoreUp' : 'Restore up',
'RingIn' : 'Ring in',
'RingOut' : 'Ring out',
'SystemStart' : 'Start Windows'
}
class MakePreview:
def __init__(self, theme_object):
#print("Reading theme file... {}".format(theme_file))
print("[MakePreview] Generating Preview Image")
self.plus = theme_object
self.plus.parse_theme()
self.set_metrics()
self.set_fonts()
self.get_icons()
self.get_wallpaper()
#self.plus.print_theme_config()
self.colors = {
"buttonface": "#C0C0C0",
"buttontext": "#000000",
"inactivetitle": "#808080",
"inactivetitletext": "#DFDFDF",
"inactiveborder": "#C0C0C0",
"buttondkshadow": "#000000",
"buttonshadow": "#808080",
"buttonhilight": "#FFFFFF",
"buttonlight": "#DFDFDF",
"activetitle": "#000080",
"titletext": "#FFFFFF",
"activeborder": "#C0C0C0",
"menutext": "#000000",
"menu": "#C0C0C0",
"hilighttext": "#FFFFFF",
"hilight": "#000080",
"window": "#FFFFFE",
"windowtext": "#000000",
"scrollbar": "#FFFFFF",
"background": "#000000",
"foreground": "#000000"
}
for i in self.colors:
try:
self.colors[i] = (self.plus.theme_config['colors'][i]['color'])
except KeyError:
continue
self.colors['foreground'] = self.black_or_white(self.colors['background'])
self.theme_name = self.plus.theme_config['theme_name']
self.buttons()
self.preview_gen()
# pprint(self.colors)
print("[MakePreview] Preview Generated")
def return_preview(self):
self.preview_window.save(running_folder+"/preview.png", "PNG")
return(running_folder+"/preview.png")
def return_preview_double(self):
self.preview_window.save(running_folder+"/preview_double.png", "PNG")
return(running_folder+"/preview_double.png")
def delete_preview(self):
os.remove(running_folder+"/preview.png")
def delete_preview_double(self):
os.remove(running_folder+"/preview_double.png")
def set_fonts(self):
print("[MakePreview] Fonts...", end=' ')
self.button_height = self.iCaptionHeight - 4
self.button_width = self.button_height + 2
self.lfMessageFont = self.get_font(self.msgfont)
self.lfcaptionfont = self.get_font(self.caption_font)
self.lfMenuFont = self.get_font(self.menufont)
self.arial = self.get_font("Nimbus Sans L")
self.arial_bold = self.get_font("Nimbus-Sans-L-Bold")
self.lfFont = self.get_font(self.iconfont)
self.cursor_font = self.get_font("Nimbus-Sans-L-Bold")
self.cursor_pt = 12
print("OK", end='\n', flush=True)
def buttons(self):
print("[MakePreview] Buttons...", end=' ')
buttons = ['minimize','maximize','close']
button_width = self.button_width
button_height = self.button_height
colors = self.colors
for button in buttons:
img = Image.new('RGB', (button_width, button_height), color = colors['buttondkshadow'])
draw = ImageDraw.Draw(img)
draw.line([(0,0),(button_width-2, 0), (0,0),(0, button_height-2)],fill=colors['buttonhilight'], width=1)
draw.line([(button_width-2,button_height-2),(button_height, 1)],fill=colors['buttonshadow'], width=1)
draw.line([(1,button_height-2),(button_width-2,button_height-2)],fill=colors['buttonshadow'], width=1)
draw.line([(1,1),(button_width-3, 1), (1,1),(1, button_height-3)],fill=colors['buttonlight'], width=1)
draw.rectangle(((2, 2), (button_width-3, button_height-3)), fill=colors['buttonface'], width=1)
if button_height < 16:
if button == "minimize":
draw.line([(4,9),(10, 9)],fill=colors['buttontext'], width=2)
self.min_button = img
elif button == 'maximize':
draw.line([(3,10),(11, 10)],fill=colors['buttontext'], width=1)
draw.line([(3,2),(11, 2)],fill=colors['buttontext'], width=2)
draw.line([(3,2),(3, 10)],fill=colors['buttontext'], width=1)
draw.line([(11,2),(11, 10)],fill=colors['buttontext'], width=1)
self.max_button = img
elif button == 'close':
img.putpixel( (4, 3), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (5, 3), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (5, 4), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (6, 4), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (6, 5), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (7, 5), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (7, 6), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (8, 6), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (8, 7), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (9, 7), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (9, 8), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (10, 8), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (10, 9), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (11, 9), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (4, 9), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (5, 9), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (5, 8), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (6, 8), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (6, 7), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (7, 7), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (7, 6), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (8, 6), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (8, 5), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (9, 5), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (9, 4), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (10, 4), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (10, 3), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
img.putpixel( (11, 3), tuple(int(colors['buttontext'].lstrip('#')[i:i+2], 16) for i in (0, 2, 4)) )
self.close_button = img
else:
if button == "minimize":
draw.line([(5, button_height - 6),(button_width - 8,button_height - 6)],fill=colors['buttontext'], width=2)
self.min_button = img
elif button == 'maximize':
draw.line([(4,button_height-5),(button_width - 6 , button_height - 5)],fill=colors['buttontext'], width=1)
draw.line([(4,4),(button_width - 6, 4)],fill=colors['buttontext'], width=2)
draw.line([(4,4),(4, button_height-5)],fill=colors['buttontext'], width=1)
draw.line([(button_width - 6, 4),(button_width - 6, button_height-5)],fill=colors['buttontext'], width=1)
self.max_button = img
elif button == 'close':
X = Image.open(running_folder+"/assets/X.png").convert('RGBA')
pixels = X.load()
rgb = struct.unpack('BBB',bytes.fromhex(colors['buttontext'].lstrip('#')))
for i in range(X.size[0]):
for j in range(X.size[1]):
if pixels[i,j] == (0, 0, 0, 255):
pixels[i,j] = rgb
x_w, x_h = X.size
offset = ((button_width - x_w) // 2, (button_height - x_h) // 2)
img.paste(X, offset, mask=X)
self.close_button = img
print("OK", end='\n', flush=True)
def set_metrics(self):
print("[MakePreview] Metrics...", end=' ', flush=True)
try:
self.iCaptionHeight = self.plus.theme_config['nonclientmetrics']['iCaptionHeight']
self.iMenuHeight = self.plus.theme_config['nonclientmetrics']['iMenuHeight']
self.iScrollWidth = self.plus.theme_config['nonclientmetrics']['iScrollWidth']
self.msgfont = self.plus.theme_config['nonclientmetrics']['lfMessageFont']['lfFaceName[32]']
self.msgfont_pt = abs(self.plus.theme_config['nonclientmetrics']['lfMessageFont']['lfHeight'])
self.caption_font = self.plus.theme_config['nonclientmetrics']['lfcaptionfont']['lfFaceName[32]']
self.caption_pt = abs(self.plus.theme_config['nonclientmetrics']['lfcaptionfont']['lfHeight'])
self.menufont = self.plus.theme_config['nonclientmetrics']['lfMenuFont']['lfFaceName[32]']
self.menufont_pt = abs(self.plus.theme_config['nonclientmetrics']['lfMenuFont']['lfHeight'])
except:
self.iCaptionHeight = 18
self.iMenuHeight = 18
self.iMenuWidth = 18
self.iScrollHeight = 13
self.iScrollWidth = 13
self.msgfont = "Microsoft Sans Serif"
self.caption_font = "MS-Reference-Sans-Serif-Bold"
self.menufont = "Microsoft Sans Serif"
self.menufont_pt = 10
self.caption_pt = 10
self.msgfont_pt = 10
try:
self.iconfont = self.plus.theme_config['iconmetrics']['lfFont']['lfFaceName[32]']
self.iconfont_pt = abs(self.plus.theme_config['iconmetrics']['lfFont']['lfHeight'])
except:
self.iconfont = "Microsoft Sans Serif"
self.iconfont_pt = 10
if self.iconfont_pt == 8:
self.iconfont_pt = 10
if self.msgfont_pt == 8:
self.msgfont_pt = 10
if self.caption_pt == 8:
self.caption_pt = 10
if self.menufont_pt == 8:
self.menufont_pt = 10
print("OK", end='\n', flush=True)
def get_icons(self):
print("[MakePreview] Icons...", end=' ', flush=True)
if self.plus.theme_config['icons']:
if self.plus.theme_config['icons']['my_computer']:
self.my_computer = self.make_icons(self.plus,'my_computer')
else:
self.my_computer = Image.open(running_folder+"/assets/my_computer~.png").convert('RGBA')
if self.plus.theme_config['icons']['network_neighborhood']:
self.network_neighborhood= self.make_icons(self.plus,'network_neighborhood')
else:
self.network_neighborhood = Image.open(running_folder+"/assets/network_neighborhood~.png").convert('RGBA')
if self.plus.theme_config['icons']['recycle_bin_empty']:
self.recycle_bin_empty = self.make_icons(self.plus,'recycle_bin_empty')
else:
self.recycle_bin_empty = Image.open(running_folder+"/assets/recycle_bin_empty~.png").convert('RGBA')
if self.plus.theme_config['icons']['my_documents']:
self.my_documents = self.make_icons(self.plus,'my_documents')
else:
self.my_documents = False
print("OK", end='\n', flush=True)
def drawlines(self, drawcontext, xy, outline=None, width=0):
(x1, y1), (x2, y2) = xy
points = (x1, y1), (x2, y1), (x2, y2), (x1, y2), (x1, y1)
drawcontext.line(points, fill=outline, width=width)
def black_or_white(self, background_color):
# Counting the perceptive luminance - human eye favors green color...
R, G, B = tuple(int(background_color.lstrip("#")[i:i+2], 16) for i in (0, 2, 4))
luminance = ( (0.299 * R) + (0.587 * G) + (0.114 * B))/255;
if (luminance > 0.5):
d = "#000000" # bright colors - black font
else:
d = "#FFFFFF" # dark colors - white font
return d
def get_font(self, fontname):
if self.plus.theme_config['fonts']:
if fontname in self.plus.theme_config['fonts']:
return self.plus.theme_config['fonts'][fontname]['path']
if fontname in ["MS Sans Serif", "MS Serif", "lr oƒSƒVƒbƒN"]:
fontname = "Microsoft Sans Serif"
if fontname in installed_fonts:
#print("Found installed font {}: {}".format(fontname,installed_fonts[fontname]['glyphs']))
return installed_fonts[fontname]['glyphs']
elif fontname.replace(' ','-') in installed_fonts:
return installed_fonts[fontname.replace(' ','-')]['glyphs']
else:
for i in installed_fonts:
if fontname.lower() == i.lower():
#print("Found installed font {}: {}".format(fontname,installed_fonts[i]['glyphs']))
return installed_fonts[i]['glyphs']
elif fontname.lower() in installed_fonts[i]['family'].lower():
#print("Found installed font {}: {}".format(fontname,installed_fonts[i]['glyphs']))
return installed_fonts[i]['glyphs']
elif fontname.replace(' ','-').lower() in i.lower():
#print("Found installed font {}: {}".format(fontname,installed_fonts[i]['glyphs']))
return installed_fonts[i]['glyphs']
#print("Font: {} NOT FOUND".format(fontname))
return self.get_font("Noto-Sans-Regular")
def preview_gen(self):
print("[MakePreview] Preview...", end=' ', flush=True)
colors = self.colors
tmp = Image.new('RGB', (500, 500), color = colors['activetitle'])
tmp_draw = ImageDraw.Draw(tmp)
#This generates the Message Box title you see in the preview windoow
msgboxtitle = Image.new('RGB', (173-6, self.iCaptionHeight), color = colors['activetitle'])
draw = ImageDraw.Draw(msgboxtitle)
myFont = ImageFont.truetype(self.lfcaptionfont, self.caption_pt)
w, h = draw.textsize("Message Box", font=myFont)
font_y_offset = myFont.getoffset("Message Box")[1]
draw.fontmode = "1"
draw.text((2,int(((self.iCaptionHeight-h)-font_y_offset)/2)), "Message Box", fill=colors['titletext'], font=myFont)
#This generates the Inactive Window title in the previre
inactive_window = Image.new('RGB', (202, self.iCaptionHeight+118+3), color = colors['buttondkshadow'])
inactivetitle = Image.new('RGB', (inactive_window.size[0]-8, self.iCaptionHeight), color = colors['inactivetitle'])
draw = ImageDraw.Draw(inactivetitle)
myFont = ImageFont.truetype(self.lfcaptionfont, self.caption_pt)
w, h = draw.textsize("Inactive Window", font=myFont)
font_y_offset = myFont.getoffset("Inactive Window")[1]
draw.fontmode = "1"
draw.text((2,int((self.iCaptionHeight-h)-font_y_offset)/2), "Inactive Window", fill=colors['inactivetitletext'], font=myFont)
#Now we create the Active window title in multiple steps, starting with the title
activetitle = Image.new('RGB', (217, self.iCaptionHeight), color = colors['activetitle'])
draw = ImageDraw.Draw(activetitle)
myFont = ImageFont.truetype(self.lfcaptionfont, self.caption_pt)
font_y_offset = myFont.getoffset("Active Window")[1]
w, h = draw.textsize("Active Window", font=myFont)
draw.fontmode = "1"
draw.text((2,int((self.iCaptionHeight-h)-font_y_offset)/2), "Active Window", fill=colors['titletext'], font=myFont)
#Next we draw the menubar
menufont = ImageFont.truetype(self.lfMenuFont, self.menufont_pt)
#normal_w, normal_h = tmp_draw.textsize("Normal", font=menufont)
menubar = Image.new('RGB', (activetitle.size[0], self.iMenuHeight), color = colors['menu'])
draw = ImageDraw.Draw(menubar)
#Normal menu item
normal_w, normal_h = draw.textsize("Normal", font=menufont)
font_y_offset = menufont.getoffset("Normal")[1]
draw.fontmode = "1"
draw.text((6,int(((menubar.size[1]-normal_h)-font_y_offset)/2)), "Normal", fill=colors['menutext'], font=menufont)
#Disabled menu item
disabled_w, disabled_h = draw.textsize("Disabled", font=menufont)
draw.text((normal_w+14,(int(((menubar.size[1]-normal_h)-font_y_offset)/2))+1), "Disabled", fill=colors['buttonhilight'], font=menufont)
draw.text((normal_w+13,int(((menubar.size[1]-normal_h)-font_y_offset)/2)), "Disabled", fill=colors['buttonshadow'], font=menufont)
#Selected menu item
selected_w, selected_h = draw.textsize("Selected", font=menufont)
#myFont.fontmode = "1"
#draw.text((6,int(menubar.size[1]-normal_h)/2), "Selected", fill=colors['hilighttext'], font=menufont)
selected = Image.new('RGB', (selected_w+12,menubar.size[1]), color = colors['hilight'])
selected_draw = ImageDraw.Draw(selected)
selected_draw.fontmode = "1"
font_y_offset = menufont.getoffset("Selected")[1]
selected_draw.text((int((selected.size[0]-selected_w)/2),int(((menubar.size[1]-normal_h)-font_y_offset)/2)), "Selected", fill=colors['hilighttext'], font=menufont)
menubar.paste(selected, (normal_w+13+disabled_w+6,int((menubar.size[1]-selected.size[1])/2)))
#Now we need to create the scrollbar, first up arrow
uparrow = Image.new('RGB', (self.iScrollWidth, self.iScrollWidth), color = colors['buttonface'])
draw = ImageDraw.Draw(uparrow)
draw.line([(0,0),(uparrow.size[0]-2, 0), (0,0), (0,uparrow.size[1]-2)],fill=colors['buttonlight'], width=1)
draw.line([(1,1),(uparrow.size[0]-3, 1), (1,1), (1,uparrow.size[1]-3)],fill=colors['buttonhilight'], width=1)
draw.line([(uparrow.size[0]-1,uparrow.size[1]-1),(uparrow.size[0]-1, 0), (uparrow.size[0]-1,uparrow.size[1]-1), (0,uparrow.size[1]-1)],fill=colors['buttondkshadow'], width=1)
draw.line([(uparrow.size[0]-2,uparrow.size[1]-2),(uparrow.size[0]-2, 1), (uparrow.size[0]-2,uparrow.size[1]-2), (1,uparrow.size[1]-2)],fill=colors['buttonshadow'], width=1)
draw.polygon([(4,7), (8,7), (6,5)], fill = colors['buttontext'])
#Next down arrow
downarrow = Image.new('RGB', (self.iScrollWidth, self.iScrollWidth), color = colors['buttonface'])
draw = ImageDraw.Draw(downarrow)
draw.line([(0,0),(downarrow.size[0]-2, 0), (0,0), (0,downarrow.size[1]-2)],fill=colors['buttonlight'], width=1)
draw.line([(1,1),(downarrow.size[0]-3, 1), (1,1), (1,downarrow.size[1]-3)],fill=colors['buttonhilight'], width=1)
draw.line([(downarrow.size[0]-1,downarrow.size[1]-1),(downarrow.size[0]-1, 0), (downarrow.size[0]-1,downarrow.size[1]-1), (0,downarrow.size[1]-1)],fill=colors['buttondkshadow'], width=1)
draw.line([(downarrow.size[0]-2,downarrow.size[1]-2),(downarrow.size[0]-2, 1), (downarrow.size[0]-2,downarrow.size[1]-2), (1,downarrow.size[1]-2)],fill=colors['buttonshadow'], width=1)
draw.polygon([(4,5), (8,5), (6,7)], fill = colors['buttontext'])
#With all the pieces done we can now create the scroll area
window = Image.new('RGB', (217, 72), color = colors['window'])
draw = ImageDraw.Draw(window)
draw.line([(0,0),(window.size[0]-2, 0), (0,0), (0,window.size[1]-2)],fill=colors['buttonshadow'], width=1)
draw.line([(1,1),(window.size[0]-3, 1), (1,1), (1,window.size[1]-3)],fill=colors['buttondkshadow'], width=1)
draw.line([(window.size[0]-1,window.size[1]-1),(window.size[0]-1, 0), (window.size[0]-1,window.size[1]-1), (0,window.size[1]-1)],fill=colors['buttonhilight'], width=1)
draw.line([(window.size[0]-2,window.size[1]-2),(window.size[0]-2, 1), (window.size[0]-2,window.size[1]-2), (1,window.size[1]-2)],fill=colors['buttonlight'], width=1)
window_font = ImageFont.truetype(self.arial_bold, 14)
draw.fontmode = "1"
font_y_offset = window_font.getoffset("Window Text")[1]
draw.text((4,7-font_y_offset), "Window Text", fill=colors['windowtext'], font=window_font)
window.paste(uparrow, (window.size[0]-2-uparrow.size[0],2))
draw.rectangle(((window.size[0]-2-uparrow.size[0],2+uparrow.size[1]),(window.size[0]-3, window.size[1]-3)), fill=colors['scrollbar'])
window.paste(downarrow, (window.size[0]-2-downarrow.size[0],window.size[1]-2-downarrow.size[1]))
#And with that we have all the peices to make the active window, first we make the window
activewindow = Image.new('RGB', (225, 4+self.iCaptionHeight+1+self.iMenuHeight+1+window.size[1]+4), color = colors['buttonface'])
draw = ImageDraw.Draw(activewindow)
draw.line([(0,0),(activewindow.size[0]-2, 0), (0,0), (0,activewindow.size[1]-2)],fill=colors['buttonlight'], width=1)
draw.line([(1,1),(activewindow.size[0]-3, 1), (1,1), (1,activewindow.size[1]-3)],fill=colors['buttonhilight'], width=1)
draw.line([(activewindow.size[0]-1,activewindow.size[1]-1),(activewindow.size[0]-1, 0), (activewindow.size[0]-1,activewindow.size[1]-1), (0,activewindow.size[1]-1)],fill=colors['buttondkshadow'], width=1)
draw.line([(activewindow.size[0]-2,activewindow.size[1]-2),(activewindow.size[0]-2, 1), (activewindow.size[0]-2,activewindow.size[1]-2), (1,activewindow.size[1]-2)],fill=colors['buttonshadow'], width=1)
draw.rectangle(((2, 2), (activewindow.size[0]-3, activewindow.size[1]-3)), fill=colors['activeborder'], width=1)
draw.rectangle(((3, 3), (activewindow.size[0]-4, activewindow.size[1]-4)), fill=colors['buttonface'], width=1)
#Then we put all the pieces inside
activewindow.paste(activetitle, (4,4))
activewindow.paste(self.close_button, (activewindow.size[0]-self.close_button.size[0]-6, 6))
activewindow.paste(self.max_button, (activewindow.size[0]-self.close_button.size[0]-6-2-self.max_button.size[0], 6))
activewindow.paste(self.min_button, (activewindow.size[0]-self.close_button.size[0]-6-2-self.max_button.size[0]-self.min_button.size[0], 6))
activewindow.paste(menubar, (4, 4+activetitle.size[1]+1))
activewindow.paste(window, (4, 4+activetitle.size[1]+1+menubar.size[1]+1))
# Next we create the message window, first making the 'ok' button
button = Image.new('RGB', (66, 22), color = colors['buttondkshadow'])
draw = ImageDraw.Draw(button)
draw.line([(0,0),(64, 0), (0,0), (0,20)],fill=colors['buttonhilight'], width=1)
draw.line([(button.size[0]-2,1),(button.size[0]-2,button.size[1]-2 )],fill=colors['buttonshadow'], width=1)
draw.line([(1,button.size[1]-2),(button.size[0]-2,button.size[1]-2)],fill=colors['buttonshadow'], width=1)
draw.line([(1,1),(button.size[0]-3, 1), (1,1),(1, button.size[1]-3)],fill=colors['buttonlight'], width=1)
draw.rectangle(((2, 2), (button.size[0]-3, button.size[1]-3)), fill=colors['buttonface'], width=1)
myFont = ImageFont.truetype(self.arial_bold, self.msgfont_pt)
draw.fontmode = "1"
font_y_offset = myFont.getoffset("OK")[1]
w, h = draw.textsize("OK", font=myFont)
draw.text(((66-w)/2,((22-h)-font_y_offset)/2), "OK", fill=colors['buttontext'], font=myFont)
#button.save("button.png", "PNG")
# Then we create the window itself
myFont = ImageFont.truetype(self.arial, self.msgfont_pt)
msg_text_w, msg_text_h = draw.textsize("Message Text", font=myFont)
message_box = Image.new('RGB', (173, self.iCaptionHeight+8+msg_text_h+3+button.size[1]+6), color = colors['buttondkshadow'])
draw = ImageDraw.Draw(message_box)
draw.line([(0,0),(171, 0), (0,0), (0,message_box.size[1]-2)],fill=colors['buttonlight'], width=1)
draw.line([(message_box.size[0]-2,1),(message_box.size[0]-2,message_box.size[1]-2 )],fill=colors['buttonshadow'], width=1)
draw.line([(1,message_box.size[1]-2),(message_box.size[0]-2,message_box.size[1]-2)],fill=colors['buttonshadow'], width=1)
draw.line([(1,1),(message_box.size[0]-3, 1), (1,1),(1, message_box.size[1]-3)],fill=colors['buttonhilight'], width=1)
draw.rectangle(((2, 2), (message_box.size[0]-3, message_box.size[1]-3)), fill=colors['activeborder'], width=1)
draw.rectangle(((3, 3), (message_box.size[0]-4, message_box.size[1]-4)), fill=colors['buttonface'], width=1)
draw.fontmode = "1"
font_y_offset = myFont.getoffset("Message Text")[1]
draw.text((7,self.iCaptionHeight+8-font_y_offset), "Message Text", fill=colors['windowtext'], font=myFont)
# We then put all the peices together
message_box.paste(msgboxtitle, (3,3))
message_box.paste(self.close_button, (173-self.close_button.size[0]-5, 5))
message_box.paste(button, (int((173-button.size[0])/2), self.iCaptionHeight+8+msg_text_h+3))
# We do the same for the inactive window, first creating them window
draw = ImageDraw.Draw(inactive_window)
draw.line([(0,0),(inactive_window.size[0]-2, 0), (0,0), (0,inactive_window.size[1]-2)],fill=colors['buttonlight'], width=1)
draw.line([(inactive_window.size[0]-2,1),(inactive_window.size[0]-2,inactive_window.size[1]-2 )],fill=colors['buttonshadow'], width=1)
draw.line([(1,inactive_window.size[1]-2),(inactive_window.size[0]-2,inactive_window.size[1]-2)],fill=colors['buttonshadow'], width=1)
draw.line([(1,1),(inactive_window.size[0]-3, 1), (1,1),(1, inactive_window.size[1]-3)],fill=colors['buttonhilight'], width=1)
draw.rectangle(((2, 2), (inactive_window.size[0]-3, inactive_window.size[1]-3)), fill=colors['activeborder'], width=1)
draw.rectangle(((3, 3), (inactive_window.size[0]-4, inactive_window.size[1]-4)), fill=colors['buttonface'], width=1)
#Then putting all the pieces inside
inactive_window.paste(inactivetitle, (4,4))
inactive_window.paste(self.close_button, (inactive_window.size[0]-self.close_button.size[0]-6, 6))
inactive_window.paste(self.max_button, (inactive_window.size[0]-self.close_button.size[0]-6-2-self.max_button.size[0], 6))
inactive_window.paste(self.min_button, (inactive_window.size[0]-self.close_button.size[0]-6-2-self.max_button.size[0]-self.min_button.size[0], 6))
height = 39 + (self.iCaptionHeight * 2) + self.iMenuHeight + message_box.size[1]
width = 4 + activewindow.size[0]
# Now that we've created all the windows we need, next is to put them all together as one
demowindows = Image.new('RGBA', (width, height), color = (0, 0, 0, 0))
demowindows.paste(inactive_window)
demowindows.paste(activewindow, (4,5+self.iCaptionHeight))
demowindows.paste(message_box, (12,39 + (self.iCaptionHeight * 2) + self.iMenuHeight))
########
# ~~~~~~~~~~~~~~~
########
# With the windows done we move on to the icons
# First we make the text under each icon
# My Computer
iconfont = ImageFont.truetype(self.lfFont, self.iconfont_pt)
size = iconfont.getsize("My Computer")
font_y_offset = iconfont.getoffset("My Computer")[1]
squaresize = (size[0] + 6, size[1] + 6- font_y_offset)
my_computer_text = Image.new('RGBA', squaresize, colors['background'])
iconfont_draw = ImageDraw.Draw(my_computer_text)
iconfont_draw.fontmode = "1"
iconfont_draw.text((3,3-font_y_offset), "My Computer", fill=colors['foreground'], font=iconfont)
# Network Neighborhood
size = iconfont.getsize("Network Neighborhood")
font_y_offset = iconfont.getoffset("Network Neighborhood")[1]
squaresize = (size[0] + 6, size[1] + 6 - font_y_offset)
network_neighborhood_text = Image.new('RGBA', squaresize, colors['background'])
iconfont_draw = ImageDraw.Draw(network_neighborhood_text)
iconfont_draw.fontmode = "1"
iconfont_draw.text((3,3-font_y_offset), "Network Neighborhood", fill=colors['foreground'],font=iconfont)
# Recycle Bin
size = iconfont.getsize("Recycle Bin")
font_y_offset = iconfont.getoffset("Recycle Bin")[1]
squaresize = (size[0] + 6, size[1] + 6- font_y_offset)
recycle_bin_empty_text = Image.new('RGBA', squaresize, colors['background'])
iconfont_draw = ImageDraw.Draw(recycle_bin_empty_text)
iconfont_draw.fontmode = "1"
iconfont_draw.text((3,3-font_y_offset), "Recycle Bin", fill=colors['foreground'], font=iconfont)
# My Documents
# Not all themes have one
if self.my_documents:
size = iconfont.getsize("My Documents")
font_y_offset = iconfont.getoffset("My Documents")[1]
squaresize = (size[0] + 6, size[1] + 6- font_y_offset)
my_documents_text = Image.new('RGBA', squaresize, colors['background'])
iconfont_draw = ImageDraw.Draw(my_documents_text)
iconfont_draw.fontmode = "1"
iconfont_draw.text((3,3-font_y_offset), "My Documents", fill=colors['foreground'], font=iconfont)
# Now we create a canvas to put all the icons and their text on
total_height = ( self.my_computer.size[1] + 4 + my_computer_text.size[1] + 16 +
self.network_neighborhood.size[1] + 4 + network_neighborhood_text.size[1] + 16 +
self.recycle_bin_empty.size[1] + 4 + recycle_bin_empty_text.size[1] )
if self.my_documents:
total_height += 16 + self.my_documents.size[1] + 4 + my_documents_text.size[1]
icons = Image.new('RGBA', (network_neighborhood_text.size[0], total_height), color = (0, 0, 0, 0))
# The center is determined by the longest text
icon_centerline = int((network_neighborhood_text.size[0]-self.network_neighborhood.size[0])/2)
# Then we start dropping in Icons/Text
icons.paste(self.my_computer, (icon_centerline,0), mask=self.my_computer)
icons.paste(my_computer_text, (int((icons.size[0]-my_computer_text.size[0])/2),self.my_computer.size[1]+4))
nn_height = self.my_computer.size[1] + 4 + my_computer_text.size[1] + 16
nn_text_height = self.network_neighborhood.size[1] + nn_height + 4
icons.paste(self.network_neighborhood, (icon_centerline,nn_height), mask=self.network_neighborhood)
icons.paste(network_neighborhood_text, (0, nn_text_height))
rb_height = nn_height + self.network_neighborhood.size[1] + 4 + network_neighborhood_text.size[1] + 16
rb_text_height = self.recycle_bin_empty.size[1] + rb_height + 4
icons.paste(self.recycle_bin_empty, (icon_centerline,rb_height), mask=self.recycle_bin_empty)
icons.paste(recycle_bin_empty_text, (int((network_neighborhood_text.size[0]-recycle_bin_empty_text.size[0])/2),rb_text_height))
if self.my_documents:
md_height = rb_height + self.recycle_bin_empty.size[1] + 4 + recycle_bin_empty_text.size[1] + 16
md_text_height = self.my_documents.size[1] + md_height + 4
icons.paste(self.my_documents, (icon_centerline,md_height), mask=self.my_documents)
icons.paste(my_documents_text, (int((network_neighborhood_text.size[0]-my_documents_text.size[0])/2),md_text_height))
#Finally we create the preview window and set it to the theme background color
theme = Image.new('RGB', (392, 332), color = colors['background'])
#Then we add the wallpaper is we need to
if self.wallpaper:
#; 0: The image is centered if TileWallpaper=0 or tiled if TileWallpaper=1
#; 2: The image is stretched to fill the screen
#; 6: The image is resized to fit the screen while maintaining the aspect
# ratio. (Windows 7 and later)
#; 10: The image is resized and cropped to fill the screen while maintaining
# the aspect ratio. (Windows 7 and later)
if self.tile:
tilew, tileh = self.wallpaper.resize((int(self.wallpaper.size[0]/2.6),int(self.wallpaper.size[1]/2.3))).size
twidth = int(theme.size[0]/tilew) + 1
theight = int(theme.size[1]/tileh) + 1
startw = 0
starth = 0
for i in range(0,theight):
for j in range(0,twidth):
theme.paste(self.wallpaper.resize((int(self.wallpaper.size[0]/2.6),int(self.wallpaper.size[1]/2.3))),
(startw,starth))
startw = startw + self.wallpaper.resize((int(self.wallpaper.size[0]/2.6),int(self.wallpaper.size[1]/2.3))).size[0]
starth = starth + self.wallpaper.resize((int(self.wallpaper.size[0]/2.6),int(self.wallpaper.size[1]/2.3))).size[1]
startw = 0
elif self.style == 2:
theme.paste(self.wallpaper.resize((392,332)))
else:
centered_size = self.wallpaper.resize((int(self.wallpaper.size[0]/2.6),int(self.wallpaper.size[1]/2.3))).size
theme.paste(self.wallpaper.resize((int(self.wallpaper.size[0]/2.6),int(self.wallpaper.size[1]/2.3))),
(int((theme.size[0]-centered_size[0])/2),int((theme.size[1]-centered_size[1])/2)))
theme.paste(icons, (1,35), mask=icons)
theme.paste(demowindows, (theme.size[0]- demowindows.size[0] - 2, theme.size[1]- demowindows.size[1]-7), mask=demowindows)
#theme.save(self.theme_name+".png", "PNG")
double = theme.resize((theme.size[0]*2,theme.size[1]*2))
#double.save(self.theme_name+"_double.png", "PNG")
self.preview_window = theme
self.preview_window_double = double
print("OK", end='\n', flush=True)
def get_wallpaper(self):
print("[MakePreview] Wallpaper...", end=' ', flush=True)
# WallpaperStyle=2
#; 0: The image is centered if TileWallpaper=0 or tiled if TileWallpaper=1
#; 2: The image is stretched to fill the screen
#; 6: The image is resized to fit the screen while maintaining the aspect
# ratio. (Windows 7 and later)
#; 10: The image is resized and cropped to fill the screen while maintaining
# the aspect ratio. (Windows 7 and later)
self.wallpaper = False
self.tile = False
if (self.plus.theme_config['wallpaper'] and self.plus.theme_config['wallpaper']['theme_wallpaper'] and
'path' in self.plus.theme_config['wallpaper']['theme_wallpaper'] and self.plus.theme_config['wallpaper']['theme_wallpaper']['path']):
#print(plus.theme_config['wallpaper']['theme_wallpaper']['path'])
#print(os.path.splitext(plus.theme_config['wallpaper']['theme_wallpaper']['path'])[1])
if os.path.splitext(self.plus.theme_config['wallpaper']['theme_wallpaper']['path'])[1].lower() in [".html", ".htm"]:
w = 1024
h = 768
if "800" in self.plus.theme_config['wallpaper']['theme_wallpaper']['path'] or "800" in self.plus.theme_name:
w = 800
h = 600
args = ['wkhtmltoimage', '--quiet','--height', str(h), '--width', str(w), self.plus.theme_config['wallpaper']['theme_wallpaper']['path'],'temp_html.png']
subprocess.check_call(args)
self.wallpaper = Image.open("temp_html.png").convert('RGBA')
os.remove("temp_html.png")
else:
try:
self.wallpaper = Image.open(self.plus.theme_config['wallpaper']['theme_wallpaper']['path']).convert('RGBA')
except OSError:
args = ['convert', '-resize', '32x32', self.plus.theme_config['wallpaper']['theme_wallpaper']['path'], "temp_bmp.png"]
subprocess.check_call(args)
self.wallpaper = Image.open("temp_bmp.png").convert('RGBA')
os.remove("temp_bmp.png")
if self.plus.theme_config['wallpaper']['theme_wallpaper']['tilewallpaper']:
self.tile = True
self.style = self.plus.theme_config['wallpaper']['theme_wallpaper']['wallpaperstyle']
print("OK", end='\n', flush=True)
def make_icons(self, plus, ico_name):
icon = running_folder+"/assets/" + ico_name+"~"+".png"
if plus.theme_config['icons'][ico_name]['type'] in ['dll', 'icl']:
index = plus.theme_config['icons'][ico_name]['index']
icon_files = plus.extract_icons_from_dll(plus.theme_config['icons'][ico_name]['path'])
if icon_files:
icon_filename, icon_file = plus.get_icons_size_dll(icon_files, index)
if icon_filename:
f = open(running_folder+"/tmp/tmp_"+icon_filename,"wb")
f.write(icon_file)
f.close()
icon = running_folder+"/tmp/tmp_"+icon_filename
else:
icon = running_folder+"/assets/" + ico_name+"~"+".png"
else:
icon_files = plus.extract_ico(plus.theme_config['icons'][ico_name]['path'])
if icon_files == 'bmp':
icon = plus.theme_config['icons'][ico_name]['path']
elif icon_files:
for i in icon_files:
if i['Width'] == 32:
icon = "{}[{}]".format(plus.theme_config['icons'][ico_name]['path'], i['ID'])
break
else:
icon = "{}[{}]".format(plus.theme_config['icons'][ico_name]['path'], i['ID'])
args = ['convert', '-resize', '32x32', icon, ico_name+".png"]
try:
subprocess.check_call(args)
icon_image = Image.open(ico_name+".png").convert('RGBA')
os.remove(ico_name+".png")
except subprocess.CalledProcessError:
icon_image = Image.open(running_folder+"/assets/" + ico_name+"~.png").convert('RGBA')
return icon_image
class plusGTK:
def __init__(self, themefile=False, colors=32, overlap=1,
squaresize=20, installdir=os.getcwd(),
chicago95_cursor_path=str(Path.home())+"/.icons/Chicago95_Cursor_Black",
chicago95_theme_path=str(Path.home())+"/.themes/Chicago95",
chicago95_icons_path=str(Path.home())+"/.icons/Chicago95",
loglevel=logging.WARNING,
logfile='plus.log'):
self.themefile=themefile
self.colors=colors
self.overlap=overlap
self.squaresize=squaresize
self.installdir=installdir
self.chicago95_cursor_path=chicago95_cursor_path
self.chicago95_theme_path=chicago95_theme_path
self.chicago95_icons_path=chicago95_icons_path
self.loglevel=loglevel
self.logfile=logfile
# Define signal mappings for builder
self.handlers = {
"cancel" : self.cancel,
"onDestroy": Gtk.main_quit,
"theme_chosen": self.open_file,
"install_screensaver" : self.set_install_screensaver,
"install_sounds" : self.set_install_sounds,
"install_cursors" : self.set_install_cursors,
"install_wallpaper" : self.set_install_wallpaper,
"install_icons" : self.set_install_icons,
"install_colors" : self.set_install_colors,
"install_fonts" : self.set_install_fonts,
"change" : self.open_file,
"warning_ok": self.warning_ok,
"screen_saver_preview" : self.screen_saver_preview,
"other_previews" : self.other_previews,
"show_cursor": self.show_cursor,
"show_icon": self.show_icon,
"show_sound": self.show_sound,
"play_sound": self.play_sound,
"install" : self.install_accept,
"install_ok": self.install_ok,
"preview_closed" : self.preview_closed
}
# GTK Initialization
self.builder = builder = Gtk.Builder()
self.builder.add_from_file(running_folder+"/plus.glade")
self.window = self.builder.get_object("Main")
self.preview = self.builder.get_object("preview")
self.builder.connect_signals(self.handlers)
self.file_chooser = self.builder.get_object("open_theme")
self.filefilter = self.builder.get_object("Microsoft Theme File")
self.file_chooser.add_filter(self.filefilter)
self.install_cursors = True
self.install_icons = True
self.install_wallpaper = True
self.install_sounds = True
self.install_colors = True
self.install_fonts = True
self.install_screensaver = True
self.theme_selected = False
if self.themefile:
self.theme = ChicagoPlus(
themefile=self.themefile,
loglevel=self.loglevel,
colors=self.colors,
overlap=self.overlap,
squaresize=self.squaresize,
installdir=self.installdir,
chicago95_cursor_path=self.chicago95_cursor_path,
chicago95_theme_path=self.chicago95_theme_path,
chicago95_icons_path=self.chicago95_icons_path,
logfile=self.logfile)
self.preview_image = MakePreview(self.theme)
self.theme_config = self.theme.theme_config
theme_name = self.builder.get_object("theme_name")
preview_theme_name = self.builder.get_object("Preview Theme Name")
theme_name.set_text(self.preview_image.theme_name)
preview_theme_name.set_text("Preview of '{}'".format(self.preview_image.theme_name))
preview = self.preview_image.return_preview()
self.preview.set_from_file(preview)
self.theme_selected = True
self.preview_image.delete_preview()
self.window.show_all()
def cancel(self, button):
Gtk.main_quit()
def open_file(self, button):
#image_file = "demo2.png"
#############################################################
#self.preview.set_from_file(image_file)
#############################################################
#print("Image rendered")
self.themefile = self.file_chooser.get_filename()
#print(theme_file)
self.theme = ChicagoPlus(
themefile=self.themefile,
loglevel=self.loglevel,
colors=self.colors,
overlap=self.overlap,
squaresize=self.squaresize,
installdir=self.installdir,
chicago95_cursor_path=self.chicago95_cursor_path,
chicago95_theme_path=self.chicago95_theme_path,
chicago95_icons_path=self.chicago95_icons_path,
logfile=self.logfile)
self.preview_image = MakePreview(self.theme)
self.theme.parse_theme()
self.theme_config = self.theme.theme_config
theme_name = self.builder.get_object("theme_name")
preview_theme_name = self.builder.get_object("Preview Theme Name")
theme_name.set_text(self.preview_image.theme_name)
preview_theme_name.set_text("Preview of '{}'".format(self.preview_image.theme_name))
preview = self.preview_image.return_preview()
self.preview.set_from_file(preview)
self.theme_selected = True
self.preview_image.delete_preview()
def set_install_screensaver(self, toggle):
if self.install_screensaver:
self.install_screensaver = False
else:
self.install_screensaver = True
def set_install_cursors(self, toggle):
if self.install_cursors:
self.install_cursors = False
else:
self.install_cursors = True
def set_install_sounds(self, toggle):
if self.install_sounds:
self.install_sounds = False
else:
self.install_sounds = True
def set_install_wallpaper(self, toggle):
if self.install_wallpaper:
self.install_wallpaper = False
else:
self.install_wallpaper = True
def set_install_icons(self, toggle):
if self.install_icons:
self.install_icons = False
else:
self.install_icons = True
def set_install_colors(self, toggle):
if self.install_colors:
self.install_colors = False
else:
self.install_colors = True
def set_install_fonts(self, toggle):
if self.install_fonts:
self.install_fonts = False
else:
self.install_fonts = True
def screen_saver_preview(self, button):
if not self.theme_config['screensaver']:
self.warning_msg("Screen Saver Preview", "{} does not include a screensaver".format(self.theme_config['theme_name']))
return
try:
wine = subprocess.check_output(["which", "wine"]).strip()
except subprocess.CalledProcessError:
self.warning_msg("Screen Saver Preview", "Wine is not installed and is required to preview screensavers.")
return
args = [wine, self.theme_config['screensaver'], '/s']
subprocess.check_call(args)
def in_store(self, store, name):
for row in store:
if row[1] == name:
return True
return False
def in_store_location(self, store, name):
for x in range(len(store)):
if store[x][1] == name:
return x
return 0
def other_previews(self, button):
checkmark = GdkPixbuf.Pixbuf.new_from_file(running_folder+"/assets/check.png")
nocheckmark = GdkPixbuf.Pixbuf.new_from_file(running_folder+"/assets/blank-check.png")
self.previews_window = self.builder.get_object("Preview Window")
self.cursor_preview = self.builder.get_object("cursor_preview")
self.cursor_preview.set_from_file(running_folder+"/assets/blank-check.png")
self.icon_preview = self.builder.get_object("icon_preview")
self.icon_preview.set_from_file(running_folder+"/assets/blank-check.png")
self.sound_preview = self.builder.get_object("sound_preview")
self.sound_preview.set_from_file(running_folder+"/assets/blank-check.png")
self.cursor_preview = self.builder.get_object("cursor_preview")
self.cursor_preview.set_from_file(running_folder+"/assets/blank-check.png")
# Populate cursor preview
self.cursor_store = self.builder.get_object("cursor_list")
for current_cursor in pointers:
print("[previews] Generating cursor preview for: {} (name: {})".format(current_cursor, pointers[current_cursor]))
if (current_cursor not in self.theme_config['cursors'] or not
self.theme_config['cursors'][current_cursor] or not
self.theme_config['cursors'][current_cursor]['path']):
if not self.in_store(self.cursor_store, pointers[current_cursor]):
self.cursor_store.append([nocheckmark,pointers[current_cursor]])
else:
loc = self.in_store_location(self.cursor_store, pointers[current_cursor])
self.cursor_store[loc][0] = nocheckmark
else:
filename = self.theme_config['cursors'][current_cursor]['path']
cursor_filename = self.theme_config['cursors'][current_cursor]['filename']
cursor_type = self.theme_config['cursors'][current_cursor]['type']
convert_args = ['convert', '-dispose', 'Background']
if cursor_type == 'ani':
ani_file_config = self.theme.extract_ani(filename)
# convert -delay X image1 -delay Y image2 -delay Z image3 -loop 0 animation.gif
if ani_file_config['seq']:
for sequence in ani_file_config['seq']:
if ani_file_config['rate']:
rate = ani_file_config['rate'][sequence] + 5
else:
rate = ani_file_config['anih']['iDispRate'] + 5
for icon in ani_file_config['icon']:
if icon['index'] == sequence:
cur_filename = current_cursor+"_"+str(sequence)
f = open(running_folder+"/tmp/"+cur_filename+".cur","wb")
f.write(icon['ico_file'])
f.close()
convert_args.append("-delay")
convert_args.append("{}x60".format(rate))
convert_args.append(running_folder+"/tmp/"+cur_filename+".cur")
else:
for icon in ani_file_config['icon']:
rate = ani_file_config['anih']['iDispRate'] + 5
cur_filename = current_cursor+"_"+str(icon['index'])
f = open(running_folder+"/tmp/"+cur_filename+".cur","wb")
f.write(icon['ico_file'])
f.close()
convert_args.append("-delay")
convert_args.append("{}x60".format(rate))
convert_args.append(running_folder+"/tmp/"+cur_filename+".cur")
convert_args.append("-loop")
convert_args.append("0")
convert_args.append(running_folder+"/tmp/"+current_cursor+".gif")
# pprint(convert_args)
try:
subprocess.check_call(convert_args)
except:
copyfile(running_folder+"/assets/blank-check.png", running_folder+"/tmp/"+current_cursor+".gif")
else:
cursor_file_config = self.theme.extract_cur(filename)
icon_file = cursor_file_config['icon'][0]['ico_file']
f = open(running_folder+"/tmp/"+current_cursor+".cur","wb")
f.write(icon_file)
f.close()
try:
subprocess.check_call(['convert', running_folder+"/tmp/"+current_cursor+".cur", running_folder+"/tmp/"+current_cursor+".gif"])
except:
copyfile(running_folder+"/assets/blank-check.png", running_folder+"/tmp/"+current_cursor+".gif")
if not self.in_store(self.cursor_store, pointers[current_cursor]):
self.cursor_store.append([checkmark,pointers[current_cursor]])
else:
loc = self.in_store_location(self.cursor_store, pointers[current_cursor])
self.cursor_store[loc][0] = checkmark
# Populate Icons
self.icon_store = self.builder.get_object("icon_list")
#pprint(self.theme_config)
#print(self.theme_config['wallpaper'] and self.theme_config['wallpaper']['theme_wallpaper'])
# Wallpaper
print("[previews] Getting wallpaper")
if self.theme_config['wallpaper'] and self.theme_config['wallpaper']['theme_wallpaper']:
if not self.in_store(self.icon_store, "Wallpaper bitmap"):
self.icon_store.append([checkmark,"Wallpaper bitmap"])
else:
loc = self.in_store_location(self.icon_store, "Wallpaper bitmap")
self.icon_store[loc][0] = checkmark
else:
if not self.in_store(self.icon_store, "Wallpaper bitmap"):
self.icon_store.append([nocheckmark,"Wallpaper bitmap"])
else:
loc = self.in_store_location(self.icon_store, "Wallpaper bitmap")
self.icon_store[loc][0] = nocheckmark
# Icons
for icon in icons:
print("[previews] Generating icon preview for: {} (name: {})".format(icon, icons[icon]))
if not self.theme_config['icons'][icon]:
if not self.in_store(self.icon_store, icons[icon]):
self.icon_store.append([nocheckmark,icons[icon]])
else:
loc = self.in_store_location(self.icon_store, icons[icon])
self.icon_store[loc][0] = nocheckmark
else:
icon_image = self.preview_image.make_icons(self.theme, icon)
icon_image.save(running_folder+"/tmp/"+icon+".png", "PNG")
if not self.in_store(self.icon_store, icons[icon]):
self.icon_store.append([checkmark,icons[icon]])
else:
loc = self.in_store_location(self.icon_store, icons[icon])
self.icon_store[loc][0] = checkmark
#screensaver
print("[previews] Getting screensaver")
if self.theme_config['screensaver']:
if not self.in_store(self.icon_store, "Screen saver"):
self.icon_store.append([checkmark,"Screen saver"])
else:
loc = self.in_store_location(self.icon_store, "Screen saver")
self.icon_store[loc][0] = checkmark
else:
if not self.in_store(self.icon_store, "Screen saver"):
self.icon_store.append([nocheckmark,"Screen saver"])
else:
loc = self.in_store_location(self.icon_store, "Screen saver")
self.icon_store[loc][0] = nocheckmark
# Sounds
self.sound_store = self.builder.get_object("sound_list")
for sound in sounds:
print("[previews] Generating sound preview for: {} (name: {})".format(sound, sounds[sound]))
if sound not in self.theme_config['sounds']:
if not self.in_store(self.sound_store, sounds[sound]):
self.sound_store.append([nocheckmark,sounds[sound]])
else:
loc = self.in_store_location(self.sound_store, sounds[sound])
self.sound_store[loc][0] = nocheckmark
else:
if not self.in_store(self.sound_store, sounds[sound]):
self.sound_store.append([checkmark,sounds[sound]])
else:
loc = self.in_store_location(self.sound_store, sounds[sound])
self.sound_store[loc][0] = checkmark
self.sound_path = False
for sound in sounds:
if sound in self.theme_config['sounds']:
self.sound_path = self.theme_config['sounds'][sound]
break
self.previews_window.show_all()
def show_cursor(self,widget, row, col):
self.cursor_text_path = self.builder.get_object("cursor_path")
model = widget.get_model()
for cursor in pointers:
if pointers[cursor] == model[row][1]:
if cursor in self.theme_config['cursors'] and self.theme_config['cursors'][cursor] is not False:
self.cursor_preview.set_from_file(running_folder+"/tmp/"+cursor+".gif")
self.cursor_text_path.set_text(self.theme_config['cursors'][cursor]['path'])
else:
self.cursor_preview.set_from_file(running_folder+"/assets/blank-check.png")
self.cursor_text_path.set_text("")
break
def show_icon(self,widget, row, col):
self.icon_text_path = self.builder.get_object("icon_path")
model = widget.get_model()
if model[row][1] == "Wallpaper bitmap":
if self.theme_config['wallpaper'] and self.theme_config['wallpaper']['theme_wallpaper']:
self.icon_text_path.set_text(self.theme_config['wallpaper']['theme_wallpaper']['path'])
self.icon_preview.set_from_file(running_folder+"/assets/blank-check.png")
else:
self.icon_preview.set_from_file(running_folder+"/assets/blank-check.png")
self.icon_text_path.set_text("")
return
if model[row][1] == "Screen saver":
if self.theme_config['screensaver'] :
self.icon_text_path.set_text(self.theme_config['screensaver'])
self.icon_preview.set_from_file(running_folder+"/assets/blank-check.png")
else:
self.icon_preview.set_from_file(running_folder+"/assets/blank-check.png")
self.icon_text_path.set_text("")
return
for icon in icons:
#print(icon, icons[icon], model[row][1])
if icons[icon] == model[row][1]:
if self.theme_config['icons'][icon] is not False:
self.icon_preview.set_from_file(running_folder+"/tmp/"+icon+".png")
self.icon_text_path.set_text(self.theme_config['icons'][icon]['path'])
else:
self.icon_preview.set_from_file(running_folder+"/assets/blank-check.png")
self.icon_text_path.set_text("")
break
def show_sound(self,widget, row, col):
self.sound_text_path = self.builder.get_object("sound_path")
model = widget.get_model()
for sound in sounds:
if sounds[sound] == model[row][1]:
if sound in self.theme_config['sounds'] and self.theme_config['sounds'][sound]:
self.sound_path = self.theme_config['sounds'][sound]
self.sound_text_path.set_text(self.sound_path)
else:
self.sound_path = False
self.sound_text_path.set_text("")
def play_sound(self, button):
if self.sound_path:
#print("Playing {} with aplay".format(self.sound_path))
try:
subprocess.check_call(['aplay', self.sound_path])
except:
self.warning_msg("Error", "aplay required to play sound previews or sound file corrupt.")
def preview_closed(self, *args):
self.previews_window.hide()
return True
def warning_msg(self, title="Error", message="Error"):
self.warning_popup = self.builder.get_object("Warning")
warning_dialogue = self.builder.get_object("warning_label")
self.warning_popup.set_title(title)
warning_dialogue.set_text(message)
self.warning_popup.show_all()
def warning_ok(self, *args):
self.warning_popup.hide()
return True
def install_accept(self, button):
self.install_theme()
return
def install_ok(self, button):
if not self.theme_selected:
return False
self.install_theme()
Gtk.main_quit()
def install_theme(self):
if not self.theme_selected:
return False
print("Installing theme with the following options:")
options = "Theme File: {}\nInkscape Options:\n\tColors: {} Overlap: {} Squaresize: {}\nInstall Directory: {}\nPaths:\n\tCursor Path: {}\n\tTheme Path: {}\n\tIcons Path: {}".format(
self.theme_config['theme_file'], self.colors, self.overlap, self.squaresize,
self.installdir, self.chicago95_cursor_path, self.chicago95_theme_path,
self.chicago95_icons_path)
checks = "Install (checkbox) Options:\n\tCursors: {}\n\tIcons: {}\n\tWallpaper: {}\n\tSounds: {}\n\tColors: {}\n\tFonts: {}\n\tScreensaver: {}".format(
self.install_cursors, self.install_icons, self.install_wallpaper,
self.install_sounds, self.install_colors, self.install_fonts, self.install_screensaver)
print(options)
print(checks)
self.theme.go(cursors=self.install_cursors, icons=self.install_icons, wallpaper=self.install_wallpaper,
sounds=self.install_sounds, colors=self.install_colors, fonts=self.install_fonts, screensaver=self.install_screensaver)
def main():
desc = '''Chicago95 Plus!'''
arg_parser = argparse.ArgumentParser(description=desc,
usage='%(prog)s [options] [MS Theme File]',
epilog="Part of the Chicago95 theme project",
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
arg_parser.add_argument('-d', '--debug', help="Print lots of debugging statements", action="store_const", dest="loglevel", const=logging.DEBUG, default=logging.WARNING)
arg_parser.add_argument('-v', '--verbose', help="Be verbose", action="store_const", dest="loglevel", const=logging.INFO)
arg_parser.add_argument('-c', '--colors', help='How many colors before skipping Inkscape fix/merge for SVGs. Set to 1 to speed up conversion. WARNING: This may result in transparent icons!', default=32, type=int)
arg_parser.add_argument('-o', '--overlap', help='Pixel overlap for SVG icons', default=1, type=int)
arg_parser.add_argument('-s', '--squaresize', help='Square size for SVG icons', default=20, type=int)
arg_parser.add_argument('--cursorfolder', help="Chicago95 cursor folder to convert to new theme", default=str(Path.home())+"/.icons/Chicago95_Cursor_Black")
arg_parser.add_argument('--themefolder', help="Chicago95 theme folder to convert to new theme", default=str(Path.home())+"/.themes/Chicago95")
arg_parser.add_argument('--iconsfolder', help="Chicago95 icons folder to convert to new theme", default=str(Path.home())+"/.icons/Chicago95")
arg_parser.add_argument("--installdir", help="Folder to create new theme in, default is current working directory", default=os.getcwd())
arg_parser.add_argument("--logfile", help="Filename for debug logging", default="chicago95_plus.log")
arg_parser.add_argument("theme_file", help="Microsoft Windows 95/98/ME .theme file", nargs="?",default=False)
args = arg_parser.parse_args()
plus = plusGTK(themefile=args.theme_file,
loglevel=args.loglevel,
colors=args.colors,
overlap=args.overlap,
squaresize=args.squaresize,
installdir=args.installdir,
chicago95_cursor_path=args.cursorfolder,
chicago95_theme_path=args.themefolder,
chicago95_icons_path=args.iconsfolder,
logfile=args.logfile)
#plus = plusGTK()
Gtk.main()
main()