Reworked GUI to be more space friendlty.

- Added compression ability for nw executables
- Added tabs to navigate options
- Added file menu with recent files and keyboard shortcuts
- Added a status bar for displaying information about fields
This commit is contained in:
Joey Payne 2015-04-21 08:02:19 -06:00
commit 17532053c9
21 changed files with 1215 additions and 113 deletions

0
build_windows.bat Normal file → Executable file
View file

View file

@ -5,7 +5,9 @@ from pycns import save_icns
from pepy.pe import PEFile
import urllib2
import platform
import re
import time
import sys
import os
import glob
@ -36,6 +38,11 @@ inside_packed_exe = getattr(sys, 'frozen', '')
CWD = os.getcwd()
def get_file(path):
parts = path.split('/')
independent_path = os.path.join(CWD, *parts)
return independent_path
TEMP_DIR = get_temp_dir()
DEFAULT_DOWNLOAD_PATH = os.path.join(CWD,
'files',
@ -99,6 +106,7 @@ class Setting(object):
self.filter = kwargs.pop('filter', '.*')
self.filter_action = kwargs.pop('filter_action', 'None')
self.check_action = kwargs.pop('check_action', 'None')
self.action = kwargs.pop('action', None)
self.set_extra_attributes_from_keyword_args(**kwargs)
@ -309,9 +317,13 @@ class CommandBase(object):
for setting_group, setting_group_dict in sgroup_items:
settings['setting_groups'].append(settings[setting_group])
self._setting_items = (config['setting_groups'].items() +
[('export_settings', config['export_settings'])] +
[('compression', config['compression'])])
config.pop('setting_groups')
config.pop('export_settings')
config.pop('compression')
self._setting_items += config.items()
for key, val in config.items():
settings[key] = val
@ -450,7 +462,8 @@ class CommandBase(object):
dl_export_items = (self.settings['download_settings'].items() +
self.settings['export_settings'].items() +
self.settings['compression'].items())
self.settings['compression'].items() +
self.settings['web2exe_settings'].items())
for setting_name, setting in dl_export_items:
if setting.value is not None:
dic['webexe_settings'][setting_name] = setting.value
@ -513,6 +526,8 @@ class CommandBase(object):
if setting.type == 'list':
val_str = self.convert_val_to_str(new_dic[item])
setting.value = val_str
if setting.type == 'range':
setting.value = new_dic[item]
if isinstance(new_dic[item], dict):
stack.append((item, new_dic[item]))
return setting_list
@ -678,7 +693,7 @@ class CommandBase(object):
if windows:
self.replace_icon_in_exe(nw_path)
#self.compress_nw(nw_path)
self.compress_nw(nw_path)
dest_binary_path = os.path.join(export_dest,
self.project_name() +
@ -709,15 +724,29 @@ class CommandBase(object):
def compress_nw(self, nw_path):
compression = self.get_setting('nw_compression_level')
upx_bin = os.path.join('files', 'compressors', 'upx-linux-x64')
cmd = '{upx_bin} --lzma -{comp_level} -o test {path}'.format(upx_bin=upx_bin,
comp_level=compression.value,
path=nw_path)
print cmd
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
output, err = proc.communicate()
print err, output
comp_dict = {'Darwin64bit': get_file('files/compressors/upx-mac'),
'Darwin32bit': get_file('files/compressors/upx-mac'),
'Linux64bit': get_file('files/compressors/upx-linux-x64'),
'Linux32bit': get_file('files/compressors/upx-linux-x32'),
'Windows64bit': get_file('files/compressors/upx-win.exe'),
'Windows32bit': get_file('files/compressors/upx-win.exe')
}
plat = platform.system()+platform.architecture()[0]
upx_version = comp_dict.get(plat, None)
if upx_version is not None:
upx_bin = os.path.join('files', 'compressors', upx_version)
os.chmod(upx_bin, 0755)
cmd = [upx_bin, '--lzma', '-{}'.format(compression.value), str(nw_path)]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.progress_text = '\nCompressing files'
while proc.poll() is None:
self.progress_text += '.'
time.sleep(5)
output, err = proc.communicate()
def copy_files_to_project_folder(self):
old_dir = CWD

BIN
files/compressors/upx-linux-x32 Executable file

Binary file not shown.

BIN
files/compressors/upx-linux-x64 Executable file

Binary file not shown.

BIN
files/compressors/upx-mac Executable file

Binary file not shown.

BIN
files/compressors/upx-win.exe Executable file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

View file

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
id="SVGRoot"
version="1.1"
inkscape:version="0.91+devel r"
sodipodi:docname="app_settings.svg">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.627417"
inkscape:cx="2.5341245"
inkscape:cy="6.1584452"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1855"
inkscape:window-height="1056"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:grid-bbox="true" />
<defs
id="defs4143">
<linearGradient
inkscape:collect="always"
id="linearGradient4772">
<stop
style="stop-color:#d3d3d3;stop-opacity:1;"
offset="0"
id="stop4774" />
<stop
style="stop-color:#d3d3d3;stop-opacity:0;"
offset="1"
id="stop4776" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4730">
<stop
style="stop-color:#3d3d3e;stop-opacity:1;"
offset="0"
id="stop4732" />
<stop
style="stop-color:#3d3d3e;stop-opacity:0;"
offset="1"
id="stop4734" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4730"
id="linearGradient4736"
x1="13.593119"
y1="13.064024"
x2="-124.15217"
y2="-100.05997"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0439827,0,0,1.0439827,-0.33554965,-0.28661264)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4772"
id="linearGradient4780"
x1="6.4024119"
y1="3.2154982"
x2="46.513737"
y2="26.952219"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4772"
id="linearGradient4826"
gradientUnits="userSpaceOnUse"
x1="6.4024119"
y1="3.2154982"
x2="46.513737"
y2="26.952219"
gradientTransform="matrix(0.94762762,0.21358123,-0.21358123,0.94762762,2.5055978,-1.2401189)" />
</defs>
<metadata
id="metadata4146">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<rect
style="opacity:1;fill:url(#linearGradient4736);fill-opacity:1;stroke:none;stroke-width:62.59950638;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4700"
width="14.126391"
height="13.637024"
x="0.93680429"
y="1.181488"
ry="2.055341" />
<path
style="opacity:1;fill:url(#linearGradient4826);fill-opacity:1;stroke:none;stroke-width:53.80522919;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
clip-path="none"
d="M 7.9398486,2.1449285 C 5.5056259,2.1703938 7.8595712,2.981495 5.7642049,4.2206599 3.6688388,5.4598248 4.0944274,3.0051573 2.8993696,5.1259886 1.7043117,7.24682 3.5834863,5.611655 3.6089516,8.0458778 3.6344164,10.480101 1.7213755,8.886713 2.9605405,10.982079 c 1.2391648,2.095366 0.7623552,-0.350899 2.8831866,0.844158 2.1208313,1.195059 -0.2157595,2.054299 2.2184632,2.028833 2.4342227,-0.02546 0.078238,-0.834526 2.1736047,-2.073692 2.095366,-1.239164 1.669777,1.215503 2.864835,-0.905328 C 14.295688,8.7552183 12.416513,10.388344 12.391048,7.9541215 12.365583,5.5198987 14.278624,7.1153253 13.03946,5.0199591 11.800294,2.9245929 12.277104,5.3708591 10.156273,4.1758012 8.0354415,2.9807433 10.374072,2.1194634 7.9398486,2.1449285 Z m 0.061171,3.6417054 A 2.2146216,2.2146216 0 0 1 10.215405,8.0010191 2.2146216,2.2146216 0 0 1 8.0010195,10.215404 2.2146216,2.2146216 0 0 1 5.7866343,8.0010191 2.2146216,2.2146216 0 0 1 8.0010195,5.7866339 Z"
id="path4738"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

View file

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/home/joey/Projects/Web2Executable/files/images/compress_settings.png"
sodipodi:docname="compress_settings.svg"
inkscape:version="0.91+devel r"
version="1.1"
id="SVGRoot"
viewBox="0 0 16 16"
height="16px"
width="16px">
<sodipodi:namedview
inkscape:grid-bbox="true"
inkscape:window-maximized="1"
inkscape:window-y="24"
inkscape:window-x="65"
inkscape:window-height="1056"
inkscape:window-width="1855"
showgrid="false"
inkscape:current-layer="layer1"
inkscape:document-units="px"
inkscape:cy="10.205154"
inkscape:cx="0.67126005"
inkscape:zoom="11.313709"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<defs
id="defs4143">
<linearGradient
id="linearGradient4772"
inkscape:collect="always">
<stop
id="stop4774"
offset="0"
style="stop-color:#d3d3d3;stop-opacity:1;" />
<stop
id="stop4776"
offset="1"
style="stop-color:#d3d3d3;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient4730"
inkscape:collect="always">
<stop
id="stop4732"
offset="0"
style="stop-color:#3d3d3e;stop-opacity:1;" />
<stop
id="stop4734"
offset="1"
style="stop-color:#3d3d3e;stop-opacity:0;" />
</linearGradient>
<linearGradient
gradientTransform="matrix(1.0439827,0,0,1.0439827,-0.33554965,-0.28661264)"
gradientUnits="userSpaceOnUse"
y2="-100.05997"
x2="-124.15217"
y1="13.064024"
x1="13.593119"
id="linearGradient4736"
xlink:href="#linearGradient4730"
inkscape:collect="always" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="26.952219"
x2="46.513737"
y1="3.2154982"
x1="6.4024119"
id="linearGradient4780"
xlink:href="#linearGradient4772"
inkscape:collect="always" />
<linearGradient
gradientTransform="matrix(0.7582309,0.17089402,-0.17089402,0.7582309,3.6731782,16.025256)"
y2="26.952219"
x2="46.513737"
y1="3.2154982"
x1="6.4024119"
gradientUnits="userSpaceOnUse"
id="linearGradient4826"
xlink:href="#linearGradient4772"
inkscape:collect="always" />
</defs>
<metadata
id="metadata4146">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
ry="2.055341"
y="1.181488"
x="0.93680429"
height="13.637024"
width="14.126391"
id="rect4700"
style="opacity:1;fill:url(#linearGradient4736);fill-opacity:1;stroke:none;stroke-width:62.59950638;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4738"
d="m 13.858968,7.2410286 c 0.923129,1.5171458 -0.809369,0.042891 -1.540816,1.3316276 -0.980653,1.7278148 2.098544,1.3308325 -0.302351,2.5199508 C 9.0597011,12.556709 11.153629,10.383417 7.8692271,10.358548 4.5984606,10.333783 6.4471116,12.533426 3.6678994,11.025787 1.4254964,9.8093494 4.4235492,10.248531 3.6341638,8.5169358 3.0465331,7.2279098 1.1881231,8.669562 2.2540087,7.1764557 3.0486014,6.0633786 3.1026251,7.1356548 4.7654177,6.1688201 6.0957901,5.3952705 4.079129,5.5396116 5.9214856,5.1486519 c 1.6502939,-0.350203 0.3038643,0.2183737 2.2102407,0.226777 1.9110007,0.00842 0.619542,-0.5722369 2.2379197,-0.2078126 1.814684,0.4086285 -0.202138,0.2456624 1.054453,1.0339594 1.576394,0.9889173 1.748209,-0.08906 2.434869,1.0394529 0,0 0,0 0,0 M 10.229006,7.208623 C 10.098503,6.6073751 9.138078,6.177246 8.0683525,6.1771923 6.9986232,6.177246 6.0096606,6.6073751 5.8392676,7.2086231 c -0.1971591,0.6966797 0.751854,1.3481626 2.1501436,1.3482548 1.398296,-9.22e-5 2.3905318,-0.6515752 2.2395948,-1.3482548 0,0 0,-10e-8 0,-10e-8"
clip-path="none"
style="opacity:1;fill:url(#linearGradient4826);fill-opacity:1;stroke:none;stroke-width:43.05149841;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

View file

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/home/joey/Projects/Web2Executable/files/images/download_settings.png"
sodipodi:docname="download_settings.svg"
inkscape:version="0.91+devel r"
version="1.1"
id="SVGRoot"
viewBox="0 0 16 16"
height="16px"
width="16px">
<sodipodi:namedview
inkscape:grid-bbox="true"
inkscape:window-maximized="1"
inkscape:window-y="24"
inkscape:window-x="65"
inkscape:window-height="1056"
inkscape:window-width="1855"
showgrid="false"
inkscape:current-layer="layer1"
inkscape:document-units="px"
inkscape:cy="10.750147"
inkscape:cx="2.0955227"
inkscape:zoom="22.627418"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<defs
id="defs4143">
<linearGradient
inkscape:collect="always"
id="linearGradient4155">
<stop
style="stop-color:#4a89dc;stop-opacity:1;"
offset="0"
id="stop4157" />
<stop
style="stop-color:#5d9cec;stop-opacity:1"
offset="1"
id="stop4159" />
</linearGradient>
<linearGradient
id="linearGradient4772"
inkscape:collect="always">
<stop
id="stop4774"
offset="0"
style="stop-color:#d3d3d3;stop-opacity:1;" />
<stop
id="stop4776"
offset="1"
style="stop-color:#d3d3d3;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient4730"
inkscape:collect="always">
<stop
id="stop4732"
offset="0"
style="stop-color:#3d3d3e;stop-opacity:1;" />
<stop
id="stop4734"
offset="1"
style="stop-color:#3d3d3e;stop-opacity:0;" />
</linearGradient>
<linearGradient
gradientTransform="matrix(1.0439827,0,0,1.0439827,-0.33554965,-0.28661264)"
gradientUnits="userSpaceOnUse"
y2="-100.05997"
x2="-124.15217"
y1="13.064024"
x1="13.593119"
id="linearGradient4736"
xlink:href="#linearGradient4730"
inkscape:collect="always" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="26.952219"
x2="46.513737"
y1="3.2154982"
x1="6.4024119"
id="linearGradient4780"
xlink:href="#linearGradient4772"
inkscape:collect="always" />
<linearGradient
gradientTransform="matrix(0.7582309,0.17089402,-0.17089402,0.7582309,3.5847899,16.799843)"
y2="26.952219"
x2="46.513737"
y1="3.2154982"
x1="6.4024119"
gradientUnits="userSpaceOnUse"
id="linearGradient4826"
xlink:href="#linearGradient4772"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4155"
id="linearGradient4161"
x1="13.189182"
y1="14.049465"
x2="3.2565863"
y2="1.3619654"
gradientUnits="userSpaceOnUse" />
</defs>
<metadata
id="metadata4146">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
ry="2.055341"
y="1.181488"
x="0.93680429"
height="13.637024"
width="14.126391"
id="rect4700"
style="opacity:1;fill:url(#linearGradient4736);fill-opacity:1;stroke:none;stroke-width:62.59950638;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path4738"
d="m 13.77058,8.0156159 c 0.923129,1.5171455 -0.809369,0.042891 -1.540816,1.3316275 -0.980653,1.7278146 2.098544,1.3308326 -0.302351,2.5199506 C 8.9713128,13.331296 11.065241,11.158004 7.7808388,11.133135 4.5100723,11.10837 6.3587233,13.308013 3.5795111,11.800374 1.3371081,10.583936 4.3351609,11.023118 3.5457755,9.2915231 2.9581448,8.0024971 1.0997348,9.4441494 2.1656204,7.951043 2.9602131,6.8379659 3.0142368,7.9102421 4.6770294,6.9434074 6.0074018,6.1698578 3.9907407,6.3141989 5.8330973,5.9232392 c 1.6502939,-0.350203 0.3038643,0.2183737 2.2102407,0.226777 1.9110007,0.00842 0.619542,-0.5722369 2.23792,-0.2078126 1.814684,0.4086285 -0.202138,0.2456624 1.054453,1.0339594 1.576394,0.9889173 1.748209,-0.08906 2.434869,1.0394529 0,0 0,0 0,0 M 10.140618,7.9832103 C 10.010115,7.3819624 9.0496897,6.9518333 7.9799642,6.9517796 6.9102349,6.9518333 5.9212723,7.3819624 5.7508793,7.9832104 5.5537202,8.6798901 6.5027333,9.331373 7.9010229,9.3314652 9.2993189,9.331373 10.291555,8.67989 10.140618,7.9832104 c 0,0 0,-1e-7 0,-1e-7"
clip-path="none"
style="opacity:1;fill:url(#linearGradient4826);fill-opacity:1;stroke:none;stroke-width:43.05149841;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient4161);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.01137726px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 9.1814569,2.2041468 C 8.1196871,2.9367735 7.2499098,2.8659711 6.1660764,9.6370096 l -2.3683598,0 3.8100016,4.4702294 4.1971408,-4.4702294 -2.2596157,0 C 9.5270521,8.6213252 9.649399,4.2097051 11.194086,1.8198522 c 0,0 -0.946091,-0.093675 -2.0126291,0.3842946 z"
id="path4138"
inkscape:export-xdpi="10.238106"
inkscape:export-ydpi="10.238106"
sodipodi:nodetypes="cccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 748 B

View file

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
id="SVGRoot"
version="1.1"
inkscape:version="0.91+devel r"
sodipodi:docname="export_settings.svg"
inkscape:export-filename="/home/joey/Projects/Web2Executable/files/images/export_settings.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8"
inkscape:cx="-2.4708373"
inkscape:cy="8.933887"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1855"
inkscape:window-height="1056"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:grid-bbox="true" />
<defs
id="defs4143">
<linearGradient
inkscape:collect="always"
id="linearGradient4886">
<stop
style="stop-color:#37b39b;stop-opacity:1"
offset="0"
id="stop4888" />
<stop
style="stop-color:#48cfad;stop-opacity:1"
offset="1"
id="stop4890" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4772">
<stop
style="stop-color:#d3d3d3;stop-opacity:1;"
offset="0"
id="stop4774" />
<stop
style="stop-color:#d3d3d3;stop-opacity:0;"
offset="1"
id="stop4776" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4730">
<stop
style="stop-color:#3d3d3e;stop-opacity:1;"
offset="0"
id="stop4732" />
<stop
style="stop-color:#3d3d3e;stop-opacity:0;"
offset="1"
id="stop4734" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4730"
id="linearGradient4736"
x1="13.593119"
y1="13.064024"
x2="-124.15217"
y2="-100.05997"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0439827,0,0,1.0439827,-0.33554965,-0.28661264)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4772"
id="linearGradient4780"
x1="6.4024119"
y1="3.2154982"
x2="46.513737"
y2="26.952219"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4772"
id="linearGradient4826"
gradientUnits="userSpaceOnUse"
x1="6.4024119"
y1="3.2154982"
x2="46.513737"
y2="26.952219"
gradientTransform="matrix(0.94762762,0.21358123,-0.21358123,0.94762762,2.5055978,-1.2401189)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4886"
id="linearGradient4894"
gradientUnits="userSpaceOnUse"
x1="10.783379"
y1="10.696699"
x2="-0.57452416"
y2="-2.1638048"
gradientTransform="matrix(1.0841182,0,0,1.0841182,-0.9286483,-0.27436275)" />
</defs>
<metadata
id="metadata4146">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<rect
style="opacity:1;fill:url(#linearGradient4736);fill-opacity:1;stroke:none;stroke-width:62.59950638;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4700"
width="14.126391"
height="13.637024"
x="0.93680429"
y="1.181488"
ry="2.055341" />
<path
style="opacity:1;fill:url(#linearGradient4826);fill-opacity:1;stroke:none;stroke-width:53.80522919;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
clip-path="none"
d="M 7.9398486,2.1449285 C 5.5056259,2.1703938 7.8595712,2.981495 5.7642049,4.2206599 3.6688388,5.4598248 4.0944274,3.0051573 2.8993696,5.1259886 1.7043117,7.24682 3.5834863,5.611655 3.6089516,8.0458778 3.6344164,10.480101 1.7213755,8.886713 2.9605405,10.982079 c 1.2391648,2.095366 0.7623552,-0.350899 2.8831866,0.844158 2.1208313,1.195059 -0.2157595,2.054299 2.2184632,2.028833 2.4342227,-0.02546 0.078238,-0.834526 2.1736047,-2.073692 2.095366,-1.239164 1.669777,1.215503 2.864835,-0.905328 C 14.295688,8.7552183 12.416513,10.388344 12.391048,7.9541215 12.365583,5.5198987 14.278624,7.1153253 13.03946,5.0199591 11.800294,2.9245929 12.277104,5.3708591 10.156273,4.1758012 8.0354415,2.9807433 10.374072,2.1194634 7.9398486,2.1449285 Z m 0.061171,3.6417054 A 2.2146216,2.2146216 0 0 1 10.215405,8.0010191 2.2146216,2.2146216 0 0 1 8.0010195,10.215404 2.2146216,2.2146216 0 0 1 5.7866343,8.0010191 2.2146216,2.2146216 0 0 1 8.0010195,5.7866339 Z"
id="path4738"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient4894);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.01325854px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 10.842376,1.5529067 -3.9731557,4.1877913 1.7972428,0 c 0.00322,1.3669134 -0.3877342,7.24255 -7.3094525,7.874669 0,0 10.4402554,3.350629 11.6434674,-7.874669 l 1.743314,0 -3.901416,-4.1877913 z"
id="path4138-0"
inkscape:export-xdpi="10.238106"
inkscape:export-ydpi="10.238106" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
files/images/warning.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

84
files/images/warning.svg Normal file
View file

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
id="SVGRoot"
version="1.1"
inkscape:version="0.91+devel r"
sodipodi:docname="warning.svg"
inkscape:export-filename="/home/joey/Projects/Web2Executable/files/images/warning.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="16"
inkscape:cx="-15.835665"
inkscape:cy="6.3038239"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1855"
inkscape:window-height="1056"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:grid-bbox="true" />
<defs
id="defs4183" />
<metadata
id="metadata4186">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<g
id="g4217"
transform="translate(-0.00532229,-0.01899142)">
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path3336"
d="m 8.1447354,2.7412884 5.6732056,10.5552146 -11.6252444,0 z"
style="fill:#d03436;fill-opacity:1;fill-rule:evenodd;stroke:#d03436;stroke-width:3.5687921;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
r="0.94282585"
cy="12.731531"
cx="8.1741886"
id="path4147"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.0342989;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
ry="1.028775"
y="3.4383595"
x="7.2482905"
height="7.5717845"
width="1.8517954"
id="rect4168"
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.12858665;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

View file

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
id="SVGRoot"
version="1.1"
inkscape:version="0.91+devel r"
sodipodi:docname="window_settings.svg"
inkscape:export-filename="/home/joey/Projects/Web2Executable/files/images/window_settings.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8"
inkscape:cx="-42.943793"
inkscape:cy="12.800391"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1855"
inkscape:window-height="1056"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:grid-bbox="true" />
<defs
id="defs4143">
<linearGradient
inkscape:collect="always"
id="linearGradient4772">
<stop
style="stop-color:#d3d3d3;stop-opacity:1;"
offset="0"
id="stop4774" />
<stop
style="stop-color:#d3d3d3;stop-opacity:0;"
offset="1"
id="stop4776" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4730">
<stop
style="stop-color:#3d3d3e;stop-opacity:1;"
offset="0"
id="stop4732" />
<stop
style="stop-color:#3d3d3e;stop-opacity:0;"
offset="1"
id="stop4734" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4730"
id="linearGradient4736"
x1="13.593119"
y1="13.064024"
x2="-124.15217"
y2="-100.05997"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0439827,0,0,1.0439827,-0.33554965,-0.28661264)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4772"
id="linearGradient4780"
x1="6.4024119"
y1="3.2154982"
x2="46.513737"
y2="26.952219"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4772"
id="linearGradient4826"
gradientUnits="userSpaceOnUse"
x1="6.4024119"
y1="3.2154982"
x2="46.513737"
y2="26.952219"
gradientTransform="matrix(0.72672638,0.16379336,-0.16379336,0.72672638,5.421581,2.5440104)" />
</defs>
<metadata
id="metadata4146">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<rect
style="opacity:1;fill:url(#linearGradient4736);fill-opacity:1;stroke:none;stroke-width:62.59950638;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4700"
width="14.126391"
height="13.637024"
x="0.93680429"
y="1.181488"
ry="2.055341" />
<path
style="opacity:1;fill:url(#linearGradient4826);fill-opacity:1;stroke:none;stroke-width:41.26270676;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
clip-path="none"
d="M 9.5890549,5.1399702 C 7.7222732,5.1594993 9.5274909,5.7815249 7.920575,6.7318284 6.3136591,7.6821319 6.6400389,5.7996713 5.7235607,7.4261161 4.8070825,9.0525611 6.2482031,7.798569 6.2677322,9.6653507 6.2872609,11.532133 4.8201685,10.310179 5.7704721,11.917095 c 0.9503034,1.606916 0.5846427,-0.269101 2.2110877,0.647376 1.6264448,0.916479 -0.1654639,1.575422 1.7013177,1.555893 1.8667815,-0.01953 0.06,-0.63999 1.6669165,-1.590295 1.606915,-0.950302 1.280535,0.932158 2.197013,-0.694287 C 14.463286,10.209337 13.022165,11.461765 13.002636,9.5949837 12.983107,7.728202 14.450199,8.9517191 13.499897,7.3448032 12.549593,5.7378873 12.915254,7.6139049 11.288809,6.6974267 9.6623642,5.7809484 11.455837,5.1204413 9.5890549,5.1399702 Z m 0.046911,2.7927884 A 1.6983717,1.6983717 0 0 1 11.334157,9.630949 1.6983717,1.6983717 0 0 1 9.6359663,11.329139 1.6983717,1.6983717 0 0 1 7.9377758,9.630949 1.6983717,1.6983717 0 0 1 9.6359663,7.9327586 Z"
id="path4738"
inkscape:connector-curvature="0" />
<circle
style="opacity:1;fill:#da4453;fill-opacity:1;stroke:none;stroke-width:77.15126038;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4855"
cx="3.1991758"
cy="3.1535499"
r="1.0519673" />
<circle
r="1.0519673"
cy="3.1535499"
cx="6.0991936"
id="circle4857"
style="opacity:1;fill:#f6bb42;fill-opacity:1;stroke:none;stroke-width:77.15126038;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<circle
style="opacity:1;fill:#8cc152;fill-opacity:1;stroke:none;stroke-width:77.15126038;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle4859"
cx="9.0296631"
cy="3.1535499"
r="1.0519673" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

@ -108,6 +108,11 @@ linux_64_dir_prefix = 'node-webkit-v{}-linux-x64'
default_value=False
type='check'
[[web2exe_settings]]
[[[export_dir]]]
default_value=''
type='string'
[[window_settings]]
[[[title]]]
default_value=''
@ -116,15 +121,18 @@ linux_64_dir_prefix = 'node-webkit-v{}-linux-x64'
display_name='Window Icon'
default_value=''
type='file'
action='set_window_icon'
file_types='*.png *.jpg *.jpeg'
[[[mac_icon]]]
default_value=''
type='file'
action='set_mac_icon'
file_types='*.png *.jpg *.jpeg *.icns'
description='This icon to be displayed for the Mac Application. Defaults to Window Icon'
[[[exe_icon]]]
default_value=''
type='file'
action='set_exe_icon'
file_types='*.png *.jpg *.jpeg'
description='This icon to be displayed for the windows exe of the app. Defaults to Window icon.'
[[[width]]]
@ -323,10 +331,12 @@ linux_64_dir_prefix = 'node-webkit-v{}-linux-x64'
[compression]
[[nw_compression_level]]
display_name='NW Compression'
default_value=5
display_name='Compression Level'
default_value=0
min=0
max=9
type='range'
description='Compression to be applied to the executable\'s node webkit binary. 0 is no compression, 9 is maximum. They all use lzma.'
description='Compression to be applied to the executable\'s nwjs binary. 0 is no compression, 9 is maximum. They all use lzma.'
[order]
@ -342,6 +352,7 @@ linux_64_dir_prefix = 'node-webkit-v{}-linux-x64'
'kiosk', 'kiosk_emulation', 'transparent']"""
export_setting_order = """['windows-x32', 'windows-x64', 'mac-x32', 'mac-x64', 'linux-x64', 'linux-x32']"""
compression_setting_order = """['nw_compression_level']"""
download_setting_order = """['nw_version', 'download_dir',
'force_download']"""

0
image_tool_build.bat Normal file → Executable file
View file

458
main.py
View file

@ -1,6 +1,6 @@
from utils import log, open_folder_in_explorer
__gui_version__ = "v0.2.0b"
__gui_version__ = "v0.2.1b"
import os
import re
@ -8,12 +8,14 @@ import glob
import sys
from PySide import QtGui, QtCore
from PySide.QtGui import QApplication
from PySide.QtGui import QApplication, QHBoxLayout, QVBoxLayout
from PySide.QtNetwork import QHttp
from PySide.QtCore import QUrl, QFile, QIODevice, QCoreApplication
from command_line import CWD, CommandBase, logger
from command_line import CommandBase, logger, get_file
MAX_RECENT = 10
class Validator(QtGui.QRegExpValidator):
@ -45,15 +47,104 @@ class BackgroundThread(QtCore.QThread):
func()
class MainWindow(QtGui.QWidget, CommandBase):
class MainWindow(QtGui.QMainWindow, CommandBase):
def update_nw_versions(self, button):
self.get_versions_in_background()
def load_recent_projects(self):
files = []
history_file = get_file('files/recent_files.txt')
with open(history_file, 'a+') as f:
for line in f:
line = line.strip()
if line and os.path.exists(line):
files.append(line)
files.reverse()
return files
def load_last_project_path(self):
proj_path = ''
proj_file = get_file('files/last_project_path.txt')
with open(proj_file, 'a+') as f:
proj_path = f.read().strip()
if not proj_path:
proj_path = QtCore.QDir.currentPath()
return proj_path
def save_project_path(self, path):
proj_file = get_file('files/last_project_path.txt')
with open(proj_file, 'w+') as f:
f.write(path)
def save_recent_project(self, proj):
recent_file_path = get_file('files/recent_files.txt')
max_length = MAX_RECENT
recent_files = open(recent_file_path, 'a+').read().split('\n')
try:
recent_files.remove(proj)
except ValueError:
pass
recent_files.append(proj)
with open(recent_file_path, 'w+') as f:
for recent_file in recent_files[-max_length:]:
if recent_file and os.path.exists(recent_file):
f.write(recent_file+'\n')
def update_recent_files(self):
previous_files = self.load_recent_projects()
self.recent_separator.setVisible(len(previous_files) > 0)
for i in xrange(len(previous_files)):
text = '{} - {}'.format(i+1, os.path.basename(previous_files[i]))
action = self.recent_file_actions[i]
action.setText(text)
action.setData(previous_files[i])
action.setVisible(True)
def __init__(self, width, height, app, parent=None):
super(MainWindow, self).__init__(parent)
CommandBase.__init__(self)
self.icon_style = 'width:48px;height:48px;background-color:white;border-radius:5px;border:1px solid rgb(50,50,50);'
self.last_project_dir = self.load_last_project_path()
status_bar = QtGui.QStatusBar()
self.setStatusBar(status_bar)
self.project_path = ''
self.project_menu = self.menuBar().addMenu('File')
browse_action = QtGui.QAction('Open Project', self.project_menu,
shortcut=QtGui.QKeySequence.Open,
statusTip='Open an existing or new project.',
triggered=self.browse_dir)
self.project_menu.addAction(browse_action)
self.project_menu.addSeparator()
self.recent_file_actions = []
for i in xrange(MAX_RECENT):
if i == 9:
key = 0
else:
key = i+1
action = QtGui.QAction(self, visible=False, triggered=self.open_recent_file,
shortcut=QtGui.QKeySequence('Ctrl+{}'.format(key)))
self.recent_file_actions.append(action)
self.project_menu.addAction(action)
self.recent_separator = self.project_menu.addSeparator()
self.update_recent_files()
exit_action = QtGui.QAction('Exit', self.project_menu)
exit_action.triggered.connect(QtGui.qApp.closeAllWindows)
self.project_menu.addAction(exit_action)
self.logger = logger
self.gui_app = app
@ -62,8 +153,7 @@ class MainWindow(QtGui.QWidget, CommandBase):
self.options_enabled = False
self.output_package_json = True
self.setWindowIcon(QtGui.QIcon(os.path.join(CWD, 'files',
'images', 'icon.png')))
self.setWindowIcon(QtGui.QIcon(get_file('files/images/icon.png')))
self.update_json = False
self.setup_nw_versions()
@ -82,10 +172,15 @@ class MainWindow(QtGui.QWidget, CommandBase):
self.setWindowTitle("Web2Executable {}".format(__gui_version__))
self.update_nw_versions(None)
def open_recent_file(self):
action = self.sender()
if action:
self.load_project(action.data())
def setup_nw_versions(self):
nw_version = self.get_setting('nw_version')
try:
f = open(os.path.join(CWD, 'files', 'nw-versions.txt'))
f = open(get_file('files/nw-versions.txt'))
for line in f:
nw_version.values.append(line.strip())
except IOError:
@ -93,28 +188,48 @@ class MainWindow(QtGui.QWidget, CommandBase):
def create_application_layout(self):
self.main_layout = QtGui.QVBoxLayout()
self.tab_widget = QtGui.QTabWidget()
self.main_layout.setContentsMargins(10, 5, 10, 5)
self.create_layout_widgets()
self.addWidgets_to_main_layout()
self.setLayout(self.main_layout)
w = QtGui.QWidget()
w.setLayout(self.main_layout)
self.setCentralWidget(w)
def create_layout_widgets(self):
self.download_bar_widget = self.create_download_bar()
self.app_settings_widget = self.create_application_settings()
self.comp_settings_widget = self.create_compression_settings()
self.win_settings_widget = self.create_window_settings()
self.ex_settings_widget = self.create_export_settings()
self.dl_settings_widget = self.create_download_settings()
self.directory_chooser_widget = self.create_directory_choose()
def addWidgets_to_main_layout(self):
self.warning_settings_icon = QtGui.QIcon(get_file('files/images/warning.png'))
self.app_settings_icon = QtGui.QIcon(get_file('files/images/app_settings.png'))
self.win_settings_icon = QtGui.QIcon(get_file('files/images/window_settings.png'))
self.ex_settings_icon = QtGui.QIcon(get_file('files/images/export_settings.png'))
self.comp_settings_icon = QtGui.QIcon(get_file('files/images/compress_settings.png'))
self.download_settings_icon = QtGui.QIcon(get_file('files/images/download_settings.png'))
self.tab_icons = [self.app_settings_icon,
self.win_settings_icon,
self.ex_settings_icon,
self.comp_settings_icon,
self.download_settings_icon]
self.main_layout.addWidget(self.directory_chooser_widget)
self.main_layout.addWidget(self.app_settings_widget)
self.main_layout.addWidget(self.win_settings_widget)
self.main_layout.addWidget(self.ex_settings_widget)
self.main_layout.addWidget(self.dl_settings_widget)
self.tab_widget.addTab(self.app_settings_widget, self.app_settings_icon, 'App Settings')
self.tab_widget.addTab(self.win_settings_widget, self.win_settings_icon, 'Window Settings')
self.tab_widget.addTab(self.ex_settings_widget, self.ex_settings_icon, 'Export Settings')
self.tab_widget.addTab(self.comp_settings_widget, self.comp_settings_icon, 'Compression Settings')
self.tab_widget.addTab(self.dl_settings_widget, self.download_settings_icon, 'Download Settings')
self.main_layout.addWidget(self.tab_widget)
self.main_layout.addLayout(self.download_bar_widget)
def option_settings_enabled(self, is_enabled):
@ -122,6 +237,7 @@ class MainWindow(QtGui.QWidget, CommandBase):
self.app_settings_widget.setEnabled(is_enabled)
self.win_settings_widget.setEnabled(is_enabled)
self.ex_settings_widget.setEnabled(is_enabled)
self.comp_settings_widget.setEnabled(is_enabled)
self.dl_settings_widget.setEnabled(is_enabled)
self.options_enabled = is_enabled
@ -168,23 +284,22 @@ class MainWindow(QtGui.QWidget, CommandBase):
self.option_settings_enabled(True)
self.directory_chooser_widget.setEnabled(True)
def get_tab_index_for_setting_name(self, name):
options_dict = {'app_settings': 0,
'webkit_settings': 0,
'window_settings': 1,
'export_settings': 2,
'compression': 3,
'download_settings': 4}
for setting_group_name, setting_group in self._setting_items:
if name in setting_group:
return options_dict.get(setting_group_name, None)
def required_settings_filled(self, ignore_options=False):
if not self.options_enabled and not ignore_options:
return False
proj_dir = self.project_dir()
out_dir = self.output_dir()
valid_proj_dirs = False
if proj_dir and out_dir:
if os.path.exists(proj_dir):
valid_proj_dirs = True
self.input_line.setStyleSheet('')
self.input_line.setToolTip('')
else:
self.input_line.setStyleSheet('QLineEdit{border:3px solid rgba(238, 68, 83, 200); border-radius:5px;}')
self.input_line.setToolTip('The project directory does not exist.')
red_border = 'QLineEdit{border:3px solid rgba(238, 68, 83, 200); border-radius:5px;}'
settings_valid = True
for sgroup in self.settings['setting_groups']:
@ -196,8 +311,10 @@ class MainWindow(QtGui.QWidget, CommandBase):
settings_valid = False
widget = self.find_child_by_name(setting.name)
if widget is not None:
widget.setStyleSheet('QLineEdit{border:3px solid rgba(238, 68, 83, 200); border-radius:5px;}')
widget.setStyleSheet(red_border)
widget.setToolTip('This setting is required.')
tab = self.get_tab_index_for_setting_name(setting.name)
self.tab_widget.setTabIcon(tab, self.warning_settings_icon)
if (setting.type == 'file' and
setting.value and
@ -206,8 +323,10 @@ class MainWindow(QtGui.QWidget, CommandBase):
settings_valid = False
widget = self.find_child_by_name(setting.name)
if widget is not None:
widget.setStyleSheet('QLineEdit{border:3px solid rgba(238, 68, 83, 200); border-radius:5px;}')
widget.setStyleSheet(red_border)
widget.setToolTip('The file "{}" does not exist.'.format(os.path.join(self.project_dir(),setting.value)))
tab = self.get_tab_index_for_setting_name(setting.name)
self.tab_widget.setTabIcon(tab, self.warning_settings_icon)
if (setting.type == 'folder' and
setting.value and
@ -215,12 +334,17 @@ class MainWindow(QtGui.QWidget, CommandBase):
settings_valid = False
widget = self.find_child_by_name(setting.name)
if widget is not None:
widget.setStyleSheet('QLineEdit{border:3px solid rgba(238, 68, 83, 200); border-radius:5px;}')
widget.setStyleSheet(red_border)
widget.setToolTip('The folder "{}" does not exist'.format(os.path.join(self.project_dir(), setting.value)))
tab = self.get_tab_index_for_setting_name(setting.name)
self.tab_widget.setTabIcon(tab, self.warning_settings_icon)
if settings_valid:
widget = self.find_child_by_name(setting.name)
widget.setStyleSheet('')
widget.setToolTip('')
if widget is not None:
widget.setStyleSheet('')
widget.setToolTip('')
tab = self.get_tab_index_for_setting_name(setting.name)
self.tab_widget.setTabIcon(tab, self.tab_icons[tab])
export_chosen = False
for setting_name, setting in self.settings['export_settings'].items():
@ -233,21 +357,30 @@ class MainWindow(QtGui.QWidget, CommandBase):
if widget is not None:
widget.setStyleSheet('QCheckBox{border:3px solid rgba(238, 68, 83, 200); border-radius:5px;}')
widget.setToolTip('At least one of these options should be selected.')
tab = self.get_tab_index_for_setting_name(setting.name)
self.tab_widget.setTabIcon(tab, self.warning_settings_icon)
else:
widget = self.find_child_by_name(setting.name)
widget.setStyleSheet('')
widget.setToolTip('')
if widget is not None:
widget.setStyleSheet('')
widget.setToolTip('')
tab = self.get_tab_index_for_setting_name(setting.name)
self.tab_widget.setTabIcon(tab, self.tab_icons[tab])
return export_chosen and valid_proj_dirs and settings_valid
return export_chosen and settings_valid
def project_dir(self):
return self.project_path
if hasattr(self, 'input_line'):
return self.input_line.text()
return ''
def output_dir(self):
if hasattr(self, 'output_line'):
return self.output_line.text()
if os.path.isabs(self.output_line.text()):
return self.output_line.text()
else:
return os.path.join(self.project_dir(), self.output_line.text())
return ''
def create_download_bar(self):
@ -278,6 +411,7 @@ class MainWindow(QtGui.QWidget, CommandBase):
open_export_button.setEnabled(False)
open_export_button.setIcon(QtGui.QIcon(os.path.join('files', 'images', 'folder_open.png')))
open_export_button.setToolTip('Open Export Folder')
open_export_button.setStatusTip('Open Export Folder')
open_export_button.setMaximumWidth(30)
open_export_button.setMaximumHeight(30)
@ -481,45 +615,103 @@ class MainWindow(QtGui.QWidget, CommandBase):
# Download the file.
self.http_get_id = self.http.get(path, self.out_file)
def create_icon_box(self, name, text):
style = 'width:48px;height:48px;background-color:white;border-radius:5px;border:1px solid rgb(50,50,50);'
icon_label = QtGui.QLabel()
icon_label.setStyleSheet(style)
icon_label.setMaximumWidth(48)
icon_label.setMinimumWidth(48)
icon_label.setMaximumHeight(48)
icon_label.setMinimumHeight(48)
setattr(self, name, icon_label)
icon_text = QtGui.QLabel(text)
icon_text.setStyleSheet('font-size:10px;')
icon_text.setAlignment(QtCore.Qt.AlignCenter)
vbox = QVBoxLayout()
vbox.setAlignment(QtCore.Qt.AlignCenter)
vbox.addWidget(icon_label)
vbox.addWidget(icon_text)
vbox.setContentsMargins(0, 0, 0, 0)
w = QtGui.QWidget()
w.setLayout(vbox)
w.setMaximumWidth(70)
return w
def create_directory_choose(self):
group_box = QtGui.QGroupBox("Choose Your Web Project")
group_box = QtGui.QGroupBox('An awesome web project called:')
input_layout = QtGui.QHBoxLayout()
title_hbox = QHBoxLayout()
title_hbox.setContentsMargins(10, 10, 10, 10)
input_label = QtGui.QLabel('Project Directory:')
self.input_line = QtGui.QLineEdit()
self.input_line.textChanged.connect(self.project_path_changed)
input_button = QtGui.QPushButton('...')
input_button.clicked.connect(self.browse_dir)
win_icon = self.create_icon_box('window_icon', 'Window Icon')
exe_icon = self.create_icon_box('exe_icon', 'Exe Icon')
mac_icon = self.create_icon_box('mac_icon', 'Mac Icon')
input_layout.addWidget(input_label)
input_layout.addWidget(self.input_line)
input_layout.addWidget(input_button)
output_layout = QtGui.QHBoxLayout()
output_label = QtGui.QLabel('Output Directory:')
self.output_line = QtGui.QLineEdit()
self.output_line.textChanged.connect(self.project_path_changed)
output_button = QtGui.QPushButton('...')
output_button.clicked.connect(self.browse_out_dir)
output_layout.addWidget(output_label)
output_layout.addWidget(self.output_line)
output_layout.addWidget(output_button)
self.title_label = QtGui.QLabel('TBD')
self.title_label.setStyleSheet('font-size:20px; font-weight:bold;')
title_hbox.addWidget(self.title_label)
title_hbox.addWidget(QtGui.QLabel())
title_hbox.addWidget(win_icon)
title_hbox.addWidget(exe_icon)
title_hbox.addWidget(mac_icon)
vlayout = QtGui.QVBoxLayout()
vlayout.setSpacing(5)
vlayout.setContentsMargins(10, 5, 10, 5)
vlayout.addLayout(input_layout)
vlayout.addLayout(output_layout)
vlayout.addLayout(title_hbox)
#vlayout.addLayout(input_layout)
#vlayout.addLayout(output_layout)
group_box.setLayout(vlayout)
return group_box
def set_window_icon(self):
icon_setting = self.get_setting('icon')
mac_icon_setting = self.get_setting('mac_icon')
exe_icon_setting = self.get_setting('exe_icon')
self.set_icon(icon_setting.value, self.window_icon)
if not mac_icon_setting.value:
self.set_icon(icon_setting.value, self.mac_icon)
if not exe_icon_setting.value:
self.set_icon(icon_setting.value, self.exe_icon)
def set_exe_icon(self):
icon_setting = self.get_setting('exe_icon')
self.set_icon(icon_setting.value, self.exe_icon)
def set_mac_icon(self):
icon_setting = self.get_setting('mac_icon')
self.set_icon(icon_setting.value, self.mac_icon)
def set_icon(self, icon_path, icon):
if icon_path:
icon_path = os.path.join(self.project_dir(), icon_path)
if os.path.exists(icon_path):
if icon_path.endswith('.icns'):
#image = QtGui.QImage.fromData(make_thumbnail(icon_path,48), 'png')
return
image = QtGui.QImage(icon_path)
if image.width() >= image.height():
image = image.scaledToWidth(48,
QtCore.Qt.SmoothTransformation)
else:
image = image.scaledToHeight(48,
QtCore.Qt.SmoothTransformation)
icon.setPixmap(QtGui.QPixmap.fromImage(image))
icon.setStyleSheet('')
else:
icon.setPixmap(None)
icon.setStyleSheet(self.icon_style)
else:
icon.setStyleSheet(self.icon_style)
def call_with_object(self, name, obj, *args, **kwargs):
"""Allows arguments to be passed to click events"""
def call(*cargs, **ckwargs):
@ -544,51 +736,67 @@ class MainWindow(QtGui.QWidget, CommandBase):
return self.find_child_by_name('app_name').text()
def browse_dir(self):
self.update_json = False
directory = QtGui.QFileDialog.getExistingDirectory(self, "Find Project Directory",
self.project_dir() or QtCore.QDir.currentPath())
directory = QtGui.QFileDialog.getExistingDirectory(self, 'Find Project Directory',
self.project_dir() or self.last_project_dir)
if directory:
self.reset_settings()
self.input_line.setText(directory)
self.output_line.setText(os.path.join(directory, 'output'))
self.load_project(directory)
proj_name = os.path.basename(directory)
def load_project(self, directory):
self.update_json = False
self.project_path = directory
self.save_recent_project(directory)
self.save_project_path(directory)
self.update_recent_files()
self.reset_settings()
#self.input_line.setText(directory)
setting_input = self.find_child_by_name('main')
files = (glob.glob(os.path.join(directory, 'index.html')) +
glob.glob(os.path.join(directory, 'index.php')) +
glob.glob(os.path.join(directory, 'index.htm')))
if not setting_input.text():
if files:
setting_input.setText(files[0].replace(self.project_dir() + os.path.sep, ''))
app_name_input = self.find_child_by_name('app_name')
name_input = self.find_child_by_name('name')
name_setting = self.get_setting('name')
title_input = self.find_child_by_name('title')
proj_name = os.path.basename(directory)
self.title_label.setText(proj_name)
if not name_input.text():
name_input.setText(name_setting.filter_name(proj_name))
setting_input = self.find_child_by_name('main')
files = (glob.glob(os.path.join(directory, 'index.html')) +
glob.glob(os.path.join(directory, 'index.php')) +
glob.glob(os.path.join(directory, 'index.htm')))
if not setting_input.text():
if files:
setting_input.setText(files[0].replace(self.project_dir() + os.path.sep, ''))
if not app_name_input.text():
app_name_input.setText(proj_name)
app_name_input = self.find_child_by_name('app_name')
name_input = self.find_child_by_name('name')
name_setting = self.get_setting('name')
title_input = self.find_child_by_name('title')
if not title_input.text():
title_input.setText(proj_name)
if not name_input.text():
name_input.setText(name_setting.filter_name(proj_name))
self.load_package_json()
self.open_export_button.setEnabled(True)
self.update_json = True
if not app_name_input.text():
app_name_input.setText(proj_name)
if not title_input.text():
title_input.setText(proj_name)
self.load_package_json()
default_dir = 'output'
export_dir_setting = self.get_setting('export_dir')
default_dir = export_dir_setting.value or default_dir
self.output_line.setText(default_dir)
self.set_window_icon()
self.open_export_button.setEnabled(True)
self.update_json = True
def browse_out_dir(self):
self.update_json = False
directory = QtGui.QFileDialog.getExistingDirectory(self, "Choose Output Directory",
(self.output_line.text() or
self.project_dir() or
QtCore.QDir.currentPath()))
self.last_project_dir))
if directory:
self.output_line.setText(directory)
self.update_json = True
self.output_line.setText(directory)
def get_file(self, obj, text_obj, setting, *args, **kwargs):
file_path, _ = QtGui.QFileDialog.getOpenFileName(self, 'Choose File',
@ -612,12 +820,22 @@ class MainWindow(QtGui.QWidget, CommandBase):
setting.last_value = folder
def create_application_settings(self):
group_box = QtGui.QGroupBox("Application Settings")
vlayout = self.create_layout(self.settings['order']['application_setting_order'], cols=4)
group_box = QtGui.QWidget()
vlayout = self.create_layout(self.settings['order']['application_setting_order'], cols=3)
group_box.setLayout(vlayout)
return group_box
def create_compression_settings(self):
group_box = QtGui.QWidget()
vlayout = self.create_layout(self.settings['order']['compression_setting_order'], cols=3)
warning_label = QtGui.QLabel('Note: When using compression (greater than 0) it will decrease the executable size,\nbut will increase the startup time when running it.')
vbox = QtGui.QVBoxLayout()
vbox.addLayout(vlayout)
vbox.addWidget(warning_label)
group_box.setLayout(vbox)
return group_box
def create_setting(self, name):
setting = self.get_setting(name)
if setting.type == 'string':
@ -634,30 +852,50 @@ class MainWindow(QtGui.QWidget, CommandBase):
return self.create_range_setting(name)
def create_window_settings(self):
group_box = QtGui.QGroupBox("Window Settings")
vlayout = self.create_layout(self.settings['order']['window_setting_order'], cols=4)
group_box = QtGui.QWidget()
vlayout = self.create_layout(self.settings['order']['window_setting_order'], cols=3)
group_box.setLayout(vlayout)
return group_box
def create_export_settings(self):
group_box = QtGui.QGroupBox("Export Settings")
group_box = QtGui.QWidget()
vlayout = self.create_layout(self.settings['order']['export_setting_order'], cols=4)
group_box.setLayout(vlayout)
output_layout = QtGui.QHBoxLayout()
output_label = QtGui.QLabel('Output Directory:')
self.output_line = QtGui.QLineEdit()
self.output_line.textChanged.connect(self.call_with_object('setting_changed',
self.output_line, self.get_setting('export_dir')))
self.output_line.textChanged.connect(self.project_path_changed)
self.output_line.setStatusTip('The output directory relative to the project directory.')
output_button = QtGui.QPushButton('...')
output_button.clicked.connect(self.browse_out_dir)
output_layout.addWidget(output_label)
output_layout.addWidget(self.output_line)
output_layout.addWidget(output_button)
vbox = QtGui.QVBoxLayout()
vbox.addLayout(vlayout)
vbox.addLayout(output_layout)
group_box.setLayout(vbox)
return group_box
def create_download_settings(self):
group_box = QtGui.QGroupBox("Download Settings")
vlayout = self.create_layout(self.settings['order']['download_setting_order'], 2)
group_box = QtGui.QWidget()
vlayout = self.create_layout(self.settings['order']['download_setting_order'], cols=1)
group_box.setLayout(vlayout)
return group_box
def create_layout(self, settings, cols=3):
glayout = QtGui.QGridLayout()
glayout.setContentsMargins(10, 5, 10, 5)
glayout.setContentsMargins(10, 15, 10, 5)
glayout.setAlignment(QtCore.Qt.AlignTop)
glayout.setSpacing(10)
glayout.setHorizontalSpacing(20)
col = 0
row = 0
@ -671,6 +909,7 @@ class MainWindow(QtGui.QWidget, CommandBase):
display_name += '*'
setting_label = QtGui.QLabel(display_name)
setting_label.setToolTip(setting.description)
setting_label.setStatusTip(setting.description)
glayout.addWidget(setting_label, row, col)
glayout.addLayout(self.create_setting(setting_name),
row, col+1)
@ -691,6 +930,8 @@ class MainWindow(QtGui.QWidget, CommandBase):
text, setting))
if setting.value:
text.setText(str(setting.value))
text.setStatusTip(setting.description)
text.setToolTip(setting.description)
hlayout.addWidget(text)
@ -713,6 +954,8 @@ class MainWindow(QtGui.QWidget, CommandBase):
if setting.value:
text.setText(str(setting.value))
text.setStatusTip(setting.description)
text.setToolTip(setting.description)
text.textChanged.connect(self.call_with_object('setting_changed',
text, setting))
@ -739,6 +982,8 @@ class MainWindow(QtGui.QWidget, CommandBase):
if setting.value:
text.setText(str(setting.value))
text.setStatusTip(setting.description)
text.setToolTip(setting.description)
text.textChanged.connect(self.call_with_object('setting_changed',
text, setting))
@ -752,6 +997,8 @@ class MainWindow(QtGui.QWidget, CommandBase):
for sgroup in self.settings['setting_groups']:
for setting in sgroup.values():
widget = self.find_child_by_name(setting.name)
if widget is None:
continue
if (setting.type == 'string' or
setting.type == 'file' or
@ -813,7 +1060,7 @@ class MainWindow(QtGui.QWidget, CommandBase):
if (setting.type == 'string' or
setting.type == 'file' or
setting.type == 'folder'):
setting.value = obj.text()
setting.value = args[0]
elif setting.type == 'check':
setting.value = obj.isChecked()
check_action = setting.check_action
@ -824,6 +1071,11 @@ class MainWindow(QtGui.QWidget, CommandBase):
elif setting.type == 'range':
setting.value = obj.value()
if setting.action is not None:
action = getattr(self, setting.action, None)
if callable(action):
action()
if self.update_json:
json_file = os.path.join(self.project_dir(), 'package.json')
@ -854,6 +1106,8 @@ class MainWindow(QtGui.QWidget, CommandBase):
check.clicked.connect(self.call_with_object('setting_changed',
check, setting))
check.setChecked(setting.value)
check.setStatusTip(setting.description)
check.setToolTip(setting.description)
hlayout.addWidget(check)
@ -877,6 +1131,9 @@ class MainWindow(QtGui.QWidget, CommandBase):
combo.editTextChanged.connect(self.call_with_object('setting_changed',
combo, setting))
combo.setStatusTip(setting.description)
combo.setToolTip(setting.description)
for val in setting.values:
combo.addItem(val)
@ -884,6 +1141,7 @@ class MainWindow(QtGui.QWidget, CommandBase):
if default_index != -1:
combo.setCurrentIndex(default_index)
hlayout.addWidget(QtGui.QLabel())
hlayout.addWidget(combo)
if button:
hlayout.addWidget(button)
@ -901,12 +1159,14 @@ class MainWindow(QtGui.QWidget, CommandBase):
button.clicked.connect(lambda: setting.button_callback(button))
slider = QtGui.QSlider(QtCore.Qt.Orientation.Horizontal)
slider.setRange(0, 9)
slider.setRange(setting.min, setting.max)
slider.valueChanged.connect(self.call_with_object('setting_changed',
slider, setting))
slider.setObjectName(setting.name)
slider.setValue(setting.default_value)
slider.setStatusTip(setting.description)
slider.setToolTip(setting.description)
range_label = QtGui.QLabel(str(setting.default_value))
range_label.setMaximumWidth(30)
@ -961,7 +1221,7 @@ if __name__ == '__main__':
QCoreApplication.setOrganizationName("SimplyPixelated")
QCoreApplication.setOrganizationDomain("simplypixelated.com")
frame = MainWindow(1000, 500, app)
frame = MainWindow(800, 500, app)
frame.show_and_raise()
sys.exit(app.exec_())