Add a "views" toolbar to the main GUI (#1057)

This commit is contained in:
Veronica Berglyd Olsen
2022-05-14 19:12:02 +02:00
committed by GitHub
19 changed files with 410 additions and 92 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ The following libraries are dependencies of novelWriter:
Some of the assets bundled with novelWriter were adapted from the following sources:
* Typicons icons by Stephen Hutchings (CC BY-SA 4.0)
* [Typicons](https://github.com/stephenhutchings/typicons.font) icons by Stephen Hutchings (CC BY-SA 4.0)
* Tomorrow syntax themes by Chris Kempson (MIT License)
* Owl syntax themes by Sarah Drasner (MIT License)
* Solarized themes by Ethan Schoonover, added by @nullbasis (MIT License)
@@ -49,10 +49,12 @@ hash = typ_hash.svg
maximise = typ_arrow-maximise.svg
minimise = typ_arrow-minimise.svg
proj_chapter = mixed_document-chapter.svg
proj_details = typ_th-list-grey.svg
proj_document = typ_document-text.svg
proj_folder = typ_folder.svg
proj_note = mixed_document-note.svg
proj_scene = mixed_document-scene.svg
proj_stats = typ_chart-bar-grey.svg
proj_title = mixed_document-title.svg
reference = typ_at.svg
refresh = typ_refresh.svg
@@ -76,3 +78,6 @@ status_time = typ_stopwatch-grey.svg
sticky-off = typ_pin-outline.svg
sticky-on = typ_pin.svg
up = typ_chevron-up.svg
view_editor = typ_edit.svg
view_novel = typ_book-grey.svg
view_outline = typ_puzzle-outline.svg
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
version="1.2"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg8707">
<metadata
id="metadata8713">
<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>
<defs
id="defs8711" />
<path
d="M 20,0 H 5.3333333 C 4.98,0 4.64,0.14 4.3906667,0.3906667 l -4,4 -0.076,0.082667 c -0.1853334,0.22 -0.3,0.4973334 -0.3133334,0.8 L 0,5.344 V 20 c 0,2.205333 1.7946667,4 4,4 h 12 c 1.738667,0 3.221333,-1.114667 3.772,-2.666667 h 0.894667 c 1.869333,0 3.333333,-1.756 3.333333,-4 V 4 C 24,1.7946667 22.205333,0 20,0 Z M 4,21.333333 C 3.2653333,21.333333 2.6666667,20.736 2.6666667,20 V 6.6666667 H 5.3333333 V 21.333333 Z M 17.333333,20 c 0,0.736 -0.598666,1.333333 -1.333333,1.333333 H 6.6666667 V 6.6666667 H 16 C 16.734667,6.6666667 17.333333,7.264 17.333333,8 Z m 4,-2.666667 c 0,0.826667 -0.432,1.333334 -0.666666,1.333334 H 20 V 8 C 20,5.7946667 18.205333,4 16,4 H 4.552 L 5.8853333,2.6666667 H 20 C 20.734667,2.6666667 21.333333,3.264 21.333333,4 Z"
id="path8705"
style="stroke-width:1.33333;fill:#aeaeae;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
version="1.2"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg7536">
<metadata
id="metadata7542">
<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>
<defs
id="defs7540" />
<path
d="M 23.445474,4.1911579 19.808842,0.5545263 C 19.438737,0.1844211 18.953684,0 18.468632,0 17.982316,0 17.498526,0.1844211 17.128421,0.5545263 L 12.631579,5.0526316 H 1.2631579 C 0.5658947,5.0526316 0,5.6172632 0,6.3157895 V 22.736842 C 0,23.435368 0.5658947,24 1.2631579,24 H 17.684211 c 0.697263,0 1.263157,-0.564632 1.263157,-1.263158 V 11.368421 L 23.445474,6.8703158 C 23.815579,6.5002105 24,6.0151579 24,5.5301053 24,5.0450526 23.815579,4.5612632 23.445474,4.1911579 Z M 10.736842,16.006737 7.993263,13.263158 15.942316,5.3141053 18.685895,8.057684 Z M 7.501895,14.315368 9.72,16.498105 7.578947,16.421053 Z m 8.919158,7.158316 H 2.5263158 V 7.5789474 H 10.105263 L 6.0884211,11.595789 C 5.7183158,11.965895 5.4846316,12.621474 5.2938947,13.224 5.0917895,13.855579 5.0526316,14.557895 5.0526316,15.080842 v 3.866526 H 8.919158 c 0.522947,0 1.399579,-0.126315 1.984421,-0.366315 0.586105,-0.24 1.131789,-0.438316 1.500632,-0.808421 l 4.016842,-3.877895 z m 3.157894,-14.3090524 -2.743579,-2.743579 1.633264,-1.6332631 2.742315,2.7435789 z"
id="path7534"
style="stroke-width:1.26316;fill:#aeaeae;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
version="1.2"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg11920">
<metadata
id="metadata11926">
<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>
<defs
id="defs11924" />
<path
d="M 22.461538,10.769231 V 8.615385 C 22.461538,6.24 20.52923,4.3076923 18.153846,4.3076923 H 17.219692 C 17.046153,1.8683077 14.816,0 12,0 9.1839995,0 6.9538461,1.8683077 6.7803077,4.3076923 H 5.8461538 C 3.4707692,4.3076923 1.5384615,6.24 1.5384615,8.615385 v 2.153846 c 0,1.245538 0.6326154,2.273231 1.5938462,2.764307 C 2.6916923,13.764923 2.3101538,14.110769 2.032,14.548923 1.7095384,15.058462 1.5384615,15.666462 1.5384615,16.307692 v 3.384616 C 1.5384615,22.067692 3.4707692,24 5.8461538,24 H 9.2307695 C 10.432,24 11.484308,23.388308 11.990154,22.401231 l 0.04431,0.08123 C 12.569847,23.432615 13.592616,24 14.76923,24 h 3.384616 c 2.375384,0 4.307692,-1.932308 4.307692,-4.307692 v -3.384616 c 0,-1.246769 -0.633845,-2.275692 -1.596308,-2.765538 0.955077,-0.505846 1.596308,-1.545846 1.596308,-2.772923 z m -2.461539,8.923077 c 0,1.015384 -0.830769,1.846154 -1.846153,1.846154 H 14.76923 c -0.438154,0 -0.891077,-0.265847 -0.481231,-0.94277 0.30277,-0.344615 0.481231,-0.761846 0.481231,-1.211077 0,-1.190153 -1.239384,-2.153846 -2.769231,-2.153846 -1.529846,0 -2.7692295,0.963693 -2.7692295,2.153846 0,0.369231 0.116923,0.708923 0.313846,1.012923 0.6239995,0.828308 0.167384,1.140924 -0.313846,1.140924 H 5.8461538 C 4.8307692,21.538462 4,20.707692 4,19.692308 v -3.384616 c 0,-0.317538 0.1390769,-0.64123 0.4726153,-0.64123 0.128,0 0.2818462,0.048 0.4701539,0.16 0.3446154,0.302769 0.7630769,0.48123 1.2110769,0.48123 1.1889231,0 2.1538462,-1.240615 2.1538462,-2.76923 0,-1.528616 -0.9649231,-2.769231 -2.1538462,-2.769231 -0.3692308,0 -0.7089231,0.116923 -1.0116923,0.313846 C 4.8504615,11.293538 4.6227692,11.382154 4.4504615,11.382154 4.1304615,11.382154 4,11.080615 4,10.769231 V 8.615385 C 4,7.6 4.8307692,6.7692308 5.8461538,6.7692308 h 3.3846157 c 0.48123,0 0.9378465,-0.3126154 0.299077,-1.1409231 -0.182154,-0.304 -0.299077,-0.6436923 -0.299077,-1.0129231 0,-1.1901538 1.2393835,-2.1538461 2.7692305,-2.1538461 1.529847,0 2.76923,0.9636923 2.76923,2.1538461 0,0.4492308 -0.17846,0.8664616 -0.48123,1.2110769 -0.409846,0.6769231 0.04308,0.9427693 0.48123,0.9427693 h 3.384616 C 19.16923,6.7692308 20,7.6 20,8.615385 v 2.153846 c 0,0.317538 -0.139076,0.641231 -0.472616,0.641231 -0.128,0 -0.281846,-0.048 -0.470154,-0.16 -0.344615,-0.30277 -0.763077,-0.481231 -1.211077,-0.481231 -1.188923,0 -2.153846,1.240615 -2.153846,2.769231 0,1.528615 0.964923,2.76923 2.153846,2.76923 0.369231,0 0.708923,-0.116923 1.011693,-0.313846 0.291693,-0.210461 0.519384,-0.300308 0.691692,-0.299077 0.318769,0 0.449232,0.301539 0.449232,0.612923 v 3.384616 z M 4,12.546462 c 0.1427692,0.03938 0.2904615,0.06646 0.4492307,0.06646 0.4209231,0 0.8406154,-0.146461 1.2775385,-0.448 l 0.084923,-0.05046 C 5.9310769,12.036923 6.0430769,12 6.1538461,12 c 0.4356923,0 0.9230769,0.658462 0.9230769,1.538462 0,0.88 -0.4873846,1.538461 -0.9230769,1.538461 -0.1329231,0 -0.2670769,-0.05908 -0.3987692,-0.174769 l -0.176,-0.128 C 5.2086153,14.548923 4.8356923,14.435692 4.4726153,14.435692 4.3076923,14.435692 4.1513846,14.464002 4,14.508312 Z M 19.550769,14.464 c -0.420922,0 -0.840616,0.146462 -1.277539,0.448 l -0.08492,0.05046 c -0.119384,0.07754 -0.231383,0.114461 -0.340923,0.114461 -0.435692,0 -0.923077,-0.658461 -0.923077,-1.538461 0,-0.88 0.487385,-1.538462 0.923077,-1.538462 0.132924,0 0.267077,0.05908 0.39877,0.174769 l 0.175999,0.128 c 0.371693,0.225231 0.743385,0.338462 1.106462,0.338462 0.167384,0 0.322461,-0.03077 0.472616,-0.07631 v 1.965539 c -0.144,-0.03938 -0.291693,-0.06646 -0.450462,-0.06646 z m -8.54523,7.074462 C 11.129847,21.112615 11.12,20.534154 10.630154,19.820308 l -0.05415,-0.09108 c -0.07631,-0.120616 -0.115692,-0.232616 -0.115692,-0.343385 0,-0.435692 0.657231,-0.923077 1.538462,-0.923077 0.88123,0 1.538461,0.487385 1.538461,0.923077 0,0.132923 -0.05908,0.267077 -0.176,0.4 l -0.128,0.174769 c -0.4,0.660923 -0.382769,1.204923 -0.270769,1.580308 h -1.956923 z"
id="path11918"
style="stroke-width:1.23077;fill:#aeaeae;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

@@ -49,10 +49,12 @@ hash = typ_hash.svg
maximise = typ_arrow-maximise.svg
minimise = typ_arrow-minimise.svg
proj_chapter = mixed_document-chapter.svg
proj_details = typ_th-list-grey.svg
proj_document = typ_document-text.svg
proj_folder = typ_folder.svg
proj_note = mixed_document-note.svg
proj_scene = mixed_document-scene.svg
proj_stats = typ_chart-bar-grey.svg
proj_title = mixed_document-title.svg
reference = typ_at.svg
refresh = typ_refresh.svg
@@ -76,3 +78,6 @@ status_time = typ_stopwatch-grey.svg
sticky-off = typ_pin-outline.svg
sticky-on = typ_pin.svg
up = typ_chevron-up.svg
view_editor = typ_edit.svg
view_novel = typ_book-grey.svg
view_outline = typ_puzzle-outline.svg
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
version="1.2"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg8707">
<metadata
id="metadata8713">
<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>
<defs
id="defs8711" />
<path
d="M 20,0 H 5.3333333 C 4.98,0 4.64,0.14 4.3906667,0.3906667 l -4,4 -0.076,0.082667 c -0.1853334,0.22 -0.3,0.4973334 -0.3133334,0.8 L 0,5.344 V 20 c 0,2.205333 1.7946667,4 4,4 h 12 c 1.738667,0 3.221333,-1.114667 3.772,-2.666667 h 0.894667 c 1.869333,0 3.333333,-1.756 3.333333,-4 V 4 C 24,1.7946667 22.205333,0 20,0 Z M 4,21.333333 C 3.2653333,21.333333 2.6666667,20.736 2.6666667,20 V 6.6666667 H 5.3333333 V 21.333333 Z M 17.333333,20 c 0,0.736 -0.598666,1.333333 -1.333333,1.333333 H 6.6666667 V 6.6666667 H 16 C 16.734667,6.6666667 17.333333,7.264 17.333333,8 Z m 4,-2.666667 c 0,0.826667 -0.432,1.333334 -0.666666,1.333334 H 20 V 8 C 20,5.7946667 18.205333,4 16,4 H 4.552 L 5.8853333,2.6666667 H 20 C 20.734667,2.6666667 21.333333,3.264 21.333333,4 Z"
id="path8705"
style="stroke-width:1.33333;fill:#000000;fill-opacity:0.72156864" />
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
version="1.2"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg7536">
<metadata
id="metadata7542">
<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>
<defs
id="defs7540" />
<path
d="M 23.445474,4.1911579 19.808842,0.5545263 C 19.438737,0.1844211 18.953684,0 18.468632,0 17.982316,0 17.498526,0.1844211 17.128421,0.5545263 L 12.631579,5.0526316 H 1.2631579 C 0.5658947,5.0526316 0,5.6172632 0,6.3157895 V 22.736842 C 0,23.435368 0.5658947,24 1.2631579,24 H 17.684211 c 0.697263,0 1.263157,-0.564632 1.263157,-1.263158 V 11.368421 L 23.445474,6.8703158 C 23.815579,6.5002105 24,6.0151579 24,5.5301053 24,5.0450526 23.815579,4.5612632 23.445474,4.1911579 Z M 10.736842,16.006737 7.993263,13.263158 15.942316,5.3141053 18.685895,8.057684 Z M 7.501895,14.315368 9.72,16.498105 7.578947,16.421053 Z m 8.919158,7.158316 H 2.5263158 V 7.5789474 H 10.105263 L 6.0884211,11.595789 C 5.7183158,11.965895 5.4846316,12.621474 5.2938947,13.224 5.0917895,13.855579 5.0526316,14.557895 5.0526316,15.080842 v 3.866526 H 8.919158 c 0.522947,0 1.399579,-0.126315 1.984421,-0.366315 0.586105,-0.24 1.131789,-0.438316 1.500632,-0.808421 l 4.016842,-3.877895 z m 3.157894,-14.3090524 -2.743579,-2.743579 1.633264,-1.6332631 2.742315,2.7435789 z"
id="path7534"
style="stroke-width:1.26316;fill:#000000;fill-opacity:0.72156864" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
version="1.2"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg11920">
<metadata
id="metadata11926">
<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>
<defs
id="defs11924" />
<path
d="M 22.461538,10.769231 V 8.615385 C 22.461538,6.24 20.52923,4.3076923 18.153846,4.3076923 H 17.219692 C 17.046153,1.8683077 14.816,0 12,0 9.1839995,0 6.9538461,1.8683077 6.7803077,4.3076923 H 5.8461538 C 3.4707692,4.3076923 1.5384615,6.24 1.5384615,8.615385 v 2.153846 c 0,1.245538 0.6326154,2.273231 1.5938462,2.764307 C 2.6916923,13.764923 2.3101538,14.110769 2.032,14.548923 1.7095384,15.058462 1.5384615,15.666462 1.5384615,16.307692 v 3.384616 C 1.5384615,22.067692 3.4707692,24 5.8461538,24 H 9.2307695 C 10.432,24 11.484308,23.388308 11.990154,22.401231 l 0.04431,0.08123 C 12.569847,23.432615 13.592616,24 14.76923,24 h 3.384616 c 2.375384,0 4.307692,-1.932308 4.307692,-4.307692 v -3.384616 c 0,-1.246769 -0.633845,-2.275692 -1.596308,-2.765538 0.955077,-0.505846 1.596308,-1.545846 1.596308,-2.772923 z m -2.461539,8.923077 c 0,1.015384 -0.830769,1.846154 -1.846153,1.846154 H 14.76923 c -0.438154,0 -0.891077,-0.265847 -0.481231,-0.94277 0.30277,-0.344615 0.481231,-0.761846 0.481231,-1.211077 0,-1.190153 -1.239384,-2.153846 -2.769231,-2.153846 -1.529846,0 -2.7692295,0.963693 -2.7692295,2.153846 0,0.369231 0.116923,0.708923 0.313846,1.012923 0.6239995,0.828308 0.167384,1.140924 -0.313846,1.140924 H 5.8461538 C 4.8307692,21.538462 4,20.707692 4,19.692308 v -3.384616 c 0,-0.317538 0.1390769,-0.64123 0.4726153,-0.64123 0.128,0 0.2818462,0.048 0.4701539,0.16 0.3446154,0.302769 0.7630769,0.48123 1.2110769,0.48123 1.1889231,0 2.1538462,-1.240615 2.1538462,-2.76923 0,-1.528616 -0.9649231,-2.769231 -2.1538462,-2.769231 -0.3692308,0 -0.7089231,0.116923 -1.0116923,0.313846 C 4.8504615,11.293538 4.6227692,11.382154 4.4504615,11.382154 4.1304615,11.382154 4,11.080615 4,10.769231 V 8.615385 C 4,7.6 4.8307692,6.7692308 5.8461538,6.7692308 h 3.3846157 c 0.48123,0 0.9378465,-0.3126154 0.299077,-1.1409231 -0.182154,-0.304 -0.299077,-0.6436923 -0.299077,-1.0129231 0,-1.1901538 1.2393835,-2.1538461 2.7692305,-2.1538461 1.529847,0 2.76923,0.9636923 2.76923,2.1538461 0,0.4492308 -0.17846,0.8664616 -0.48123,1.2110769 -0.409846,0.6769231 0.04308,0.9427693 0.48123,0.9427693 h 3.384616 C 19.16923,6.7692308 20,7.6 20,8.615385 v 2.153846 c 0,0.317538 -0.139076,0.641231 -0.472616,0.641231 -0.128,0 -0.281846,-0.048 -0.470154,-0.16 -0.344615,-0.30277 -0.763077,-0.481231 -1.211077,-0.481231 -1.188923,0 -2.153846,1.240615 -2.153846,2.769231 0,1.528615 0.964923,2.76923 2.153846,2.76923 0.369231,0 0.708923,-0.116923 1.011693,-0.313846 0.291693,-0.210461 0.519384,-0.300308 0.691692,-0.299077 0.318769,0 0.449232,0.301539 0.449232,0.612923 v 3.384616 z M 4,12.546462 c 0.1427692,0.03938 0.2904615,0.06646 0.4492307,0.06646 0.4209231,0 0.8406154,-0.146461 1.2775385,-0.448 l 0.084923,-0.05046 C 5.9310769,12.036923 6.0430769,12 6.1538461,12 c 0.4356923,0 0.9230769,0.658462 0.9230769,1.538462 0,0.88 -0.4873846,1.538461 -0.9230769,1.538461 -0.1329231,0 -0.2670769,-0.05908 -0.3987692,-0.174769 l -0.176,-0.128 C 5.2086153,14.548923 4.8356923,14.435692 4.4726153,14.435692 4.3076923,14.435692 4.1513846,14.464002 4,14.508312 Z M 19.550769,14.464 c -0.420922,0 -0.840616,0.146462 -1.277539,0.448 l -0.08492,0.05046 c -0.119384,0.07754 -0.231383,0.114461 -0.340923,0.114461 -0.435692,0 -0.923077,-0.658461 -0.923077,-1.538461 0,-0.88 0.487385,-1.538462 0.923077,-1.538462 0.132924,0 0.267077,0.05908 0.39877,0.174769 l 0.175999,0.128 c 0.371693,0.225231 0.743385,0.338462 1.106462,0.338462 0.167384,0 0.322461,-0.03077 0.472616,-0.07631 v 1.965539 c -0.144,-0.03938 -0.291693,-0.06646 -0.450462,-0.06646 z m -8.54523,7.074462 C 11.129847,21.112615 11.12,20.534154 10.630154,19.820308 l -0.05415,-0.09108 c -0.07631,-0.120616 -0.115692,-0.232616 -0.115692,-0.343385 0,-0.435692 0.657231,-0.923077 1.538462,-0.923077 0.88123,0 1.538461,0.487385 1.538461,0.923077 0,0.132923 -0.05908,0.267077 -0.176,0.4 l -0.128,0.174769 c -0.4,0.660923 -0.382769,1.204923 -0.270769,1.580308 h -1.956923 z"
id="path11918"
style="stroke-width:1.23077;fill:#000000;fill-opacity:0.72156864" />
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

+14
View File
@@ -130,6 +130,20 @@ class nwState(Enum):
# END Enum nwState
class nwView(Enum):
EDITOR = 0
PROJECT = 1
NOVEL = 2
OUTLINE = 3
DETAILS = 4
STATS = 5
SET_PROJ = 6
SET_MAIN = 7
# END Enum nwView
class nwWidget(Enum):
TREE = 1
+2
View File
@@ -29,6 +29,7 @@ from novelwriter.gui.outlinedetails import GuiOutlineDetails
from novelwriter.gui.projtree import GuiProjectTree
from novelwriter.gui.statusbar import GuiMainStatus
from novelwriter.gui.theme import GuiTheme
from novelwriter.gui.viewsbar import GuiViewsBar
__all__ = [
"GuiDocEditor",
@@ -42,4 +43,5 @@ __all__ = [
"GuiOutlineDetails",
"GuiProjectTree",
"GuiTheme",
"GuiViewsBar",
]
+1
View File
@@ -115,6 +115,7 @@ class GuiItemDetails(QWidget):
self.usageData = QLabel("")
self.usageData.setFont(fntValue)
self.usageData.setAlignment(Qt.AlignLeft)
self.usageData.setWordWrap(True)
# Character Count
self.cCountName = QLabel(" "+self.tr("Characters"))
+5 -1
View File
@@ -26,11 +26,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
import logging
import novelwriter
from PyQt5.QtCore import Qt, QT_TRANSLATE_NOOP
from PyQt5.QtCore import Qt, QT_TRANSLATE_NOOP, pyqtSignal
from PyQt5.QtWidgets import (
QScrollArea, QWidget, QGridLayout, QHBoxLayout, QGroupBox, QLabel
)
from novelwriter.enum import nwView
from novelwriter.common import checkInt
from novelwriter.constants import trConst, nwKeyWords, nwLabels
@@ -46,6 +47,8 @@ class GuiOutlineDetails(QScrollArea):
"H4": QT_TRANSLATE_NOOP("GuiOutlineDetails", "Section"),
}
viewChangeRequested = pyqtSignal(nwView)
def __init__(self, theParent):
QScrollArea.__init__(self, theParent)
@@ -329,6 +332,7 @@ class GuiOutlineDetails(QScrollArea):
if len(theLink) > 0:
theBits = theLink.split("=")
if len(theBits) == 2:
self.viewChangeRequested.emit(nwView.PROJECT)
self.theParent.docViewer.loadFromTag(theBits[1])
return
+10 -12
View File
@@ -456,20 +456,18 @@ class GuiIcons:
ICON_KEYS = {
# Project and GUI icons
"novelwriter", "proj_nwx",
"cls_none", "cls_novel", "cls_plot", "cls_character", "cls_world",
"cls_timeline", "cls_object", "cls_entity", "cls_custom", "cls_archive", "cls_trash",
"proj_document", "proj_title", "proj_chapter", "proj_scene", "proj_note", "proj_folder",
"status_lang", "status_time", "status_idle", "status_stats", "status_lines",
"doc_h0", "doc_h1", "doc_h2", "doc_h3", "doc_h4",
"search_case", "search_regex", "search_word", "search_loop", "search_project",
"search_cancel", "search_preserve",
"novelwriter", "cls_archive", "cls_character", "cls_custom", "cls_entity", "cls_none",
"cls_novel", "cls_object", "cls_plot", "cls_timeline", "cls_trash", "cls_world", "doc_h0",
"doc_h1", "doc_h2", "doc_h3", "doc_h4", "proj_chapter", "proj_details", "proj_document",
"proj_folder", "proj_note", "proj_nwx", "proj_scene", "proj_stats", "proj_title",
"search_cancel", "search_case", "search_loop", "search_preserve", "search_project",
"search_regex", "search_word", "status_idle", "status_lang", "status_lines",
"status_stats", "status_time", "view_editor", "view_novel", "view_outline",
# General Button Icons
"delete", "close", "done", "clear", "save", "add", "remove",
"search", "search_replace", "edit", "check", "cross", "hash",
"maximise", "minimise", "refresh", "reference", "backward",
"forward", "settings", "up", "down",
"add", "backward", "check", "clear", "close", "cross", "delete", "done", "down", "edit",
"forward", "hash", "maximise", "minimise", "reference", "refresh", "remove", "save",
"search_replace", "search", "settings", "up",
# Switches
"sticky-on", "sticky-off",
+103
View File
@@ -0,0 +1,103 @@
"""
novelWriter GUI Main Window Views ToolBar
===========================================
GUI class for the main window "Views" toolbar
File History:
Created: 2022-05-10 [1.7b1]
This file is a part of novelWriter
Copyright 20182022, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import logging
import novelwriter
from PyQt5.QtCore import Qt, QSize, pyqtSignal
from PyQt5.QtWidgets import QToolBar, QWidget, QSizePolicy, QAction
from novelwriter.enum import nwView
logger = logging.getLogger(__name__)
class GuiViewsBar(QToolBar):
viewChangeRequested = pyqtSignal(nwView)
def __init__(self, theParent):
QToolBar.__init__(self, theParent)
logger.debug("Initialising GuiViewsBar ...")
self.mainConf = novelwriter.CONFIG
self.theParent = theParent
self.theTheme = theParent.theTheme
# Style
iPx = self.mainConf.pxInt(22)
lblFont = self.theTheme.guiFont
lblFont.setPointSizeF(0.65*self.theTheme.fontPointSize)
self.setFont(lblFont)
self.setMovable(False)
self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
self.setIconSize(QSize(iPx, iPx))
self.setContentsMargins(0, 0, 0, 0)
stretch = QWidget(self)
stretch.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
# Actions
self.aProject = QAction(self.tr("Project"))
self.aProject.setIcon(self.theTheme.getIcon("view_editor"))
self.aProject.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.PROJECT))
self.aNovel = QAction(self.tr("Novel"))
self.aNovel.setIcon(self.theTheme.getIcon("view_novel"))
self.aNovel.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.NOVEL))
self.aOutline = QAction(self.tr("Outline"))
self.aOutline.setIcon(self.theTheme.getIcon("view_outline"))
self.aOutline.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.OUTLINE))
self.aDetails = QAction(self.tr("Details"))
self.aDetails.setIcon(self.theTheme.getIcon("proj_details"))
self.aDetails.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.DETAILS))
self.aStats = QAction(self.tr("Stats"))
self.aStats.setIcon(self.theTheme.getIcon("proj_stats"))
self.aStats.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.STATS))
self.aSettings = QAction(self.tr("Settings"))
self.aSettings.setIcon(self.theTheme.getIcon("settings"))
self.aSettings.triggered.connect(lambda: self.viewChangeRequested.emit(nwView.SET_PROJ))
# Assemble
self.addAction(self.aProject)
self.addAction(self.aNovel)
self.addAction(self.aOutline)
self.addWidget(stretch)
self.addAction(self.aDetails)
self.addAction(self.aStats)
self.addAction(self.aSettings)
logger.debug("GuiViewsBar initialisation complete")
return
# END Class GuiViewsBar
+74 -74
View File
@@ -30,17 +30,17 @@ import novelwriter
from time import time
from datetime import datetime
from PyQt5.QtCore import Qt, QTimer, QSize, QThreadPool, pyqtSlot
from PyQt5.QtCore import Qt, QTimer, QThreadPool, pyqtSlot
from PyQt5.QtGui import QIcon, QKeySequence, QCursor
from PyQt5.QtWidgets import (
qApp, QMainWindow, QVBoxLayout, QWidget, QSplitter, QFileDialog, QShortcut,
QMessageBox, QDialog, QTabWidget, QToolBar, QAction
QMessageBox, QDialog, QStackedWidget
)
from novelwriter.gui import (
GuiDocEditor, GuiDocViewDetails, GuiDocViewer, GuiItemDetails, GuiMainMenu,
GuiMainStatus, GuiNovelTree, GuiOutline, GuiOutlineDetails, GuiProjectTree,
GuiTheme
GuiTheme, GuiViewsBar
)
from novelwriter.dialogs import (
GuiAbout, GuiDocMerge, GuiDocSplit, GuiItemEditor, GuiPreferences,
@@ -52,7 +52,7 @@ from novelwriter.tools import (
)
from novelwriter.core import NWProject, NWIndex
from novelwriter.enum import (
nwItemType, nwItemClass, nwAlert, nwWidget, nwState
nwItemType, nwItemClass, nwAlert, nwWidget, nwState, nwView
)
from novelwriter.common import getGuiItem, hexToInt
@@ -102,8 +102,6 @@ class GuiMain(QMainWindow):
# Sizes
mPx = self.mainConf.pxInt(4)
fPx = self.theTheme.fontPixelSize
fPt = self.theTheme.fontPointSize
# Main GUI Elements
self.statusBar = GuiMainStatus(self)
@@ -116,6 +114,7 @@ class GuiMain(QMainWindow):
self.projView = GuiOutline(self)
self.projMeta = GuiOutlineDetails(self)
self.mainMenu = GuiMainMenu(self)
self.viewsBar = GuiViewsBar(self)
# Connect Signals Between Main Elements
self.docEditor.spellDictionaryChanged.connect(self.statusBar.setLanguage)
@@ -128,48 +127,21 @@ class GuiMain(QMainWindow):
self.treeView.novelItemChanged.connect(self._treeNovelItemChanged)
self.treeView.wordCountsChanged.connect(self._updateStatusWordCount)
# Project Tree Tabs
self.projTabs = QTabWidget()
self.projTabs.setTabPosition(QTabWidget.South)
self.projTabs.setStyleSheet("QTabWidget::pane {border: 0;};")
self.projTabs.addTab(self.treeView, self.tr("Project"))
self.projTabs.addTab(self.novelView, self.tr("Novel"))
self.projTabs.currentChanged.connect(self._projTabsChanged)
self.viewsBar.viewChangeRequested.connect(self._changeView)
self.projMeta.viewChangeRequested.connect(self._changeView)
tabFont = self.projTabs.tabBar().font()
tabFont.setPointSizeF(0.9*fPt)
self.projTabs.tabBar().setFont(tabFont)
# Project Tree Action Buttons
btnSize = int(round(0.7*fPx))
self.treeButtons = QToolBar()
self.treeButtons.setToolButtonStyle(Qt.ToolButtonIconOnly)
self.treeButtons.setIconSize(QSize(btnSize, btnSize))
self.treeButtons.setContentsMargins(0, 0, 0, 0)
self.treeButtons.setStyleSheet("QToolBar {padding: 0;}")
self.projTabs.setCornerWidget(self.treeButtons, Qt.BottomRightCorner)
self.projDetailsBtn = QAction(self.tr("Project Details"))
self.projDetailsBtn.setIcon(self.theTheme.getIcon("status_lines"))
self.projDetailsBtn.triggered.connect(lambda: self.showProjectDetailsDialog())
self.treeButtons.addAction(self.projDetailsBtn)
self.projStatsBtn = QAction(self.tr("Writing Statistics"))
self.projStatsBtn.setIcon(self.theTheme.getIcon("status_stats"))
self.projStatsBtn.triggered.connect(lambda: self.showWritingStatsDialog())
self.treeButtons.addAction(self.projStatsBtn)
self.projSettingsBtn = QAction(self.tr("Project Settings"))
self.projSettingsBtn.setIcon(self.theTheme.getIcon("settings"))
self.projSettingsBtn.triggered.connect(lambda: self.showProjectSettingsDialog())
self.treeButtons.addAction(self.projSettingsBtn)
# Project Tree Stack
self.projStack = QStackedWidget()
self.projStack.addWidget(self.treeView)
self.projStack.addWidget(self.novelView)
self.projStack.currentChanged.connect(self._projStackChanged)
# Project Tree View
self.treePane = QWidget()
self.treeBox = QVBoxLayout()
self.treeBox.setContentsMargins(0, 0, 0, 0)
self.treeBox.setSpacing(mPx)
self.treeBox.addWidget(self.projTabs)
self.treeBox.addWidget(self.projStack)
self.treeBox.addWidget(self.treeMeta)
self.treePane.setLayout(self.treeBox)
@@ -190,34 +162,32 @@ class GuiMain(QMainWindow):
self.splitOutline.addWidget(self.projMeta)
self.splitOutline.setSizes(self.mainConf.getOutlinePanePos())
# Main Tabs : Editor / Outline
self.mainTabs = QTabWidget()
self.mainTabs.setTabPosition(QTabWidget.East)
self.mainTabs.setStyleSheet("QTabWidget::pane {border: 0;}")
self.mainTabs.addTab(self.splitDocs, self.tr("Editor"))
self.mainTabs.addTab(self.splitOutline, self.tr("Outline"))
self.mainTabs.currentChanged.connect(self._mainTabChanged)
# Splitter : Project Tree / Main Tabs
self.splitMain = QSplitter(Qt.Horizontal)
self.splitMain.setContentsMargins(mPx, mPx, mPx, mPx)
self.splitMain.setContentsMargins(0, 0, mPx, 0)
self.splitMain.addWidget(self.treePane)
self.splitMain.addWidget(self.mainTabs)
self.splitMain.addWidget(self.splitDocs)
self.splitMain.setSizes(self.mainConf.getMainPanePos())
# Main Stack : Editor / Outline
self.mainStack = QStackedWidget()
self.mainStack.addWidget(self.splitMain)
self.mainStack.addWidget(self.splitOutline)
self.mainStack.currentChanged.connect(self._mainStackChanged)
# Indices of Splitter Widgets
self.idxTree = self.splitMain.indexOf(self.treePane)
self.idxMain = self.splitMain.indexOf(self.mainTabs)
self.idxMain = self.splitMain.indexOf(self.splitDocs)
self.idxEditor = self.splitDocs.indexOf(self.docEditor)
self.idxViewer = self.splitDocs.indexOf(self.splitView)
self.idxViewDoc = self.splitView.indexOf(self.docViewer)
self.idxViewMeta = self.splitView.indexOf(self.viewMeta)
# Indices of Tab Widgets
self.idxTabEdit = self.mainTabs.indexOf(self.splitDocs)
self.idxTabProj = self.mainTabs.indexOf(self.splitOutline)
self.idxTreeView = self.projTabs.indexOf(self.treeView)
self.idxNovelView = self.projTabs.indexOf(self.novelView)
self.idxEditorView = self.mainStack.indexOf(self.splitMain)
self.idxOutlineView = self.mainStack.indexOf(self.splitOutline)
self.idxTreeView = self.projStack.indexOf(self.treeView)
self.idxNovelView = self.projStack.indexOf(self.novelView)
# Splitter Behaviour
self.splitMain.setCollapsible(self.idxTree, False)
@@ -236,8 +206,9 @@ class GuiMain(QMainWindow):
# Set Main Window Elements
self.setMenuBar(self.mainMenu)
self.setCentralWidget(self.splitMain)
self.setCentralWidget(self.mainStack)
self.setStatusBar(self.statusBar)
self.addToolBar(Qt.LeftToolBarArea, self.viewsBar)
# Finalise Initialisation
# =======================
@@ -448,7 +419,7 @@ class GuiMain(QMainWindow):
self.theIndex.clearIndex()
self.clearGUI()
self.hasProject = False
self.mainTabs.setCurrentWidget(self.splitDocs)
self._changeView(nwView.PROJECT)
return saveOK
@@ -464,7 +435,7 @@ class GuiMain(QMainWindow):
return False
# Switch main tab to editor view
self.mainTabs.setCurrentWidget(self.splitDocs)
self._changeView(nwView.PROJECT)
# Try to open the project
if not self.theProject.openProject(projFile):
@@ -603,7 +574,7 @@ class GuiMain(QMainWindow):
return False
self.closeDocument()
self.mainTabs.setCurrentWidget(self.splitDocs)
self._changeView(nwView.EDITOR)
if self.docEditor.loadText(tHandle, tLine):
if changeFocus:
self.docEditor.setFocus()
@@ -686,7 +657,7 @@ class GuiMain(QMainWindow):
return False
# Make sure main tab is in Editor view
self.mainTabs.setCurrentWidget(self.splitDocs)
self._changeView(nwView.EDITOR)
logger.debug("Viewing document with handle '%s'", tHandle)
if self.docViewer.loadText(tHandle):
@@ -871,7 +842,7 @@ class GuiMain(QMainWindow):
def requestNovelTreeRefresh(self):
"""Update the novel tree, but only if it is visible.
"""
if self.projTabs.currentIndex() == self.idxNovelView and self.hasProject:
if self.projStack.currentIndex() == self.idxNovelView and self.hasProject:
self.novelView.refreshTree()
return True
return False
@@ -932,7 +903,7 @@ class GuiMain(QMainWindow):
return False
logger.verbose("Forcing a rebuild of the Project Outline")
self.mainTabs.setCurrentWidget(self.splitOutline)
self._changeView(nwView.OUTLINE)
self.projView.refreshTree(overRide=True)
return True
@@ -1245,19 +1216,19 @@ class GuiMain(QMainWindow):
"""Switch focus between main GUI views.
"""
if paneNo == nwWidget.TREE:
tabIdx = self.projTabs.currentIndex()
tabIdx = self.projStack.currentIndex()
if tabIdx == self.idxTreeView:
self.treeView.setFocus()
elif tabIdx == self.idxNovelView:
self.novelView.setFocus()
elif paneNo == nwWidget.EDITOR:
self.mainTabs.setCurrentWidget(self.splitDocs)
self._changeView(nwView.EDITOR)
self.docEditor.setFocus()
elif paneNo == nwWidget.VIEWER:
self.mainTabs.setCurrentWidget(self.splitDocs)
self._changeView(nwView.EDITOR)
self.docViewer.setFocus()
elif paneNo == nwWidget.OUTLINE:
self.mainTabs.setCurrentWidget(self.splitOutline)
self._changeView(nwView.OUTLINE)
self.projView.setFocus()
return
@@ -1290,7 +1261,6 @@ class GuiMain(QMainWindow):
self.mainMenu.setFocusMode(self.isFocusMode)
if self.isFocusMode:
logger.debug("Activating Focus Mode")
self.mainTabs.setCurrentWidget(self.splitDocs)
self.switchFocus(nwWidget.EDITOR)
else:
logger.debug("Deactivating Focus Mode")
@@ -1299,7 +1269,7 @@ class GuiMain(QMainWindow):
self.treePane.setVisible(isVisible)
self.statusBar.setVisible(isVisible)
self.mainMenu.setVisible(isVisible)
self.mainTabs.tabBar().setVisible(isVisible)
self.viewsBar.setVisible(isVisible)
hideDocFooter = self.isFocusMode and self.mainConf.hideFocusFooter
self.docEditor.docFooter.setVisible(not hideDocFooter)
@@ -1513,6 +1483,36 @@ class GuiMain(QMainWindow):
# Slots
##
@pyqtSlot(nwView)
def _changeView(self, view):
"""Handle the requested change of view from the GuiViewBar.
"""
if view == nwView.EDITOR:
# Only change the main stack, but not the project stack
self.mainStack.setCurrentWidget(self.splitMain)
elif view == nwView.PROJECT:
self.mainStack.setCurrentWidget(self.splitMain)
self.projStack.setCurrentWidget(self.treeView)
elif view == nwView.NOVEL:
self.mainStack.setCurrentWidget(self.splitMain)
self.projStack.setCurrentWidget(self.novelView)
elif view == nwView.OUTLINE:
self.mainStack.setCurrentWidget(self.splitOutline)
elif view == nwView.DETAILS:
self.showProjectDetailsDialog()
elif view == nwView.STATS:
self.showWritingStatsDialog()
elif view == nwView.SET_PROJ:
self.showProjectSettingsDialog()
return
@pyqtSlot()
def _timeTick(self):
"""Triggered on every tick of the main timer.
@@ -1586,7 +1586,7 @@ class GuiMain(QMainWindow):
"""Triggered when there is a change to a novel item in the
project tree.
"""
if self.mainTabs.currentIndex() == self.idxTabProj:
if self.mainStack.currentIndex() == self.idxOutlineView:
logger.verbose("Novel tree changed while Outline tab active")
if self.hasProject:
self.treeView.flushTreeOrder()
@@ -1615,12 +1615,12 @@ class GuiMain(QMainWindow):
return
@pyqtSlot(int)
def _mainTabChanged(self, tabIndex):
def _mainStackChanged(self, tabIndex):
"""Activated when the main window tab is changed.
"""
if tabIndex == self.idxTabEdit:
if tabIndex == self.idxEditorView:
logger.verbose("Editor tab activated")
elif tabIndex == self.idxTabProj:
elif tabIndex == self.idxOutlineView:
logger.verbose("Project outline tab activated")
if self.hasProject:
self.projView.refreshTree()
@@ -1628,7 +1628,7 @@ class GuiMain(QMainWindow):
return
@pyqtSlot(int)
def _projTabsChanged(self, tabIndex):
def _projStackChanged(self, tabIndex):
"""Activated when the project view tab is changed.
"""
sHandle = None
+2 -2
View File
@@ -85,7 +85,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
# Project Tree has focus
nwGUI.switchFocus(nwWidget.TREE)
nwGUI.projTabs.setCurrentIndex(0)
nwGUI.projStack.setCurrentIndex(0)
with monkeypatch.context() as mp:
mp.setattr(GuiProjectTree, "hasFocus", lambda *a: True)
assert nwGUI.docEditor.docHandle() is None
@@ -95,7 +95,7 @@ def testGuiMain_ProjectTreeItems(qtbot, monkeypatch, nwGUI, fncProj, mockRnd):
assert nwGUI.closeDocument() is True
# Novel Tree has focus
nwGUI.projTabs.setCurrentIndex(1)
nwGUI.projStack.setCurrentIndex(1)
nwGUI.novelView.refreshTree(True)
with monkeypatch.context() as mp:
mp.setattr(GuiNovelTree, "hasFocus", lambda *a: True)
+1 -1
View File
@@ -59,7 +59,7 @@ def testGuiNovelTree_TreeItems(qtbot, monkeypatch, nwGUI, nwMinimal):
# Populate Tree
##
nwGUI.projTabs.setCurrentIndex(nwGUI.idxNovelView)
nwGUI.projStack.setCurrentIndex(nwGUI.idxNovelView)
nwGUI.rebuildIndex()
nwTree._populateTree()
assert nwTree.topLevelItemCount() == 1
+1 -1
View File
@@ -43,7 +43,7 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, nwLipsum):
nwGUI.mainConf.lastPath = nwLipsum
nwGUI.rebuildIndex()
nwGUI.mainTabs.setCurrentIndex(nwGUI.idxTabProj)
nwGUI.mainStack.setCurrentIndex(nwGUI.idxOutlineView)
assert nwGUI.projView.topLevelItemCount() > 0