Compare commits
795 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83fca9fd94 | ||
|
|
4150a9740b | ||
|
|
f7021559d0 | ||
|
|
00d4c550f1 | ||
|
|
97903993c8 | ||
|
|
3d858ed9ab | ||
|
|
cc5cd50065 | ||
|
|
0c0d909dcb | ||
|
|
8dafaa13c0 | ||
|
|
05385ba73b | ||
|
|
924a2c3381 | ||
|
|
6502c424e2 | ||
|
|
243124a4ba | ||
|
|
4a2a14bc05 | ||
|
|
976328c9dc | ||
|
|
3b0086e75e | ||
|
|
7c38a748b6 | ||
|
|
4d98689304 | ||
|
|
8307822e20 | ||
|
|
f1548dc8ea | ||
|
|
25b33ab4d3 | ||
|
|
4af98dcab5 | ||
|
|
3cf916c845 | ||
|
|
bcac05ca20 | ||
|
|
07c61450c7 | ||
|
|
43d95462e0 | ||
|
|
c091e0b9bb | ||
|
|
18c70ffe3e | ||
|
|
ff470028be | ||
|
|
8463188336 | ||
|
|
2808c36753 | ||
|
|
05b1fdd7f2 | ||
|
|
00017e8065 | ||
|
|
ff34112532 | ||
|
|
4cadd1597e | ||
|
|
e30d2cbbf1 | ||
|
|
0449cf824d | ||
|
|
32d899dbfb | ||
|
|
9ec9c55c3f | ||
|
|
01b2b53fd5 | ||
|
|
be6888f8c8 | ||
|
|
c1ed0647fe | ||
|
|
1bf42ceb55 | ||
|
|
ca8bd8d271 | ||
|
|
bf23a4920f | ||
|
|
cfb048ec19 | ||
|
|
5284bea0f0 | ||
|
|
1244a4058c | ||
|
|
8c51363651 | ||
|
|
893f18c7ad | ||
|
|
909c97feda | ||
|
|
fea989c1f8 | ||
|
|
a64ed405f3 | ||
|
|
ffe6cd0a65 | ||
|
|
e0b27317f3 | ||
|
|
7ed619cf2e | ||
|
|
d55f53be0a | ||
|
|
55eed706fb | ||
|
|
2f71ec68d8 | ||
|
|
a45ab2f017 | ||
|
|
26b4da9eb4 | ||
|
|
4897f6ad69 | ||
|
|
bbe8683d59 | ||
|
|
072be78991 | ||
|
|
3f41e62e21 | ||
|
|
ec01336c21 | ||
|
|
5dcfe5c874 | ||
|
|
72f1bc2d77 | ||
|
|
54685c8184 | ||
|
|
3532306833 | ||
|
|
442b065834 | ||
|
|
53e70c118c | ||
|
|
a5575992d6 | ||
|
|
df0244095f | ||
|
|
337f05f60e | ||
|
|
4f8e898440 | ||
|
|
7991b9b27c | ||
|
|
ef42e1956c | ||
|
|
27b3dde6f6 | ||
|
|
cbe557507f | ||
|
|
7a9da5f219 | ||
|
|
d944a70063 | ||
|
|
c20f970405 | ||
|
|
49bb7f3a34 | ||
|
|
021827ff2d | ||
|
|
97312aecf5 | ||
|
|
f3c9a77989 | ||
|
|
2c031bc093 | ||
|
|
69147c2480 | ||
|
|
22ca0045bc | ||
|
|
af431a4766 | ||
|
|
5a8045131b | ||
|
|
7c0a6f1d02 | ||
|
|
4fc69ef7c6 | ||
|
|
91e502deb6 | ||
|
|
1ee191220f | ||
|
|
a96ccf8422 | ||
|
|
57641ecd7d | ||
|
|
ed431aa30f | ||
|
|
7a111bb173 | ||
|
|
220be06631 | ||
|
|
d8c14f6712 | ||
|
|
e514b1be4f | ||
|
|
5e7ef1d25a | ||
|
|
c2b3eb4ac2 | ||
|
|
1bd8370864 | ||
|
|
8c952953e3 | ||
|
|
c065c9b30f | ||
|
|
a18eb1158e | ||
|
|
08ef352288 | ||
|
|
25297b8b0b | ||
|
|
ea591fe707 | ||
|
|
b0bcf8605c | ||
|
|
b28921d6c2 | ||
|
|
87ae7585e8 | ||
|
|
b39b37fb2f | ||
|
|
cd9e0de9dd | ||
|
|
5107849909 | ||
|
|
5c988960f5 | ||
|
|
44792778aa | ||
|
|
0a7bd68258 | ||
|
|
30118eceaa | ||
|
|
87512eb13b | ||
|
|
9919e1a49e | ||
|
|
d04a21b70f | ||
|
|
fc6e0a577f | ||
|
|
0c659422b7 | ||
|
|
2018023dc7 | ||
|
|
04645cab71 | ||
|
|
bec082c0ae | ||
|
|
83b244a8a3 | ||
|
|
ae261381aa | ||
|
|
b088b79ee8 | ||
|
|
0b59ee8634 | ||
|
|
f62b755903 | ||
|
|
04036ef35c | ||
|
|
e4a2ca2d19 | ||
|
|
89f452f3fc | ||
|
|
843f8e0d39 | ||
|
|
8618306230 | ||
|
|
34a3e17326 | ||
|
|
5af49dfc6f | ||
|
|
837d3060b8 | ||
|
|
2754f78083 | ||
|
|
1b509ad60b | ||
|
|
82e923b181 | ||
|
|
e92b8400c7 | ||
|
|
1ad6a80682 | ||
|
|
f355b82bba | ||
|
|
66567b6d6f | ||
|
|
d9582436d4 | ||
|
|
31c75ea0b1 | ||
|
|
057fc10565 | ||
|
|
bbb07c9963 | ||
|
|
dd09d3af2f | ||
|
|
ccb5f8418b | ||
|
|
55d2605222 | ||
|
|
7f49979bc9 | ||
|
|
b529d5b125 | ||
|
|
f2e36d9974 | ||
|
|
ca2b509d54 | ||
|
|
0ba0674b9e | ||
|
|
a2b09fdfec | ||
|
|
fa0bef5500 | ||
|
|
92d148b03d | ||
|
|
3d935e29eb | ||
|
|
3749c9f21d | ||
|
|
2a3d3e46c2 | ||
|
|
9bc1561e01 | ||
|
|
d987246062 | ||
|
|
c6a22e2d96 | ||
|
|
42f904f1ea | ||
|
|
f92521c93a | ||
|
|
041183f914 | ||
|
|
857b6ddc55 | ||
|
|
f2d2b4c4f2 | ||
|
|
8725edaf7e | ||
|
|
4eace705e3 | ||
|
|
b2d71acd93 | ||
|
|
e424fcfe53 | ||
|
|
eefb40cb1f | ||
|
|
785cd3aea9 | ||
|
|
07c700f666 | ||
|
|
8db0928724 | ||
|
|
b25ba9de27 | ||
|
|
bf478a6706 | ||
|
|
a1a58f51b1 | ||
|
|
8850161641 | ||
|
|
f931148594 | ||
|
|
c31b0bcf17 | ||
|
|
ba260ac608 | ||
|
|
f2fc19b168 | ||
|
|
ceabc666c3 | ||
|
|
6c217c2450 | ||
|
|
7ff8921420 | ||
|
|
fe56c88309 | ||
|
|
b13b91c8e8 | ||
|
|
d71435df53 | ||
|
|
058758122c | ||
|
|
759cfd77e9 | ||
|
|
37268b873a | ||
|
|
439a04c603 | ||
|
|
9f642d501a | ||
|
|
7f8e2c66a6 | ||
|
|
9962fd4a55 | ||
|
|
c27343534f | ||
|
|
46ecb2cf70 | ||
|
|
88aa3f38c2 | ||
|
|
9214da3756 | ||
|
|
41e5152771 | ||
|
|
6b01bd7ffe | ||
|
|
76a9f8e3df | ||
|
|
e15941520f | ||
|
|
ff7404d01d | ||
|
|
560540618c | ||
|
|
bfa82f6bb3 | ||
|
|
f77cd1c752 | ||
|
|
8461b0c15d | ||
|
|
2938a0f122 | ||
|
|
beccd1a7d1 | ||
|
|
c6883908f1 | ||
|
|
36d8547f78 | ||
|
|
b01c91c0a3 | ||
|
|
3712b2e93f | ||
|
|
0ddc1131dc | ||
|
|
f4a941cd93 | ||
|
|
db72f2a722 | ||
|
|
16023676ea | ||
|
|
52e85835df | ||
|
|
fe63770d21 | ||
|
|
bd5442c9e5 | ||
|
|
c7554f2b8d | ||
|
|
63f9cd0bac | ||
|
|
c537d0f396 | ||
|
|
e759aa8d1b | ||
|
|
2d8664b3ce | ||
|
|
16076ebfb6 | ||
|
|
38ca447c8a | ||
|
|
f91006631d | ||
|
|
3cc5e4cc7a | ||
|
|
75178b7874 | ||
|
|
ce3f6dae20 | ||
|
|
bd82392d71 | ||
|
|
836a3d353a | ||
|
|
a4d2a9ea6f | ||
|
|
b0fc8d63a6 | ||
|
|
ec7781fb9f | ||
|
|
787e1a46d1 | ||
|
|
148d46fcbc | ||
|
|
7e1a676e0a | ||
|
|
e9220c5e77 | ||
|
|
72d41d4883 | ||
|
|
de6c3e9b45 | ||
|
|
a0ab507ed1 | ||
|
|
3c76d0e7e3 | ||
|
|
34127d78bf | ||
|
|
ca33f488f1 | ||
|
|
717aac9dc8 | ||
|
|
4b07dbadb2 | ||
|
|
9bbebd2085 | ||
|
|
d60b29e0a2 | ||
|
|
80d2dfd9a4 | ||
|
|
464454e7a6 | ||
|
|
d145b65237 | ||
|
|
912198cc40 | ||
|
|
bffab79ba7 | ||
|
|
c82f7fd9ca | ||
|
|
53afe528e8 | ||
|
|
225befe57e | ||
|
|
40817e73b4 | ||
|
|
17c93c2172 | ||
|
|
c8d7ccadb7 | ||
|
|
7bb292404a | ||
|
|
d2ac0ed53f | ||
|
|
c633a56bfb | ||
|
|
34696ba3a8 | ||
|
|
93c105fe86 | ||
|
|
29eac0b4e5 | ||
|
|
fc27078954 | ||
|
|
759a8e84f0 | ||
|
|
b2c7da319e | ||
|
|
b56095224a | ||
|
|
2f12a8cc93 | ||
|
|
140f85f214 | ||
|
|
7405c7e20f | ||
|
|
f29b13679a | ||
|
|
9b9ed53cf9 | ||
|
|
2447ae5cff | ||
|
|
7379b8b521 | ||
|
|
22473823c9 | ||
|
|
d8bb9950d3 | ||
|
|
279fe2ae18 | ||
|
|
1e812f3f06 | ||
|
|
0f1401eb71 | ||
|
|
57e739c3ef | ||
|
|
1b457585d9 | ||
|
|
c9eab0b01e | ||
|
|
3da5074d14 | ||
|
|
e97a476c7f | ||
|
|
a716f31b17 | ||
|
|
b2e760a284 | ||
|
|
7cc48aeb7f | ||
|
|
a6494b4226 | ||
|
|
5ed03e29f3 | ||
|
|
5c07148eb2 | ||
|
|
17b4a7be4d | ||
|
|
9b08ebbbd5 | ||
|
|
37c469dbc7 | ||
|
|
c08033d153 | ||
|
|
9c63f621a8 | ||
|
|
c3cb12e5e2 | ||
|
|
d3799bc30a | ||
|
|
cb8933b493 | ||
|
|
1aa58c047f | ||
|
|
52b3084bee | ||
|
|
70b05c9e07 | ||
|
|
cafa440aee | ||
|
|
681cb7226a | ||
|
|
b36e49e43f | ||
|
|
90a6c2d98d | ||
|
|
21d21846ca | ||
|
|
cc8d7d9912 | ||
|
|
10527afbda | ||
|
|
d16ece2a81 | ||
|
|
e7f7dc8d60 | ||
|
|
2f2943452f | ||
|
|
08ae2b5351 | ||
|
|
eda1a1c4dd | ||
|
|
238abdb567 | ||
|
|
c3f9ceb03a | ||
|
|
b95e9fcda3 | ||
|
|
b3f8a2c18c | ||
|
|
18bbf7d86f | ||
|
|
8e3ad6d874 | ||
|
|
7a63ac83d2 | ||
|
|
8dc28ddbee | ||
|
|
15803cf0a3 | ||
|
|
5ac001781c | ||
|
|
66986b88f8 | ||
|
|
f4e12a63a5 | ||
|
|
09b0f34199 | ||
|
|
095c005c3f | ||
|
|
e414b6458d | ||
|
|
ece73784c2 | ||
|
|
8dd9644c13 | ||
|
|
556e8db104 | ||
|
|
ce979b6c84 | ||
|
|
d2f422a441 | ||
|
|
e4daff8956 | ||
|
|
c146c311c1 | ||
|
|
2e1b17dcdf | ||
|
|
2ef11f56e5 | ||
|
|
fdaeca78a7 | ||
|
|
93e7343fe9 | ||
|
|
5167608f7a | ||
|
|
7fe3a8520d | ||
|
|
d4a0881e77 | ||
|
|
7f42210f2f | ||
|
|
33497bc92d | ||
|
|
06aa2e6c07 | ||
|
|
3bffaa01dc | ||
|
|
66237c35ea | ||
|
|
f532857345 | ||
|
|
5936e1a68b | ||
|
|
17b3b2b770 | ||
|
|
826e805b06 | ||
|
|
5419d76606 | ||
|
|
0d84653f7d | ||
|
|
b7da56ac42 | ||
|
|
7140788b48 | ||
|
|
a43bd5a50e | ||
|
|
81dd98e83b | ||
|
|
742f84576e | ||
|
|
ba81662d6a | ||
|
|
f669ac1265 | ||
|
|
b8a97b1afc | ||
|
|
4eb0ed386c | ||
|
|
ece225c355 | ||
|
|
69d97a3f3e | ||
|
|
dcecaae3af | ||
|
|
1c261ef371 | ||
|
|
ea89e66a46 | ||
|
|
dd03c19be2 | ||
|
|
08e6d320df | ||
|
|
446163c6de | ||
|
|
abd503b5a2 | ||
|
|
2e1c08cbfa | ||
|
|
7bdadadea1 | ||
|
|
bc33a4d0d4 | ||
|
|
188bc5d16f | ||
|
|
3fd0385160 | ||
|
|
5f3f55133e | ||
|
|
47b8e12bc7 | ||
|
|
cc97129e64 | ||
|
|
e40e282837 | ||
|
|
eba0fa58bf | ||
|
|
1c0fdd6a17 | ||
|
|
43eb62576c | ||
|
|
d43a799389 | ||
|
|
4d716555af | ||
|
|
7c65d22452 | ||
|
|
1b8867537e | ||
|
|
b91a11980b | ||
|
|
e80a9824f6 | ||
|
|
140b22dc63 | ||
|
|
60169b914a | ||
|
|
fbe381638a | ||
|
|
6dcb44c391 | ||
|
|
54c7c5a463 | ||
|
|
d5bcee14f5 | ||
|
|
0064b742d3 | ||
|
|
9f88f3b79e | ||
|
|
b95d030032 | ||
|
|
f4f3f82954 | ||
|
|
5e8892ee7c | ||
|
|
42b1e6a559 | ||
|
|
e1bcfcfc05 | ||
|
|
069e35565f | ||
|
|
880b560a39 | ||
|
|
8becc83c05 | ||
|
|
b5ef62194d | ||
|
|
a87c287fa6 | ||
|
|
18f5deee82 | ||
|
|
53545a0015 | ||
|
|
f662eaeccc | ||
|
|
1e6377abaa | ||
|
|
516db26c05 | ||
|
|
2df55cf6ee | ||
|
|
251475197d | ||
|
|
802069b4e5 | ||
|
|
d07543926f | ||
|
|
5665efd9d7 | ||
|
|
ea7f3fe51c | ||
|
|
c6569b63e5 | ||
|
|
930c60ae4a | ||
|
|
869cdd2fb0 | ||
|
|
f7d0adad1b | ||
|
|
d25e2adfb6 | ||
|
|
cb3a24bcd2 | ||
|
|
6540c56672 | ||
|
|
efc94a7fd5 | ||
|
|
683e81c57b | ||
|
|
f548927b74 | ||
|
|
53522908c8 | ||
|
|
43cdc8420c | ||
|
|
45ad0f8c20 | ||
|
|
59c9783393 | ||
|
|
611a6bb80a | ||
|
|
ee46fdb5b1 | ||
|
|
7c33c949cb | ||
|
|
e9e7fae40e | ||
|
|
ac05b07f10 | ||
|
|
aff027b735 | ||
|
|
14f1697428 | ||
|
|
a3381f1f79 | ||
|
|
1b7d331e41 | ||
|
|
df34293e74 | ||
|
|
fe27acc3ef | ||
|
|
35632abea3 | ||
|
|
ea247c5814 | ||
|
|
928a116666 | ||
|
|
2a99cafbf2 | ||
|
|
2196486454 | ||
|
|
f99bd79ce8 | ||
|
|
ddaced1b78 | ||
|
|
3e8845ab58 | ||
|
|
d5be1e0479 | ||
|
|
babc39c6a2 | ||
|
|
5c35ebeffa | ||
|
|
5fbc608c90 | ||
|
|
0c7808a24b | ||
|
|
4aadbdaed2 | ||
|
|
195a7e354b | ||
|
|
c03e832c7b | ||
|
|
73515c96d8 | ||
|
|
e7c0d59809 | ||
|
|
556caea308 | ||
|
|
6d54902a08 | ||
|
|
fb32cea5b5 | ||
|
|
69cd443999 | ||
|
|
cc61c5321e | ||
|
|
7821f099bf | ||
|
|
4b0ad6ec48 | ||
|
|
416c580a45 | ||
|
|
0b3488c265 | ||
|
|
f0f5ae6dc9 | ||
|
|
f61ce3919b | ||
|
|
67c6497e2a | ||
|
|
9bcb2479ac | ||
|
|
8a9b038d56 | ||
|
|
eed4721ef0 | ||
|
|
b76c866c9d | ||
|
|
255a4a327e | ||
|
|
811db81a86 | ||
|
|
29b61c07b0 | ||
|
|
f8c1ee90ce | ||
|
|
d9c86d56bb | ||
|
|
cddf63f111 | ||
|
|
ca91e6a677 | ||
|
|
a48fde95a3 | ||
|
|
aed4ba4310 | ||
|
|
57ee88059d | ||
|
|
c8dccbe438 | ||
|
|
8a071090e0 | ||
|
|
cbf76e6575 | ||
|
|
83d2cb4f82 | ||
|
|
497d4dd7f9 | ||
|
|
d48f1fa292 | ||
|
|
7744ae5912 | ||
|
|
92b7168363 | ||
|
|
8fc97c263b | ||
|
|
d190315909 | ||
|
|
987740f7e9 | ||
|
|
2e143071d9 | ||
|
|
388141aae6 | ||
|
|
80811ebf44 | ||
|
|
208c4fb8ba | ||
|
|
38a5fddb9d | ||
|
|
f844a5080a | ||
|
|
a11a013d16 | ||
|
|
f34cb567e4 | ||
|
|
6cb330b06c | ||
|
|
04cf375725 | ||
|
|
b66686a869 | ||
|
|
31776a51a7 | ||
|
|
f1b7257e73 | ||
|
|
be7078aa7e | ||
|
|
931aed6d78 | ||
|
|
dc6fe77612 | ||
|
|
b387150d4f | ||
|
|
9b09b13bf9 | ||
|
|
d8693c7afa | ||
|
|
019dd3e478 | ||
|
|
b01a2f5abd | ||
|
|
087a9cdd2e | ||
|
|
b33bf954bb | ||
|
|
f7cdc7da0c | ||
|
|
cf14f84652 | ||
|
|
6289840a74 | ||
|
|
770cccda49 | ||
|
|
aa02c0f15d | ||
|
|
ee137b6ffd | ||
|
|
206ca6040e | ||
|
|
16f5670c83 | ||
|
|
0fc1af7180 | ||
|
|
55714bbcad | ||
|
|
6f144c20cd | ||
|
|
f23bd3818f | ||
|
|
d3ea763d6b | ||
|
|
91222f631f | ||
|
|
aceb344856 | ||
|
|
f11ea8d07e | ||
|
|
a4e3bf848b | ||
|
|
e74c1057a4 | ||
|
|
6cc046c65c | ||
|
|
c97a070e98 | ||
|
|
b4c0bf3322 | ||
|
|
e998cb634e | ||
|
|
c8017a1f42 | ||
|
|
6d84942746 | ||
|
|
818f145b62 | ||
|
|
f92c22ce7e | ||
|
|
69b362b9d2 | ||
|
|
1fe7ca3db8 | ||
|
|
cc32674b0f | ||
|
|
cf16b57f66 | ||
|
|
411163f750 | ||
|
|
7f3da655c0 | ||
|
|
76e786d961 | ||
|
|
7e1f1a725c | ||
|
|
c63a0c2f58 | ||
|
|
04a7e092a9 | ||
|
|
309065bcbf | ||
|
|
20ae3febef | ||
|
|
e95d33031c | ||
|
|
3fd62d0b02 | ||
|
|
dc0ddcfa9f | ||
|
|
7a13b14c15 | ||
|
|
adf0550571 | ||
|
|
ba6259f08a | ||
|
|
d8bb2ad3ae | ||
|
|
afe4a29fd1 | ||
|
|
1203dd639b | ||
|
|
aadad6aa8c | ||
|
|
8ac0440bb3 | ||
|
|
d2fca3b980 | ||
|
|
d6b4019614 | ||
|
|
a6eb951361 | ||
|
|
dce5bdd31d | ||
|
|
0b999bd726 | ||
|
|
774437f7bb | ||
|
|
c0673b8128 | ||
|
|
0bc8a63ccf | ||
|
|
192f4507e3 | ||
|
|
2d22adcd2a | ||
|
|
4c4b92fdd4 | ||
|
|
2a727d1c39 | ||
|
|
35693f5433 | ||
|
|
bf459b4090 | ||
|
|
728f1ce1e3 | ||
|
|
7b8021de02 | ||
|
|
60593cde21 | ||
|
|
f9292d61da | ||
|
|
9388ce6a46 | ||
|
|
cb19475409 | ||
|
|
09b51badd4 | ||
|
|
fddd5fda47 | ||
|
|
5b0a6f05ed | ||
|
|
51f91a27e2 | ||
|
|
09018d1214 | ||
|
|
de12b22c97 | ||
|
|
d1ae7f5fe2 | ||
|
|
201d32f6ae | ||
|
|
6a441b1c6b | ||
|
|
0afa15f2db | ||
|
|
85eb44da02 | ||
|
|
4856c7a61b | ||
|
|
1b4cc933e7 | ||
|
|
d64acb038b | ||
|
|
b5def640ed | ||
|
|
7e35b4c675 | ||
|
|
e5e3066b3d | ||
|
|
e1af21bf88 | ||
|
|
8c9d08e46b | ||
|
|
e4acfb4831 | ||
|
|
a8101c2231 | ||
|
|
a3ce426613 | ||
|
|
161d02cd98 | ||
|
|
101400bea3 | ||
|
|
1ff9fea378 | ||
|
|
3f4538a60e | ||
|
|
142d7c4f3a | ||
|
|
2afe0ebbe9 | ||
|
|
bc71a62199 | ||
|
|
1e85ce4a84 | ||
|
|
39951a5099 | ||
|
|
9cbb6f3125 | ||
|
|
2dbd3e2534 | ||
|
|
f871a51e5b | ||
|
|
6ab3c68ebb | ||
|
|
7243ccd44c | ||
|
|
2a96fa1a2d | ||
|
|
c05620dddb | ||
|
|
917977ae13 | ||
|
|
2b8338f537 | ||
|
|
e75b5e012c | ||
|
|
78e194d8c1 | ||
|
|
c594e07c8c | ||
|
|
a3ed079828 | ||
|
|
976ce16ac2 | ||
|
|
5faeb12a74 | ||
|
|
acc463eb76 | ||
|
|
3b7459ffbc | ||
|
|
cfb19a697a | ||
|
|
ceec43db67 | ||
|
|
229fa39436 | ||
|
|
2496eb22cb | ||
|
|
d0a45bceca | ||
|
|
7180fae453 | ||
|
|
e1a1b5980e | ||
|
|
53d410a6ee | ||
|
|
a56b38694c | ||
|
|
600b60b441 | ||
|
|
aa7208b602 | ||
|
|
0092b3ece6 | ||
|
|
d01c1e867d | ||
|
|
dd3c8dfac8 | ||
|
|
7c9c5a9a76 | ||
|
|
8f9a55c5ca | ||
|
|
ea0b61aa6d | ||
|
|
b94e7159b8 | ||
|
|
2eabca8267 | ||
|
|
afbe434b59 | ||
|
|
2a50799873 | ||
|
|
77727ad500 | ||
|
|
e89f1fe5a8 | ||
|
|
503e7eceb5 | ||
|
|
c15eba8f62 | ||
|
|
e2f83d5106 | ||
|
|
937b5cca12 | ||
|
|
1d438d5d76 | ||
|
|
22a34be21a | ||
|
|
17a492444e | ||
|
|
9a714a903d | ||
|
|
69a99fc97f | ||
|
|
8beb74689c | ||
|
|
6be7da0305 | ||
|
|
8a08fe213c | ||
|
|
205b17aea0 | ||
|
|
864172ea50 | ||
|
|
e01e14075c | ||
|
|
e9596e1bbc | ||
|
|
db9305c230 | ||
|
|
4572d101cf | ||
|
|
41506911c1 | ||
|
|
b722224863 | ||
|
|
b585b8ecd1 | ||
|
|
52e8ae9cb6 | ||
|
|
6d6d0c2d12 | ||
|
|
383640cb7e | ||
|
|
e5ef27dfbf | ||
|
|
96741fc08b | ||
|
|
dc41f495be | ||
|
|
b278d64d0c | ||
|
|
b5e32844f5 | ||
|
|
4179d2e515 | ||
|
|
815ba9d553 | ||
|
|
0d294f49f9 | ||
|
|
a195cfc792 | ||
|
|
d3c9168ebf | ||
|
|
4d153b8d99 | ||
|
|
bf8d224064 | ||
|
|
b7ad2c969a | ||
|
|
d78643160c | ||
|
|
221b38c766 | ||
|
|
e8bd9b21b5 | ||
|
|
c2f0d04a35 | ||
|
|
54ebcd91cb | ||
|
|
07411327b6 | ||
|
|
094ad1a17b | ||
|
|
c362848b86 | ||
|
|
47a8dfbd93 | ||
|
|
73b8443d7b | ||
|
|
48a7929254 | ||
|
|
2c1abf1519 | ||
|
|
e27e066ccc | ||
|
|
621e933f63 | ||
|
|
885974a84e | ||
|
|
b1d1af2153 | ||
|
|
cb94be5b3c | ||
|
|
5a202e96fd | ||
|
|
b80edee225 | ||
|
|
48e653a546 | ||
|
|
a2d8aefb21 | ||
|
|
ae893be79b | ||
|
|
791080107f | ||
|
|
7d22ed1249 | ||
|
|
8150edbc43 | ||
|
|
5acbfeffa5 | ||
|
|
3b763e3460 | ||
|
|
6dd5f4295d | ||
|
|
ac7b0bc9a2 | ||
|
|
1733938eb4 | ||
|
|
e5c9ed4b80 | ||
|
|
f45170850c | ||
|
|
bdce0e12c7 | ||
|
|
57f9a0a844 | ||
|
|
988d969de7 | ||
|
|
17960d286f | ||
|
|
26ac68e98e | ||
|
|
0729dd798b | ||
|
|
c65dee1df9 | ||
|
|
92888338f4 | ||
|
|
44192c88f5 | ||
|
|
8d24243d4f | ||
|
|
7c4d4dec5c | ||
|
|
9823677983 | ||
|
|
ec6a5712e5 | ||
|
|
70033cb0f3 | ||
|
|
da102d3d5a | ||
|
|
5568b43b22 | ||
|
|
5da30e6608 | ||
|
|
0fb0af5b32 | ||
|
|
f5fcc57a06 | ||
|
|
4a1a3013f4 | ||
|
|
cf57a3ead0 | ||
|
|
39b2ff4a72 | ||
|
|
eced026aeb | ||
|
|
730d09a76c | ||
|
|
b521b39498 | ||
|
|
492bc044fc | ||
|
|
84ff2f8371 | ||
|
|
54f26ea06e | ||
|
|
e10f3a19d3 | ||
|
|
21a5dbbb52 | ||
|
|
f67d2c5a4c | ||
|
|
6cf83bb381 | ||
|
|
f4decae77f | ||
|
|
e47f0c5166 | ||
|
|
778b65b48c | ||
|
|
d1dbb0b378 | ||
|
|
adfd003532 | ||
|
|
f17302439e | ||
|
|
63d2f5c57d | ||
|
|
478db63b30 | ||
|
|
127588699e | ||
|
|
29c10542b1 | ||
|
|
5c9fd471a7 | ||
|
|
dd15c93f51 | ||
|
|
4003ececb2 | ||
|
|
ff3cae9db4 | ||
|
|
af44646a77 | ||
|
|
ba42285172 | ||
|
|
dff2d5996b | ||
|
|
08b17daec9 |
5
.flake8
@@ -1,5 +0,0 @@
|
||||
[flake8]
|
||||
ignore = E133,E221,E226,E228,E241,W503,ANN101,ANN102,ANN401
|
||||
per-file-ignores=tests/*:ANN
|
||||
max-line-length = 99
|
||||
exclude = docs/*
|
||||
99
.github/workflows/build.yml
vendored
@@ -1,99 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
buildAssets:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
architecture: x64
|
||||
|
||||
- name: Install Packages (apt)
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install qttools5-dev-tools latexmk texlive texlive-latex-extra
|
||||
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Packages (pip)
|
||||
run: pip install -r docs/source/requirements.txt
|
||||
|
||||
- name: Build Assets
|
||||
run: python pkgutils.py qtlrelease sample manual
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nw-assets
|
||||
path: |
|
||||
novelwriter/assets/sample.zip
|
||||
novelwriter/assets/manual.pdf
|
||||
novelwriter/assets/i18n/*.qm
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
buildLinux:
|
||||
needs: buildAssets
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.11"]
|
||||
linux-tag: ["manylinux_2_24_x86_64", "manylinux_2_28_x86_64"]
|
||||
steps:
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
architecture: x64
|
||||
|
||||
- name: Install Packages (pip)
|
||||
run: pip install python-appimage
|
||||
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nw-assets
|
||||
path: novelwriter/assets
|
||||
|
||||
- name: Build AppImage
|
||||
run: python pkgutils.py build-appimage --linux-tag ${{ matrix.linux-tag }} --python-version ${{ matrix.python-version }}
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AppImage-${{ matrix.python-version }}-${{ matrix.linux-tag }}
|
||||
path: dist_appimage
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
buildMac:
|
||||
needs: buildAssets
|
||||
runs-on: macos-12
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nw-assets
|
||||
path: novelwriter/assets
|
||||
|
||||
- name: Build App Bundle
|
||||
run: ./setup/macos/build.sh
|
||||
|
||||
- name: Upload DMG
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MacOS-DMG
|
||||
path: dist_macos
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
39
.github/workflows/build_assets.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: BuildAssets
|
||||
|
||||
on: workflow_call
|
||||
|
||||
jobs:
|
||||
buildAssets:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
architecture: x64
|
||||
|
||||
- name: Install Packages (apt)
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install qttools5-dev-tools latexmk texlive texlive-latex-extra
|
||||
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Packages (pip)
|
||||
run: pip install -r docs/source/requirements.txt
|
||||
|
||||
- name: Build Assets
|
||||
run: |
|
||||
python pkgutils.py build-assets
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nw-assets
|
||||
path: |
|
||||
novelwriter/assets/manual.pdf
|
||||
novelwriter/assets/sample.zip
|
||||
novelwriter/assets/i18n/*.qm
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
46
.github/workflows/build_linux.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
name: BuildLinux
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
buildAssets:
|
||||
uses: ./.github/workflows/build_assets.yml
|
||||
|
||||
buildLinux-AppImage:
|
||||
needs: buildAssets
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
PYTHON_VERSION: "3.12"
|
||||
LINUX_TAG: "manylinux_2_28_x86_64"
|
||||
steps:
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
architecture: x64
|
||||
|
||||
- name: Install Packages (pip)
|
||||
run: pip install python-appimage
|
||||
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nw-assets
|
||||
path: novelwriter/assets
|
||||
|
||||
- name: Build AppImage
|
||||
id: build
|
||||
run: |
|
||||
echo "BUILD_VERSION=$(python pkgutils.py version)" >> $GITHUB_OUTPUT
|
||||
python pkgutils.py build-appimage --linux-tag $LINUX_TAG --python-version $PYTHON_VERSION
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: novelWriter-${{ steps.build.outputs.BUILD_VERSION }}-Linux-AppImage
|
||||
path: dist_appimage/*.AppImage*
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
70
.github/workflows/build_mac.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
name: BuildMacOS
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
buildAssets:
|
||||
uses: ./.github/workflows/build_assets.yml
|
||||
|
||||
buildMac-AMD64:
|
||||
needs: buildAssets
|
||||
# Stay on macos-12 due to https://github.com/create-dmg/create-dmg/issues/143
|
||||
runs-on: macos-12
|
||||
env:
|
||||
PYTHON_VERSION: "3.12"
|
||||
PACKAGE_ARCH: x86_64
|
||||
MINICONDA_ARCH: x86_64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nw-assets
|
||||
path: novelwriter/assets
|
||||
|
||||
- name: Build App Bundle
|
||||
id: build
|
||||
run: |
|
||||
echo "BUILD_VERSION=$(python pkgutils.py version)" >> $GITHUB_OUTPUT
|
||||
./setup/macos/build.sh $PYTHON_VERSION $PACKAGE_ARCH $MINICONDA_ARCH
|
||||
|
||||
- name: Upload DMG
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: novelWriter-${{ steps.build.outputs.BUILD_VERSION }}-MacOS-AMD64-DMG
|
||||
path: dist_macos/*.dmg*
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
buildMac-M1:
|
||||
needs: buildAssets
|
||||
runs-on: macos-14
|
||||
env:
|
||||
PYTHON_VERSION: "3.12"
|
||||
PACKAGE_ARCH: aarch64
|
||||
MINICONDA_ARCH: arm64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nw-assets
|
||||
path: novelwriter/assets
|
||||
|
||||
- name: Build App Bundle
|
||||
id: build
|
||||
run: |
|
||||
echo "BUILD_VERSION=$(python pkgutils.py version)" >> $GITHUB_OUTPUT
|
||||
./setup/macos/build.sh $PYTHON_VERSION $PACKAGE_ARCH $MINICONDA_ARCH
|
||||
|
||||
- name: Upload DMG
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: novelWriter-${{ steps.build.outputs.BUILD_VERSION }}-MacOS-M1-DMG
|
||||
path: dist_macos/*.dmg*
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
62
.github/workflows/build_win.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: BuildWindows
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
buildAssets:
|
||||
uses: ./.github/workflows/build_assets.yml
|
||||
|
||||
buildWin64:
|
||||
needs: buildAssets
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
architecture: x64
|
||||
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nw-assets
|
||||
path: novelwriter/assets
|
||||
|
||||
- name: Build Setup Installer
|
||||
id: build
|
||||
run: |
|
||||
echo "BUILD_VERSION=$(python pkgutils.py version)" >> $Env:GITHUB_OUTPUT
|
||||
python pkgutils.py build-win-exe
|
||||
|
||||
- name: Upload Unsigned Artifacts
|
||||
id: upload-unsigned-artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: novelWriter-${{ steps.build.outputs.BUILD_VERSION }}-Win-Setup
|
||||
path: dist/*.exe
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
- name: Submit Signing Request
|
||||
uses: signpath/github-action-submit-signing-request@v1
|
||||
with:
|
||||
api-token: "${{ secrets.SIGNPATH_API_TOKEN }}"
|
||||
organization-id: "0471e52c-66fa-4e9a-bfb9-36167095ca3f"
|
||||
project-slug: "novelWriter"
|
||||
signing-policy-slug: "release-signing "
|
||||
github-artifact-id: "${{ steps.upload-unsigned-artifact.outputs.artifact-id }}"
|
||||
wait-for-completion: true
|
||||
output-artifact-directory: "dist/"
|
||||
parameters: |
|
||||
version: "${{ steps.build.outputs.BUILD_VERSION }}"
|
||||
|
||||
- name: Upload Signed Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: novelWriter-${{ steps.build.outputs.BUILD_VERSION }}-Win-Setup-Signed
|
||||
path: dist/*.exe
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
9
.github/workflows/test_linux.yml
vendored
@@ -14,7 +14,8 @@ jobs:
|
||||
testLinux:
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Python Setup
|
||||
@@ -32,11 +33,13 @@ jobs:
|
||||
run: |
|
||||
pip install -U -r requirements.txt -r tests/requirements.txt
|
||||
- name: Run Build Commands
|
||||
run: python pkgutils.py qtlrelease sample
|
||||
run: |
|
||||
python pkgutils.py qtlrelease
|
||||
python pkgutils.py sample
|
||||
- name: Run Tests
|
||||
run: |
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
pytest -v --cov=novelwriter --timeout=60
|
||||
python -m pytest -v --cov=novelwriter --timeout=60
|
||||
- name: Upload to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
env:
|
||||
|
||||
4
.github/workflows/test_mac.yml
vendored
@@ -12,7 +12,7 @@ on:
|
||||
|
||||
jobs:
|
||||
testMac:
|
||||
runs-on: macos-latest
|
||||
runs-on: macos-13
|
||||
steps:
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v5
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Run Tests
|
||||
run: |
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
pytest -v --cov=novelwriter --timeout=60
|
||||
python -m pytest -v --cov=novelwriter --timeout=60
|
||||
- name: Upload to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
env:
|
||||
|
||||
2
.github/workflows/test_win.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
pip install -U -r requirements.txt -r tests/requirements.txt
|
||||
- name: Run Tests
|
||||
run: |
|
||||
pytest -v --cov=novelwriter --timeout=60
|
||||
python -m pytest -v --cov=novelwriter --timeout=60
|
||||
- name: Upload to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
env:
|
||||
|
||||
548
CHANGELOG.md
@@ -1,5 +1,553 @@
|
||||
# novelWriter Changelog
|
||||
|
||||
## Version 2.6 Beta 2 [2024-12-23]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a beta release of the next release version, and is intended for testing purposes. Please be
|
||||
careful when using this version on live writing projects, and make sure you take frequent backups.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**New Features**
|
||||
|
||||
* The project tree has been completely rewritten under the hood. The main difference in the GUI is
|
||||
a lifting of restrictions on drag and drop. You can now select multiple items in multiple places
|
||||
in the tree, and drag them to a new location. It is still not allowed to drag root level items,
|
||||
or drop items on the root level. PR #2119.
|
||||
* You can now drag and drop items from the project tree onto the editor and viewer to load the
|
||||
documents there. PR #2119.
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Make line height in DocX scale correctly. Issue #2099. PR #2102.
|
||||
* Make margins scale with font size in ODT and HTML output. PR #2102.
|
||||
* Fix DocX page count to work with Office 365. PR #2102.
|
||||
* Fix font scaling issues for PDF output. Issue #2100. PR #2104.
|
||||
* Fix an issue that cleared the editor when the return key was used on a folder item. PR #2113.
|
||||
* Fix an issue where the viewer and preview would not reset text emphasis when selecting a default
|
||||
font style with emphasis features. Issue #2121. PR #2122.
|
||||
* Change how custom fonts are loaded to ensure that the Qt framework don't take shortcuts by using
|
||||
a similar font instead of the chosen font. This is a side effect of the Qt font matching feature.
|
||||
Issue #2118. PR #2122.
|
||||
|
||||
**Improvements**
|
||||
|
||||
* Move processing of alternative apostrophe and dash to a later point in the tokenization process.
|
||||
It needs to happen after dialogue is processed to work as intended. PR #2095.
|
||||
* Use icons for text margin settings in Build Settings. Issue #2098. PR #2102.
|
||||
* Replace the toolbar icon in the editor. PR #2103.
|
||||
* Turn off auto-default button on the Build dialog. Issue #2101. PR #2105.
|
||||
* Add ANSI colours to log output for easier debugging. PRs #2114 and #2117.
|
||||
* Document header is now aligned to the bottom of the top page margin in the same way for ODT and
|
||||
DocX output. Issue #2120. PR #2128.
|
||||
* Dialogue detection for quoted dialogue has been improved to better support Chinese, and other
|
||||
languages that don't use whitespaces to separate words. Some improvements have also been made to
|
||||
how single quoted dialogues are processed when apostrophes are present. Issue #2131. PR #2138.
|
||||
|
||||
**Code Improvements**
|
||||
|
||||
* Completely rewrite the project tree into a model/view set with one single definition if the
|
||||
project structure. PR #2109.
|
||||
* The auto-replace feature in the editor has been refactored. It is now better separated from the
|
||||
editor code, and may have some minor performance improvements. Issue #2129. PR #2132.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.6 Beta 1 [2024-11-12]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a beta release of the next release version, and is intended for testing purposes. Please be
|
||||
careful when using this version on live writing projects, and make sure you take frequent backups.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**New Features**
|
||||
|
||||
* Added PDF build format. Issue #2046. PR #2048.
|
||||
* Added DocX (MS Word) format. Issue #1537. PR #2056.
|
||||
* The Build settings tool has the following changes: Ability to control page break and centring of
|
||||
main titles, an option to disable styling for headings altogether, and the ODT section has been
|
||||
generalised to apply to all document formats. Issue #2023. PR #2045.
|
||||
* Text and heading margin can now be control in the Manuscript Build tool. Issue #2023. PR #2051.
|
||||
* Word counts and other such statistics can now be inserted into the manuscript. This is done
|
||||
through new insert actions in the Insert menu, and processed at build time. Issue #2024.
|
||||
PR #2073.
|
||||
* Forced line breaks can now be inserted as a shortcode. This is useful when line breaks in
|
||||
paragraphs are ignored when building the manuscript. Issue #1991. PR #2063.
|
||||
* A new `@mentions` keyword has been added that can list any tag in the project as being mentioned
|
||||
in the current section. These are listed separately from tags present in the story section.
|
||||
Issue #1822. PR #2064.
|
||||
* Tags in novel documents can now be referenced with the `@story` keyword. Issue #1990. PR #2072.
|
||||
* URLs starting with http/https are now recognised and clickable in the editor, viewer, and
|
||||
manuscript preview. Issue #1426. PR #2067.
|
||||
* Added dialogue highlighting for Portuguese and Polish dialogue styles. Issues #2066 and #2070.
|
||||
Related to #1773. PRs #2068, #2079, #2081 and #2082.
|
||||
* Four dashes in the editor are now replaced by a horizontal bar. This is useful as a replacement
|
||||
symbol for em dash when using dialogue highlighting to avoid triggering it. The horizontal bar is
|
||||
replaced with an em dash in the manuscript. Issue #2070. PR #2079.
|
||||
* Manuscript Build settings can now be duplicated. Issue #1931. PR #2084.
|
||||
* Page breaks can optionally be made visible in the Manuscript preview. PR #2086.
|
||||
* The document status label can now be selected in the Outline View. Issue #1909. PR #2088.
|
||||
* The document viewer now has an edit button to open the document in the editor. Issue #1963.
|
||||
PR #2089.
|
||||
|
||||
**User Interface**
|
||||
|
||||
* The Manuscript Build settings have now been moved into a single scrollable page, using the same
|
||||
layout as in Preferences. The heading and filtering pages are still separate forms, as they are
|
||||
of a more complex nature. PR #2031.
|
||||
* The currently open document in the editor is now highlighted in the project tree, just like it is
|
||||
in the novel view. Issue #1981. PR #2077.
|
||||
* The details panel in the Outline view is now resizable. PR #2078.
|
||||
|
||||
**Improvements**
|
||||
|
||||
* Add an option to ignore a word in the spell checker. An ignored word is ignored only for the
|
||||
current writing session. PR #2030.
|
||||
* Word counts and other such statistics is now exported as custom variables to ODT files, and can
|
||||
be inserted in the text in LibreOffice, and similar. Issue #2033. PR #2035.
|
||||
|
||||
**Code Improvements**
|
||||
|
||||
* Added Python 3.13 coverage to ensure the new Python release is supported. Issue #2040. PR #2044.
|
||||
* Preparation for Qt6: Clean up Qt enums. PR #2025.
|
||||
* Preparation for Qt6: Replace Qt regular expression tools with the internal Python re module for
|
||||
markup processing and syntax highlighting. It is both slightly faster, and there are issues with
|
||||
text encoding in at least some versions of Qt6 or PyQt6. PRs #2028 and #2043.
|
||||
* Preparation for Qt6: Added a wrapper function for connecting signals to slots that has a
|
||||
different function signature. Python lambdas generate warnings inn Qt6. PR #2075.
|
||||
* Refactored manuscript formats and moved most of the processing to the Tokenizer class to simplify
|
||||
the format classes and also make them more consistent. PRs #2060, #2061 and #2062.
|
||||
* The document builder has been refactored to support more generalised format classes. PR #2047.
|
||||
* Action parent assignment has been rafactored in the main menu. #2075.
|
||||
* Raw text format output has been refactored and reduced to just appending documents. PR #2087.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.5.3 [2024-11-26]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a patch release that fixes a few minor bugs in the user interface, and with the HTML
|
||||
manuscript format. This patch also adds a Russian translation, and updated the German and
|
||||
Portuguese translations.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fixed the red/green LEDs on the statusbar for the Default Light theme. The colours were swapped.
|
||||
Issue #2057. PR #2059.
|
||||
* Moved the styles tag into the head tag for HTML manuscript output, which is the correct placement
|
||||
for them. Issue #2080. PR #2085.
|
||||
* Fixed a bug in the project tree where it was possible to drag content to root level on some Qt
|
||||
versions where the disallow flag is not obeyed. The illegal action is now additionally blocked by
|
||||
code. Issue #2108. PR #2109.
|
||||
|
||||
**Documentation**
|
||||
|
||||
* Updated a dead link to the spell check library with the new one. Issue #2042. PR #2059.
|
||||
|
||||
**Internationalisation**
|
||||
|
||||
* Russian translation added by Konstantin Tan (@k1kimosha). PR #2126
|
||||
* Updated German and Portuguese translations. PR #2126
|
||||
|
||||
----
|
||||
|
||||
## Version 2.5.2 [2024-09-17]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a patch release that fixes a series of issues mostly affecting dialogue highlighting in the
|
||||
document viewer. The way the text is formatted in the viewer changed a lot in 2.5, and there were a
|
||||
few issues with the new implementation. The tab stop distance setting was also ignored, but has now
|
||||
been fixed as well.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fixed an issue where the tab stop distance setting was being ignored in the document viewer. It
|
||||
must be set again every time a document is loaded. Issue #1996. PR #2014.
|
||||
* Fixed an issue with overlapping formatting markers when processing text into new formats. This
|
||||
issues was introduced when dialogue highlighting was added to the document viewer and manuscript
|
||||
build. It arises because start and end of dialogue can occur on the same character as other
|
||||
formatting, and then the order these markers are processed matters. This was not properly handled
|
||||
in the code. Issue #2012. PR #2014.
|
||||
* Dialogue highlighting is now only applied to plain text paragraphs, not comments, headings, and
|
||||
other places where there should be no dialogue. Issue #2013. PR #2014.
|
||||
* Note documents no longer get dialogue highlighting. Issue #2011. PR #2014.
|
||||
|
||||
**Documentation**
|
||||
|
||||
* Added a section about spell checking in the documentation. PR #2015.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.5.1 [2024-07-28]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a patch release that fixes an issue with the lock file being left in the project when the
|
||||
project open is cancelled, a few issues with custom input boxes in Preferences, and a usability
|
||||
issue when selecting to edit a tag or reference from the Tags and References panel as well as fixed
|
||||
an issue with the Importance labels not being updated in the tabs for tags.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fixes an issue where the project lock file was created before certain checks where the user could
|
||||
cancel the project open process, leaving a lock file in the project folder behind. Issue #1977.
|
||||
PR #1978.
|
||||
* Fixes an issue where the user could add spaces to the pad before and after Preference settings,
|
||||
which would pad every space entered into the text. The Preferences settings no longer accept any
|
||||
white spaces in these boxes (they are removed on save) and also strips duplicate character
|
||||
entries. Issue #1985. PR #1986.
|
||||
* The narrator break and dialog symbol Preference text boxes will now be cleared if the settings is
|
||||
a white space. PR #1986.
|
||||
* Fixed an issue where Importance labels were not updated in the viewer panel's tags tabs when they
|
||||
where changed in Project Settings. Issue #1992. PR #1993.
|
||||
|
||||
**Usability**
|
||||
|
||||
* When selecting to edit a tag or reference from the panel below the Document Viewer, the editor
|
||||
now scrolls to the relevant heading as it does in the viewer. Issue #1983. PR #1987.
|
||||
|
||||
**Internationalisation**
|
||||
|
||||
* Latin American Spanish translation updated by Tommy Marplatt (@tmarplatt). PR #1989.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.5 [2024-07-10]
|
||||
|
||||
### Release Notes
|
||||
|
||||
The 2.5 release fixes a number of minor issues from the RC 1 pre-release, and updates most
|
||||
translation files. Polish has also been added.
|
||||
|
||||
See the website for complete [Release Notes](https://novelwriter.io/releases/release_2_5.html).
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fix an issue with unresponsiveness when switching from Outline View to Tree View with a keyboard
|
||||
shortcut. Issue #1949. PR #1954.
|
||||
* Fix an issue with switching focus between editor and viewer when the viewer is hidden.
|
||||
Issue #1950. PR #1954.
|
||||
* Fix an issue with first line indentation where it would sometimes indent first paragraph when it
|
||||
should not. Issue #1965. PR #1971.
|
||||
|
||||
**Usability**
|
||||
|
||||
* Remove the "Apply" button from Preferences as changing theme does not updated the Preferences
|
||||
dialog, which is unexpected behaviour. The Preferences dialog is now also consistent with other
|
||||
settings dialogs. Issue #1951. PR #1954.
|
||||
* Improved the error messages when opening a project fails. Issue #1944. PR #1956.
|
||||
* Make sure the Project Name is selected and in focus when switching to the New Project Form on the
|
||||
Welcome dialog. Issue #1967. PR #1968.
|
||||
|
||||
**Improvements**
|
||||
|
||||
* Add first line indentation to Manuscript previews. Issue #1961. PR #1962.
|
||||
|
||||
**Internationalisation**
|
||||
|
||||
* Norwegian and US English translations updated by @vkbo. PR #1955.
|
||||
* German translation updated by Myian (@HeyMyian). PR #1955.
|
||||
* Italian translation updated by Lou Cyper (loucyper1). PR #1955.
|
||||
* Dutch translation updated by Martijn van der Kleijn (mvdkleijn). PR #1955.
|
||||
* Chinese translation updated by @longqzh. PR #1955.
|
||||
* Portuguese translation updated by Oli Maia. PR #1955.
|
||||
* Japanese translation updated by @hebekeg. PR #1955.
|
||||
* French translation updated by Albert Aribaud (@aaribaud). PR #1955.
|
||||
* Polish translation added by Anna Maria Polak (@Nauthiz). PR #1955.
|
||||
|
||||
**Packaging**
|
||||
|
||||
* Rewrote the packaging utilities script. Windows builds are now created in GitHub actions, which
|
||||
is needed for signed packages when this is enabled. PRs #1958 and #1959.
|
||||
|
||||
**Documentation**
|
||||
|
||||
* Updated the documentation for 2.5. PR #1928.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.5 RC 1 [2024-06-22]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a release candidate of the next release version, and is intended for testing purposes.
|
||||
Please be careful when using this version on live writing projects, and make sure you take frequent
|
||||
backups.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* The Status bar LEDs are now properly updated when the theme changes. Issue #1893. PR #1906.
|
||||
* All HTML tags are now properly closed at the end of each paragraph in HTML output. After
|
||||
shortcodes were introduced, it was possible to leave formatting tags open. Issue #1919. PR #1926.
|
||||
|
||||
**Improvements**
|
||||
|
||||
* Move the first line indent setting from being an Open Document feature to a general build
|
||||
settings feature that also applies to HTML, and make it visible in the Manuscript build tool
|
||||
preview. Issue #1839 and #1858. PR #1898.
|
||||
* Make sure the document in the editor is saved before the same document is opened in the viewer.
|
||||
Issue #1884. PR #1902.
|
||||
* The project name now appears before "novelWriter" in the main window title, which improves the
|
||||
task bar label on at least Linux Mint Cinnamon, and Windows. Issue #1910. PR #1911.
|
||||
* Dialogue highlighting now only applies to novel documents, not notes. It is also possible to
|
||||
apply it to HTML and ODT manuscripts, and it also shows up in the preview and in the document
|
||||
viewer. Issue #1774. PR #1908.
|
||||
* The Welcome dialog and other tools that use the project name to generate files of folder names
|
||||
are now less restrictive on what characters it allows in the file or folder names. Issue #1917.
|
||||
PR #1922.
|
||||
* Last used folder paths are now remembered individually for each tool or feature that requires
|
||||
path input from the user. Issues #1930 and #1933. PR #1934.
|
||||
* The Manuscript preview will now show line height as set in build settings. Issue #1920. PR #1935.
|
||||
* Global search now refreshes if any of the search option buttons are toggled, and the search
|
||||
result will show the complete word if the search term only matches part of a word. Issue #1830.
|
||||
PR #1936.
|
||||
* When a new note is created from a reference tag in the editor, the syntax highlighting is
|
||||
properly updated to indicate the tag is now valid. Issue #1916. PR #1938.
|
||||
* The `Ctrl+E` shortcut now toggles focus between editor and viewer instead of just going to the
|
||||
editor. The header text colour changes to indicate which panel has focus. This should make it
|
||||
easier to scroll the content of the viewer without having to click it with the mouse first.
|
||||
Issue #1387. PRs #1940 and #1941.
|
||||
|
||||
**Code Improvements**
|
||||
|
||||
* Change how dialogs are handled in memory, and drop the calls to deleteLater for the underlying Qt
|
||||
object as it caused problems in some cases. Instead, the dialog is disconnected from the parent
|
||||
object, which seems to let the Python and Qt garbage collectors to kick in.
|
||||
PRs #1899. #1913 and #1921.
|
||||
* Overload the reject call for dialogs rather to call close, which the default implementation does
|
||||
not. This simplifies the logic when closing dialogs, as reject() is also a slot, which close() is
|
||||
not. Issue #1915. PR #1918.
|
||||
* Processing of dialogue highlighting has been added to the Tokenizer class, and the RegEx handling
|
||||
moved to a separate factory class. PR #1908.
|
||||
* The progress bar widgets have been moved to a single module, and test coverage added. PR #1937.
|
||||
|
||||
**Packaging**
|
||||
|
||||
* The Windows installer is now built with Inno Setup 6.3, and uses zip compression rather than
|
||||
lzma. It also properly sets the undelete icon, and the undelete process is better at cleaning up
|
||||
files. PR #1932.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.5 Beta 1 [2024-05-26]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a beta release of the next release version, and is intended for testing purposes. Please be
|
||||
careful when using this version on live writing projects, and make sure you take frequent backups.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**General Changes**
|
||||
|
||||
* novelWriter now requires Python 3.9 and Qt 5.15 as a minimum. That means Ubuntu 20.04 and older
|
||||
are no longer supported for the Debian packages. Users on Ubuntu 20.04 and equivalent Linux
|
||||
distros must use the AppImage. PRs #1826 and #1833.
|
||||
|
||||
**Major Features**
|
||||
|
||||
* Status and Importance icons can now be assigned a shape in addition to a colour. Issue #1786.
|
||||
PRs #1810 and #1819.
|
||||
* Footnotes have been added. They use a modified comment format for specifying the footnote text,
|
||||
and a shortcode for inserting the footnote into the text. They are linked via a key. If the
|
||||
footnote is inserted via the **Insert** menu, a unique key is generated. Issue #342. PR #1832.
|
||||
* Comments in general now support formatting, so format tags work just like in regular text. This
|
||||
was needed for footnotes, but has been expanded to include all comments. PR #1832.
|
||||
* Two new themes have been added. Dracula is available as a set for both the GUI and the editor.
|
||||
Snazzy Light is available for syntax only, but works well with the default light GUI theme.
|
||||
PR #1840.
|
||||
* Character dialogue highlighting has been completely redesigned. The highlighting rule now
|
||||
specifically relates to dialogue, and not just quoted text in general. To that effect, more rules
|
||||
for detecting what is and isn't dialogue has been added. This is designed to support difference
|
||||
between dialogue conventions in different languages. Issues #1770 and #1771. PR #1864.
|
||||
* The font settings in Preferences now considers the full range of font options, in particular font
|
||||
style and weight. The changes include the font size in these settings, so the additional setting
|
||||
for font size has been removed. Use the font dialog to pick size as well. Due to this removal,
|
||||
the font size has been reset to default and must be set again by the user. Issue #1733. PR #1881.
|
||||
* The document viewer and the manuscript preview now uses a completely new class to generate the
|
||||
formatted text. The old method used an outdated HTML format as the go-between, which restricted
|
||||
what formatting could be applied. The main noticeable change to users at the moment should be the
|
||||
size of headings, that now match the size in the editor. Issue #1882. PR #1892.
|
||||
|
||||
**Improvements**
|
||||
|
||||
* The default dark theme has been redesigned to match the GUI theme a little better, and is now
|
||||
also consistent with the default light themes. PRs #1836 and #1840.
|
||||
* Special comments now have a different text colour than plain comments. PR #1836.
|
||||
* The various Tomorrow themes are now a little more consistent in what colours are used for which
|
||||
components. More variation has also been added. PR #1840.
|
||||
* The Tango theme has been updated. PR #1840.
|
||||
* The last cursor position is now always saved when a document is closed in the editor, even if the
|
||||
content has not been changed. PR #1849.
|
||||
* The settings for first line indent have now been extended to allow setting how deep the indents
|
||||
are and whether or not to indent the first paragraph after a heading or break. The settings have
|
||||
also moved from being Open Document specific to the general formatting tab for manuscripts.
|
||||
PR #1857.
|
||||
* Preserving in-paragraph line breaks is now a general Manuscript setting that applies to all
|
||||
output formats. PR #1891.
|
||||
* The Manuscript builds now also uses the full font settings of the selected output font, not just
|
||||
the font family and size option. Since the size option has been merged into the general font
|
||||
choice, the separate font size setting has been dropped and users must set it again. PR #1891.
|
||||
* It is now possible to disable the usage of the font selection dialog from your operating system.
|
||||
At least on Linux Gnome desktops, the system's font dialog lacks a lot of the selection options
|
||||
available in the font dialog provided with Qt. PR #1891.
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fixed an issue where Manuscript dialogs would be left open if the project was closed. PR #1844.
|
||||
* First line indents are no longer reset after a comment. Issue #1852. PR #1857.
|
||||
|
||||
**Packaging**
|
||||
|
||||
* Minimal zip file release packages can no longer be built from the package utility script. The zip
|
||||
file needed for building the Windows installer is still available. PR #1826.
|
||||
* Added build packages for AARCH64 on MacOS. It seems some dependencies still prevents it from
|
||||
being installed cleanly without requiring some virtualisation feature, but it works. PR #1829.
|
||||
* AppImages are now released with Python 3.12. PR #1829.
|
||||
|
||||
**Other Changes**
|
||||
|
||||
* A new GUI theme setting for error text has been added. It is used when error messages need to be
|
||||
displayed on the GUI. PR #1880.
|
||||
|
||||
**Code Improvements**
|
||||
|
||||
* The behaviour of dialogs across various platforms has been unified and improved a little to
|
||||
ensure more consistent behaviour. It is mostly related to modality and z-order. There are still
|
||||
limitations due to platform restrictions, like non-modal dialogs being stuck on top on Linux
|
||||
Wayland. PR #1844.
|
||||
* Some GUI components have been improved and refactored to rely more on signals and slots rather
|
||||
than reaching into each other's classes and calling methods. This is a little more robust.
|
||||
PR #1849.
|
||||
* The text tokenizer used to parse the formatting codes in novelWriter has been refactored and
|
||||
improved. In particular, multi-line paragraphs are now processed during the second pass of
|
||||
tokenization rather than when the final format is applied. This allows a much more compact format
|
||||
of the token data, and avoid potential inconsistencies between the various output formats.
|
||||
PR #1885.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.4.4 [2024-06-12]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a patch release that fixes a usage issue when setting document label from an unsaved
|
||||
document, fixes a rare chance of a crash when closing the Manuscript tool, and updates the
|
||||
Portuguese translation.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Backported some memory improvements from the upcoming 2.5 release. This also fixes a potential,
|
||||
but low probability crash in the Manuscript tool. If the tool is closed during the milliseconds
|
||||
long window when the clock on the yellow label is updated, the app can crash with a segmentation
|
||||
fault. PRs #1903 and #1905.
|
||||
* Fixed an issue where changing a document's label to match the document heading would suggest the
|
||||
wrong title if the document was open in the editor, but in an unsaved state. An easy condition to
|
||||
encounter when creating a new document and setting the heading first. Issue #1914. PR #1923.
|
||||
|
||||
**Internationalisation**
|
||||
|
||||
* Portuguese translation updated by Oli Maia. PR #1904.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.4.3 [2024-05-20]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a patch release that fixes issues with the document font in the editor, viewer and
|
||||
manuscript preview on some Linux distros, and also fixes a potential crash on Windows when using
|
||||
the spell check dictionary install tool.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fixed a crash in the dictionaries install tool on Windows if the config folder reported by the
|
||||
third party Enchant spell checker tool didn't already exist prior to adding new dictionaries.
|
||||
The folder is now created when the tool is opened if it doesn't exist. Issue #1874. PR #1876.
|
||||
* Fixed issues when setting a different text font for the editor and viewer, and related issues
|
||||
with the preview in the Manuscript Build tool, on certain platforms. Changing the font and
|
||||
setting non-standard font sizes produced unexpected results when reloading. The issue seems to be
|
||||
related to Qt 5.15.3, but that is not fully confirmed. However, the only place so far where the
|
||||
issue is observed is on Mint 21.3. Issues #1862 and #1875. PR #1877.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.4.2 [2024-05-18]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a patch release that fixes two minor font issues and updates the Dutch and Chinese
|
||||
translations.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Change the preview widget in the Manuscript Build tool to use the document font only for the
|
||||
document itself, not the yellow heading stating the age of the previewed text. PR #1863.
|
||||
* Fixes the syntax highlighter so that it is re-initialised when the document editor is
|
||||
re-initialised, so that changes to document font size regenerates the heading font sizes as well.
|
||||
Issue #1865. PR #1866.
|
||||
|
||||
**Internationalisation**
|
||||
|
||||
* Dutch translation updated by Martijn van der Kleijn (@mvdkleijn). PR #1872.
|
||||
* Chinese translation updated by @longqzh. PR #1872.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.4.1 [2024-05-06]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a patch release that fixes a number of minor issues with the Manuscript Build tool. The
|
||||
only critical fix is related to a potential crash when deleting a build entry when its settings
|
||||
dialog is still open.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fixed an issue that could crash novelWriter if a build settings entry was deleted from the
|
||||
Manuscript tool while its settings window was open. PR #1845.
|
||||
|
||||
**Improvements**
|
||||
|
||||
* Changed the font used for the document editor and viewer header and footer from the one used for
|
||||
the document text to the one used for the user interface. Issue #1842. PR #1843.
|
||||
* Added a save document step in the editor before running a manuscript build or a preview job. This
|
||||
ensures that the text in the editor is included in the manuscript. Issue #1835. PR #1846.
|
||||
* Restore preview panel scroll bar position after updating the preview on the Manuscript tool.
|
||||
Issue #1837. PR #1846.
|
||||
* Close all non-modal dialogs when a project is closed. PR #1848.
|
||||
|
||||
**Code Improvements**
|
||||
|
||||
* Fixed an issue with the Build Settings dialog that blocks the garbage collector from deleting the
|
||||
dialog after it's been closed. PR #1843.
|
||||
* Remove some deprecated translation entries from the translation files. PR #1850.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.4 [2024-04-20]
|
||||
|
||||
### Release Notes
|
||||
|
||||
60
CREDITS.md
@@ -2,69 +2,75 @@
|
||||
|
||||
## Main Developer
|
||||
|
||||
* Veronica Berglyd Olsen (@vkbo)
|
||||
* Veronica Berglyd Olsen
|
||||
|
||||
## Contributors
|
||||
|
||||
* Concept: Marian Lückhof (@Number042)
|
||||
* Internationalisation: Bruno Meneguello (@bkmeneguello)
|
||||
* Setup and Packaging: Rachel Powers (@Ryex)
|
||||
* Early Concept: Marian Lückhof
|
||||
* Internationalisation: Bruno Meneguello
|
||||
* Setup and Packaging: Rachel Powers
|
||||
|
||||
For other contributions, see the project's [Contributors](https://github.com/vkbo/novelWriter/graphs/contributors) page.
|
||||
|
||||
## Artwork
|
||||
|
||||
The artwork on the Welcome dialog was created by [Louis Durrant](https://louisdurrant.art).
|
||||
The artwork on the Welcome dialog was created by Louis Durrant.
|
||||
|
||||
## Translations
|
||||
|
||||
The default language is English (UK) with English (US) as an option. These are the original
|
||||
translators for the languages currently available:
|
||||
|
||||
* Dutch: Martijn van der Kleijn (@mvdkleijn)
|
||||
* French: Jan Lüdke (@jyhelle)
|
||||
* German: Myian (@heymyian)
|
||||
* Italian: Riccardo Mangili
|
||||
* Japanese: hebekeg (@hebekeg)
|
||||
* Latin American Spanish: Tommy Marplatt (@tmarplatt)
|
||||
* Norwegian: Veronica Berglyd Olsen (@vkbo)
|
||||
* Portuguese: Bruno Meneguello (@bkmeneguello)
|
||||
* Simplified Chinese: Qianzhi Long (@longqzh)
|
||||
* **Dutch:** Martijn van der Kleijn (mvdkleijn)
|
||||
* **French:** Jan Lüdke (jyhelle)
|
||||
* **German:** Myian (HeyMyian)
|
||||
* **Italian:** Riccardo Mangili
|
||||
* **Japanese:** hebekeg
|
||||
* **Latin American Spanish:** Tommy Marplatt (tmarplatt)
|
||||
* **Norwegian:** Veronica Berglyd Olsen (vkbo)
|
||||
* **Polish:** Anna Maria Polak (Nauthiz)
|
||||
* **Portuguese:** Bruno Meneguello (bkmeneguello)
|
||||
* **Russian:** Konstantin Tan (k1kimosha)
|
||||
* **Simplified Chinese:** Qianzhi Long (longqzh)
|
||||
|
||||
Additional larger translation contributions:
|
||||
|
||||
* French: Albert Aribaud (@aaribaud)
|
||||
* **French:** Albert Aribaud (aaribaud)
|
||||
* **Portuguese:** Oli Maia (olimaia)
|
||||
|
||||
Translations are managed on [Crowdin](https://crowdin.com/project/novelwriter), and more
|
||||
contributions are listed on the project's [Members](https://crowdin.com/project/novelwriter/members) page.
|
||||
contributions are listed on the project's Members page.
|
||||
|
||||
## Libraries
|
||||
|
||||
The following libraries are dependencies of novelWriter:
|
||||
|
||||
* [Qt5](https://www.qt.io) by Qt Company
|
||||
* [PyQt5](https://www.riverbankcomputing.com/software/pyqt) by Riverbank Computing
|
||||
* [Enchant](https://abiword.github.io/enchant) by Dom Lachowicz
|
||||
* [PyEnchant](https://pyenchant.github.io/pyenchant) by Dimitri Merejkowsky
|
||||
* **Qt5** by Qt Company
|
||||
* **PyQt5** by Riverbank Computing
|
||||
* **Enchant** by Dom Lachowicz
|
||||
* **PyEnchant** by Dimitri Merejkowsky
|
||||
|
||||
## Assets
|
||||
|
||||
Some of the assets bundled with novelWriter were adapted from the following sources:
|
||||
|
||||
* [Typicons](https://github.com/stephenhutchings/typicons.font) icons by Stephen Hutchings (CC BY-SA 4.0)
|
||||
* [Tomorrow](https://github.com/chriskempson/base16) syntax themes by Chris Kempson (MIT License)
|
||||
* [Owl](https://github.com/sdras/night-owl-vscode-theme) syntax themes by Sarah Drasner (MIT License)
|
||||
* [Solarized](https://github.com/altercation/solarized) themes by Ethan Schoonover (MIT License)
|
||||
* **Typicons** 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 (MIT License)
|
||||
* **Cyberpunk Night** theme by Anders Lemvigh (CC BY-SA 4.0)
|
||||
* **Dracula** theme by Zeno Rocha (MIT License)
|
||||
* **Snazzy Light** theme by Florian Reuschel (MIT License)
|
||||
|
||||
## Fonts
|
||||
|
||||
The font used for the main novelWriter logo, mimetype and text banners is Pridi. Other fonts are
|
||||
used on buttons and icons.
|
||||
|
||||
* Pridi by Cadson Demak (Open Font License, Version 1.1)
|
||||
* Source Sans Pro by Paul D. Hunt (SIL Open Font License)
|
||||
* **Pridi** by Cadson Demak (Open Font License, Version 1.1)
|
||||
* **Source Sans Pro** by Paul D. Hunt (SIL Open Font License)
|
||||
|
||||
## Special Mentions
|
||||
|
||||
Additional thanks to @johnblommers who was an early user and who has provided a lot of very useful
|
||||
Additional thanks to John Blommers who was an early user and who has provided a lot of very useful
|
||||
feedback over the years.
|
||||
|
||||
15
README.md
@@ -29,11 +29,20 @@ documentation.
|
||||
* PyPi Project: [pypi.org/project/novelWriter](https://pypi.org/project/novelWriter)
|
||||
* Social Media: [fosstodon.org/@novelwriter](https://fosstodon.org/@novelwriter)
|
||||
|
||||
## Sponsors
|
||||
|
||||
<table style="border: none;">
|
||||
<tr>
|
||||
<td><img align="left" style="height: 25px;" src="https://raw.githubusercontent.com/vkbo/novelWriter/main/setup/signpath_logo.png"></td>
|
||||
<td>Free code signing on Windows provided by <a href="https://about.signpath.io/">SignPath.io</a>, certificate by <a href="https://signpath.org/">SignPath Foundation</a>.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Implementation
|
||||
|
||||
novelWriter is written with Python 3 (3.8+) using Qt5 and PyQt5 (5.10+), and is released on Linux,
|
||||
Windows and macOS. It can in principle run on any Operating System that also supports Qt, PyQt and
|
||||
Python.
|
||||
novelWriter is written with Python 3 (3.9+) using Qt5 and PyQt5 (5.15 only), and is released on
|
||||
Linux, Windows and macOS. It can in principle run on any Operating System that also supports Qt,
|
||||
PyQt and Python.
|
||||
|
||||
## Project Contributions
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 185 KiB |
@@ -16,13 +16,21 @@ This is a list of hopefully helpful little tips on how to get the most out of no
|
||||
Managing the Project
|
||||
====================
|
||||
|
||||
.. dropdown:: Create a Project from a Template
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
On the Welcome dialog's **Create New Project** form, you can select to "Prefill Project" from
|
||||
the content of a different project. This feature is most useful if you copy a project you have
|
||||
dedicated to be a template project. If you have a structure and settings you want to use for
|
||||
every new project, this is the best solution.
|
||||
|
||||
.. dropdown:: Merge Multiple Documents Into One
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
If you need to merge a selection of documents in your project into a single document, you can
|
||||
achieve this by first making a new folder for just that purpose, and drag all the files you want
|
||||
merged into this folder. Then you can right click the folder, select :guilabel:`Transform` and
|
||||
:guilabel:`Merge Documents in Folder`.
|
||||
achieve this by first making a new folder for just that purpose, and drag all the documents you
|
||||
want merged into this folder. Then you can right click the folder, select :guilabel:`Transform`
|
||||
and :guilabel:`Merge Documents in Folder`.
|
||||
|
||||
In the dialog that pops up, the documents will be in the same order as in the folder, but you
|
||||
can rearrange them here of you wish. See :ref:`a_ui_tree_split_merge` for more details.
|
||||
@@ -31,6 +39,23 @@ Managing the Project
|
||||
Layout Tricks
|
||||
=============
|
||||
|
||||
.. dropdown:: Align Paragraphs with Line Breaks
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
If you have line breaks in you paragraphs, and also want to apply additional text alignment or
|
||||
indentation, you must apply the alignment tags to the first line.
|
||||
|
||||
For example, this will centre the two lines.
|
||||
|
||||
.. code-block:: md
|
||||
|
||||
>> Line one is centred. <<
|
||||
Line two is also centred.
|
||||
|
||||
This text is not centred, because it is a new paragraph.
|
||||
|
||||
See :ref:`a_fmt_align` for more details.
|
||||
|
||||
.. dropdown:: Create a Simple Table
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
@@ -44,6 +69,15 @@ Layout Tricks
|
||||
This is most suitable for your notes, as the result in exported documents cannot be guaranteed
|
||||
to match. Especially if you don't use the same font in your manuscript as in the editor.
|
||||
|
||||
.. dropdown:: Turn Off First Line Indent for a Paragraph
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
If you have first line indent enabled, but have a specific paragraph that you don't want
|
||||
indented, you can disable the indentation by explicitly add text alignment. Aligned paragraphs
|
||||
are not indented. For instance by adding ``<<`` to the end to left-align it,
|
||||
|
||||
See :ref:`a_fmt_align` for more details.
|
||||
|
||||
|
||||
Organising Your Text
|
||||
====================
|
||||
@@ -58,8 +92,6 @@ Organising Your Text
|
||||
such text. Separating chapter and scene files also allows you to make scene files child
|
||||
documents of the chapter.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. dropdown:: Distinguishing Soft and Hard Scene Breaks
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
|
||||
@@ -12,16 +12,17 @@ text without having to deal with formatting until you generate a draft document
|
||||
Instead, you can focus on the writing right from the start.
|
||||
|
||||
Of course, you probably need *some* formatting for your text. At the very least you need emphasis.
|
||||
Most people are familiar with adding emphasis using underscores and asterisks. This formatting
|
||||
standard comes from Markdown_ and is supported by novelWriter. It also uses Markdown formatting for
|
||||
defining document headings. If you need more specialised formatting, additional formatting options
|
||||
are available using a shortcode format. See :ref:`a_fmt_shortcodes` for more details.
|
||||
Most people are familiar with adding emphasis using ``_underscores_`` and ``**asterisks**``. This
|
||||
formatting standard comes from Markdown_ and is supported by novelWriter. It also uses Markdown
|
||||
formatting for defining document headings. If you need more specialised formatting, additional
|
||||
formatting options are available using a shortcode format. See :ref:`a_fmt_shortcodes` for more
|
||||
details.
|
||||
|
||||
.. admonition:: Limitations
|
||||
|
||||
novelWriter is designed for writing fiction, so the formatting features available are limited to
|
||||
those relevant for this purpose. It is **not** suitable for technical writing, and it is **not**
|
||||
a full-featured Markdown editor.
|
||||
those relevant for this purpose. It is *not* suitable for technical writing, and it is *not* a
|
||||
full-featured Markdown editor.
|
||||
|
||||
It is also not intended as a tool for organising research for writing, and therefore lacks
|
||||
formatting features you may need for this purpose. The notes feature in novelWriter is mainly
|
||||
@@ -32,7 +33,7 @@ instead of a single, large document. The idea is to make it easier to reorganise
|
||||
structure without having to cut and paste text between chapters and scenes.
|
||||
|
||||
There are two kinds of documents in your project: :term:`Novel Documents` are documents that are
|
||||
part of your story. The other kind of documents are :term:`Project Notes`. These are intended for
|
||||
part of your story. The other kind of documents are :term:`Project Notes`, which are intended for
|
||||
your notes about your characters, your world building, and so on.
|
||||
|
||||
You can at any point split the individual documents by their headings up into multiple documents,
|
||||
@@ -51,9 +52,12 @@ Below are some key features of novelWriter.
|
||||
**Focus on writing**
|
||||
The aim of the user interface is to let you focus on writing instead of spending time formatting
|
||||
text. Formatting is therefore limited to a small set of formatting tags for simple things like
|
||||
text emphasis and paragraph alignment. When you really want to focus on just writing, you can
|
||||
switch the editor into **Focus Mode** where only the text editor panel itself is visible, and
|
||||
the project structure view is hidden away.
|
||||
text emphasis and paragraph alignment. Additional shortcodes are available for special
|
||||
formatting cases.
|
||||
|
||||
When you really want to focus on just writing, you can switch the editor into **Focus Mode**
|
||||
where only the text editor panel itself is visible, and the project structure view is hidden
|
||||
away.
|
||||
|
||||
**Keep an eye on your notes**
|
||||
The main window can optionally show a document viewer to the right of the editor. The viewer
|
||||
@@ -72,19 +76,22 @@ Below are some key features of novelWriter.
|
||||
**Multi-novel project support**
|
||||
The main parts of your project is split up into top level special folders called "Root" folders.
|
||||
Your main story text lives in the "Novel" root folder. You can have multiple such folders in a
|
||||
project. This allows you to keep a series of individual novels with the same characters and
|
||||
world building in the same project, and create manuscripts for them individually.
|
||||
project, and rename them to whatever you want. This allows you to keep a series of individual
|
||||
novels with the same characters and world building in the same project, and create manuscripts
|
||||
for them individually.
|
||||
|
||||
**Keep track of your story elements**
|
||||
All notes in your project can be assigned a :term:`tag` that you can then :term:`reference` from
|
||||
any other document or note. In fact, you can add a new tag under each heading of a note if you
|
||||
need to be able to reference specific sections of it.
|
||||
need to be able to reference specific sections of it, or you want to keep several topics in the
|
||||
same note.
|
||||
|
||||
**Get an overview of your story**
|
||||
It is not the documents themselves that define the chapters and scenes of your story, but the
|
||||
headings that separate them. In the **Outline View** on the main window you can see an outline
|
||||
of all the chapter and scene headings of your project. If they have any references in them, like
|
||||
which character is in what chapter and scene, these are listed in additional columns.
|
||||
of all the chapter and scene headings of each novel root folder in your project. If they have
|
||||
any references in them, like which character is in what chapter and scene, these are listed in
|
||||
additional columns.
|
||||
|
||||
You can also add a synopsis to each chapter or scene, which can be listed here as well. You have
|
||||
the option to add or remove columns of information from this outline. A subset of the outline
|
||||
@@ -100,9 +107,9 @@ Below are some key features of novelWriter.
|
||||
Whether you want to assemble a manuscript, or export all your notes, or generate an outline of
|
||||
your chapters and scenes with a synopsis included, you can use the **Build Manuscript** tool to
|
||||
do so. The tool lets you select what information you want to include in the generated document,
|
||||
and how it is formatted. You can send the result to a printer, a PDF, or to an Open Document
|
||||
file that can be opened by most office type word processors. You can also generate the result
|
||||
as HTML, or Markdown, both suitable for further conversion to other formats.
|
||||
and how it is formatted. You can send the result to a printer or PDF, or generate an Open
|
||||
Document file that can be opened by most office type word processors. You can also generate the
|
||||
result as HTML, or Markdown, both suitable for further conversion to other formats.
|
||||
|
||||
|
||||
.. _a_intro_screenshots:
|
||||
|
||||
@@ -10,7 +10,7 @@ but you don't need all of them to get started.
|
||||
The chapters below labelled "Essential Information" are the ones you need to know to use the
|
||||
application correctly. By "correctly", it is meant: in a way so novelWriter understands the basic
|
||||
structure of your text. It collects a lot of information from your text and uses it to display the
|
||||
structure of it in various ways to help you get an overview of your project.
|
||||
structure of it in various ways to help you get an overview of your writing.
|
||||
|
||||
The chapters labelled "Recommended Reading" includes additional information on how the different
|
||||
parts if the application work and what the features do.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Customisations
|
||||
**************
|
||||
|
||||
.. _Enchant: https://abiword.github.io/enchant
|
||||
.. _Enchant: https://rrthomas.github.io/enchant/
|
||||
.. _Free Desktop: https://cgit.freedesktop.org/libreoffice/dictionaries/tree/
|
||||
|
||||
There are a few ways you can customise novelWriter yourself. Currently, you can add new GUI themes,
|
||||
@@ -131,9 +131,12 @@ A GUI theme ``.conf`` file consists of the following settings:
|
||||
linkvisited = 100, 100, 100
|
||||
|
||||
[GUI]
|
||||
statusnone = 100, 100, 100
|
||||
statussaved = 100, 100, 100
|
||||
statusunsaved = 100, 100, 100
|
||||
helptext = 0, 0, 0
|
||||
fadedtext = 128, 128, 128
|
||||
errortext = 255, 0, 0
|
||||
statusnone = 120, 120, 120
|
||||
statussaved = 2, 133, 37
|
||||
statusunsaved = 200, 15, 39
|
||||
|
||||
In the Main section you must at least define the ``name`` and ``icontheme`` settings. The
|
||||
``icontheme`` settings should correspond to one of the internal icon themes, either
|
||||
@@ -143,7 +146,11 @@ setting must match the icon theme's folder name.
|
||||
The Palette values correspond to the Qt enum values for ``QPalette::ColorRole``, see the
|
||||
`Qt documentation <https://doc.qt.io/qt-5.15/qpalette.html#ColorRole-enum>`_ for more details. The
|
||||
colour values are RGB numbers on the format ``r, g, b`` where each is an integer from ``0`` to
|
||||
``255``. Omitted values are not loaded and will use default values.
|
||||
``255``. Omitted values are not loaded and will use default values. If the ``helptext`` colour is
|
||||
not defined, it is computed as a colour between the ``window`` and ``windowtext`` colour.
|
||||
|
||||
.. versionadded:: 2.5
|
||||
The ``fadedtext`` and ``errortext`` theme colour entries were added.
|
||||
|
||||
|
||||
Custom Syntax Theme
|
||||
@@ -168,12 +175,13 @@ A syntax theme ``.conf`` file consists of the following settings:
|
||||
headertext = 0, 0, 0
|
||||
headertag = 0, 0, 0
|
||||
emphasis = 0, 0, 0
|
||||
straightquotes = 0, 0, 0
|
||||
doublequotes = 0, 0, 0
|
||||
singlequotes = 0, 0, 0
|
||||
dialog = 0, 0, 0
|
||||
altdialog = 0, 0, 0
|
||||
note = 0, 0, 0
|
||||
hidden = 0, 0, 0
|
||||
shortcode = 0, 0, 0
|
||||
keyword = 0, 0, 0
|
||||
tag = 0, 0, 0
|
||||
value = 0, 0, 0
|
||||
optional = 0, 0, 0
|
||||
spellcheckline = 0, 0, 0
|
||||
@@ -197,3 +205,7 @@ Omitted syntax colours default to black, except ``background`` which defaults to
|
||||
|
||||
.. versionadded:: 2.4
|
||||
The ``texthighlight`` syntax colour entry was added.
|
||||
|
||||
.. versionadded:: 2.5
|
||||
The ``dialog``, ``altdialog``, ``note`` and ``tag`` syntax colour entries were added.
|
||||
``straightquotes``, ``doublequotes`` and ``singlequotes`` were removed.
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
.. _a_proj:
|
||||
|
||||
**************
|
||||
Novel Projects
|
||||
**************
|
||||
*****************
|
||||
Managing Projects
|
||||
*****************
|
||||
|
||||
Your text in novelWriter is organised into projects. Each project is meant to contain one novel
|
||||
and associated notes. If you have multiple novels in a series, with the same characters and shared
|
||||
notes, it is also possible to keep all of them in the same project.
|
||||
|
||||
.. _a_proj_new:
|
||||
|
||||
Creating Project
|
||||
================
|
||||
|
||||
New projects can be created from the **Project** menu by selecting **Create or Open Project**. This
|
||||
will open the **Welcome** dialog, where you can select the :guilabel:`New` button that will assist
|
||||
@@ -27,10 +36,19 @@ and page counts, is available through the **Novel Details** dialog. Statistics a
|
||||
is also available in the **Manuscript Build** tool.
|
||||
|
||||
|
||||
Template Projects
|
||||
-----------------
|
||||
|
||||
From the Welcome dialog you can also create a new from another existing project. If you have a
|
||||
specific structure you want to use for all your new projects, you can create a dedicated project to
|
||||
be used as a template, and select to copy an existing project from the :guilabel:"Prefill Project"
|
||||
option from the **New Project** form.
|
||||
|
||||
|
||||
.. _a_proj_roots:
|
||||
|
||||
Project Roots
|
||||
=============
|
||||
Project Structure
|
||||
=================
|
||||
|
||||
Projects are structured into a set of top level folders called "Root Folders". They are visible in
|
||||
the project tree at the left side of the main window.
|
||||
@@ -100,6 +118,9 @@ The root folders are closely tied to the tags and reference system. Each folder
|
||||
the categories of tags that can be used to reference them. For more information about the tags
|
||||
listed, see :ref:`a_references_references`.
|
||||
|
||||
There is also a ``@mention`` keyword that can be used to reference any tag.
|
||||
See :ref:`a_references_references` for more details.
|
||||
|
||||
.. note::
|
||||
You can rename root folders to whatever you want. However, this doesn't change the reference
|
||||
keyword or what they do.
|
||||
@@ -288,7 +309,8 @@ Status and Importance Tabs
|
||||
--------------------------
|
||||
|
||||
Each document or folder of type **Novel** can be given a "Status" label accompanied by a coloured
|
||||
icon, and each document or folder of the remaining types can be given an "Importance" label.
|
||||
icon with an optional shape selected from a list of pre-defined shapes. Each document or folder of
|
||||
the remaining types can be given an "Importance" label with the same customisation options.
|
||||
|
||||
These labels are there purely for your convenience, and you are not required to use them for any
|
||||
other features to work. No other part of novelWriter accesses this information. The intention is to
|
||||
|
||||
@@ -162,6 +162,12 @@ reference keywords allow multiple values.
|
||||
Custom references in the current section. The target must be a note tag in a **Custom** type
|
||||
root folder. The custom folder are for any other category of notes you may want to use.
|
||||
|
||||
``@mention``
|
||||
Anything mentioned, but not present in the current section. It is intended for those cases where
|
||||
you reveal details about a character or place in a scene without it being otherwise a part of
|
||||
it. This can be useful when checking for consistency later. Any tag in any root note folder can
|
||||
be listed under mentions.
|
||||
|
||||
The syntax highlighter will alert the user that the tags and references are used correctly, and
|
||||
that the tags referenced exist.
|
||||
|
||||
|
||||
@@ -39,11 +39,9 @@ The following Python packages are needed to run all features of novelWriter:
|
||||
* ``PyQt5`` – needed for connecting with the Qt5 libraries.
|
||||
* ``PyEnchant`` – needed for spell checking (optional).
|
||||
|
||||
PyQt/Qt should be at least 5.10, but ideally 5.13 or higher for all features to work. For instance,
|
||||
searching using regular expressions with full Unicode support requires 5.13.
|
||||
|
||||
If you want spell checking, you must install the ``PyEnchant`` package. The spell check library
|
||||
must be at least 3.0 to work with Windows. On Linux, 2.0 also works fine.
|
||||
PyQt/Qt must be at least 5.15.0. If you want spell checking, you must install the ``PyEnchant``
|
||||
package. The spell check library must be at least 3.0 to work with Windows. On Linux, 2.0 also
|
||||
works fine.
|
||||
|
||||
If you install from PyPi, these dependencies should be installed automatically. If you install from
|
||||
source, dependencies can still be installed from PyPi with:
|
||||
@@ -55,7 +53,7 @@ source, dependencies can still be installed from PyPi with:
|
||||
.. note::
|
||||
On Linux distros, the Qt library is usually split up into multiple packages. In some cases,
|
||||
secondary dependencies may not be installed automatically. For novelWriter, the library files
|
||||
for renderring the SVG icons may be left out and needs to be installed manually. This is the
|
||||
for rendering the SVG icons may be left out and needs to be installed manually. This is the
|
||||
case on for instance Arch Linux.
|
||||
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ project-related tools and quick access to settings at the bottom.
|
||||
|
||||
.. versionadded:: 2.2
|
||||
A number of new formatting options were added in 2.2 to allow for some special formatting cases.
|
||||
At the same time, a small formatting toolbar was added in the editor. It is hidden by default,
|
||||
but can be opened by pressing the icon button in the top right corner.
|
||||
At the same time, a small formatting toolbar was added to the editor. It is hidden by default,
|
||||
but can be opened by pressing the button in the top right corner of the editor header.
|
||||
|
||||
|
||||
Project Tree and Editor View
|
||||
@@ -148,6 +148,20 @@ in the document editor that acts on the open document.
|
||||
.. versionadded:: 2.4
|
||||
|
||||
|
||||
Switching Focus
|
||||
---------------
|
||||
|
||||
If the project or novel view does not have focus, pressing :kbd:`Ctrl+T` switches focus to
|
||||
whichever of the two is visible. If one of them already has focus, the key press will switch
|
||||
between them instead.
|
||||
|
||||
Likewise, pressing :kbd:`Ctrl+E` with switch focus to the document editor or viewer, or if any of
|
||||
them already have focus, it will switch focus between them,
|
||||
|
||||
These two shortcuts makes it possible to jump between all these GUI elements without having to
|
||||
reach for the mouse or touchpad.
|
||||
|
||||
|
||||
.. _a_breakdown_project:
|
||||
|
||||
Project Layout
|
||||
|
||||
@@ -125,8 +125,8 @@ background, depending on the selected theme.
|
||||
|
||||
.. _a_fmt_emph:
|
||||
|
||||
Text Emphasis
|
||||
=============
|
||||
Text Emphasis with Markdown
|
||||
===========================
|
||||
|
||||
A minimal set of Markdown text emphasis styles are supported for text paragraphs.
|
||||
|
||||
@@ -156,7 +156,7 @@ In addition, the following rules apply:
|
||||
outside, they violate rule 2.
|
||||
4. Text emphasis does not span past line breaks. If you need to add emphasis to multiple lines or
|
||||
paragraphs, you must apply it to each of them in turn.
|
||||
5. Text emphasis can only be used in plain paragraphs. Comments, titles, and meta data tags don't
|
||||
5. Text emphasis can only be used in comments and paragraphs. Headings and meta data tags don't
|
||||
allow for formatting, and any formatting markup will be rendered as-is.
|
||||
|
||||
.. tip::
|
||||
@@ -168,8 +168,8 @@ In addition, the following rules apply:
|
||||
|
||||
.. _a_fmt_shortcodes:
|
||||
|
||||
Extended Formatting with Shortcodes
|
||||
===================================
|
||||
Formatting with Shortcodes
|
||||
==========================
|
||||
|
||||
For additional formatting options, you can use shortcodes. Shortcodes is a form of in-line codes
|
||||
that can be used to change the format of the text that follows and opening code, and last until
|
||||
@@ -197,6 +197,13 @@ word if you need to. You can also freely combine them to form more complex forma
|
||||
The shortcodes are available from the **Format** menu and in the editor toolbar, which can be
|
||||
activated by clicking the left-most icon button in the editor header.
|
||||
|
||||
.. note::
|
||||
|
||||
Shortcodes are not processed until you generate a preview or generate a manuscript document. So
|
||||
there is no highlighting of the text between the formatting markers. There is also no check that
|
||||
your markers make sense. You must ensure that you have both the opening and closing formatting
|
||||
markers where you want them.
|
||||
|
||||
.. versionadded:: 2.2
|
||||
|
||||
|
||||
@@ -217,27 +224,26 @@ correctly formatted, the syntax highlighter will indicate this by altering the c
|
||||
|
||||
The different styles of comments are as follows:
|
||||
|
||||
``% Comment text ...``
|
||||
``% Your comment text ...``
|
||||
This is a comment. The text is not rendered by default (this can be overridden), seen in the
|
||||
document viewer, or counted towards word counts. It is intended for you to make notes in your
|
||||
text for your own sake, whatever that may be, that isn't part of the story text. This is the
|
||||
general format of a comment.
|
||||
|
||||
``%Synopsis: Comment text ...``
|
||||
``%Synopsis: Your synopsis text ...``
|
||||
This is a synopsis comment. It is generally treated in the same way as a regular comment, except
|
||||
that it is also captured by the indexing algorithm and displayed in the :ref:`a_ui_outline`. It
|
||||
can also be filtered separately when building the project to for instance generate an outline
|
||||
document of the whole project.
|
||||
|
||||
``%Short: Comment text ...``
|
||||
``%Short: Your short description ...``
|
||||
This is a short description comment. It is identical to the synopsis comment (they are
|
||||
interchangeable), but is intended to be used for project notes. The text shows up in the
|
||||
Reference panel below the document viewer in the last column labelled **Short Description**.
|
||||
|
||||
``%~ Comment text ...``
|
||||
This can be used to exclude story text from your manuscript without having to delete it from
|
||||
your text. Comments with the ``~`` will *never* be included in the manuscript, even if you have
|
||||
chosen to include comments in it. That is the main difference between these two formats.
|
||||
``%Footnote.<key>: Your footnote text ...``
|
||||
This is a special comment assigned to a footnote marker. See :ref:`a_fmt_footnote` for how to
|
||||
use them in your text.
|
||||
|
||||
.. note::
|
||||
Only one comment can be flagged as a synopsis or short comment for each heading. If multiple
|
||||
@@ -245,16 +251,74 @@ The different styles of comments are as follows:
|
||||
ignored.
|
||||
|
||||
|
||||
.. _a_fmt_footnote:
|
||||
|
||||
Footnotes
|
||||
=========
|
||||
|
||||
Footnotes are added with a shortcode, paired with a matching comment for the actual footnote text.
|
||||
The matching is done with a key that links the two. If you insert a footnote from the **Insert**
|
||||
menu, a unique key is generated for you.
|
||||
|
||||
The insert feature will add the footnote shortcode marker at the position of your cursor in the
|
||||
text, and create the associated footnote comment right after the paragraph, and move the cursor
|
||||
there so you can immediately start typing the footnote text.
|
||||
|
||||
The footnote comment can be anywhere in the document, so if you wish to move them to, say, the
|
||||
bottom of the text, you are free to do so.
|
||||
|
||||
Footnote keys are only required to be unique within a document, so if you copy, move or merge text,
|
||||
you must make sure the keys are not duplicated. If you use the automatically generated keys from
|
||||
the **Insert** menu, they are unique among all indexed documents. They are not guaranteed to be
|
||||
unique against footnotes in the Archive or Trash folder though, but the chance of accidentally
|
||||
generating the same key twice in a project is relatively small in the first place (1 in 810 000).
|
||||
|
||||
This is what a footnote inserted into a paragraph may look like when completed:
|
||||
|
||||
.. code-block:: md
|
||||
|
||||
This is a text paragraph with a footnote[footnote:fn1] in the middle.
|
||||
|
||||
%Footnote.fn1: This is the text of the footnote.
|
||||
|
||||
.. versionadded:: 2.5
|
||||
|
||||
|
||||
.. _a_fmt_ignore:
|
||||
|
||||
Ignored Text
|
||||
============
|
||||
|
||||
If you want to completely ignore some of the text in your documents, but are not ready to delete
|
||||
it, you can add ``%~`` before the text paragraph or line. This will cause novelWriter to skip the
|
||||
text entirely when generating previews or building manuscripts.
|
||||
|
||||
This is a better way of removing text than converting them to regular comments, as you may want to
|
||||
include regular comments in your previews or draft manuscript.
|
||||
|
||||
You can toggle the ignored text feature on and off for a paragraph by pressing :kbd:`Ctrl+Shift+D`
|
||||
on your keyboard with your cursor somewhere in the paragraph.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: md
|
||||
|
||||
%~ This text is ignored.
|
||||
|
||||
This text is a regular paragraph.
|
||||
|
||||
|
||||
.. _a_fmt_tags:
|
||||
|
||||
Tags and References
|
||||
===================
|
||||
|
||||
The document editor supports a set of keywords used for setting tags, and making references between
|
||||
documents.
|
||||
documents based on those tags.
|
||||
|
||||
Tags use the keyword ``@tag:`` to define a tag. The tag can be set once per section defined by a
|
||||
heading. Setting it multiple times under the same heading will just override the previous setting.
|
||||
You must use the keyword ``@tag:`` to define a tag. The tag can be set once per section defined by
|
||||
a heading. Setting it multiple times under the same heading will just override the previous
|
||||
setting.
|
||||
|
||||
``@tag: value``
|
||||
A tag keyword followed by the tag value, like for instance the name of a character.
|
||||
@@ -306,6 +370,40 @@ Examples:
|
||||
from the manuscript build tool as long as the format supports paragraph alignment.
|
||||
|
||||
|
||||
Alignment with Line Breaks
|
||||
--------------------------
|
||||
|
||||
If you have line breaks in the paragraph, like for instance when you are writing verses, the
|
||||
alignment markers must be applied to the first line. Markers on the other lines are ignored. The
|
||||
markers for the first line are used for all the other lines.
|
||||
|
||||
For the following text, all lines will be centred, not just the first:
|
||||
|
||||
.. code-block:: md
|
||||
|
||||
>> I am the very model of a modern Major-General <<
|
||||
I've information vegetable, animal, and mineral
|
||||
I know the kings of England, and I quote the fights historical
|
||||
From Marathon to Waterloo, in order categorical
|
||||
|
||||
|
||||
Alignment with First Line Indent
|
||||
--------------------------------
|
||||
|
||||
If you have first line indent enabled in your Manuscript build settings, you probably want to
|
||||
disable it for text in verses. Adding any alignment tags will cause the first line indent to be
|
||||
switched off for that paragraph.
|
||||
|
||||
The following text will always be aligned against the left margin:
|
||||
|
||||
.. code-block:: md
|
||||
|
||||
I am the very model of a modern Major-General <<
|
||||
I've information vegetable, animal, and mineral
|
||||
I know the kings of England, and I quote the fights historical
|
||||
From Marathon to Waterloo, in order categorical
|
||||
|
||||
|
||||
.. _a_fmt_break:
|
||||
|
||||
Vertical Space and Page Breaks
|
||||
|
||||
@@ -54,7 +54,8 @@ At the top of the project tree, you will find a set of buttons.
|
||||
* The next two buttons can be used to move items up and down in the project tree. This is the only
|
||||
way to move root folders.
|
||||
* The next button opens a dropdown menu for adding new items to the tree. This includes root
|
||||
folders. You can also activate this dropdown menu by pressing :kbd:`Ctrl+N`.
|
||||
folders and template documents. You can also activate this dropdown menu by pressing
|
||||
:kbd:`Ctrl+N`.
|
||||
* The last button is a menu of further actions you can apply to the project tree.
|
||||
|
||||
Below the project tree you will find a small details panel showing the full information of the
|
||||
|
||||
@@ -26,7 +26,7 @@ Main Window Shortcuts
|
||||
":kbd:`F9`", "Re-build the project's index"
|
||||
":kbd:`F11`", "Toggle full screen mode"
|
||||
":kbd:`Ctrl+,`", "Open the **Preferences** dialog"
|
||||
":kbd:`Ctrl+E`", "Switch focus to the document editor"
|
||||
":kbd:`Ctrl+E`", "Switch or toggle focus for the editor or viewer"
|
||||
":kbd:`Ctrl+T`", "Switch or toggle focus for the project tree or novel view"
|
||||
":kbd:`Ctrl+Q`", "Exit novelWriter"
|
||||
":kbd:`Ctrl+Shift+,`", "Open the **Project Settings** dialog"
|
||||
@@ -165,6 +165,7 @@ a key or key combination for the inserted content.
|
||||
":kbd:`Ctrl+K`, :kbd:`G`", "Insert a ``@tag`` keyword"
|
||||
":kbd:`Ctrl+K`, :kbd:`H`", "Insert a short description comment"
|
||||
":kbd:`Ctrl+K`, :kbd:`L`", "Insert a ``@location`` keyword"
|
||||
":kbd:`Ctrl+K`, :kbd:`M`", "Insert a ``@mention`` keyword"
|
||||
":kbd:`Ctrl+K`, :kbd:`O`", "Insert an ``@object`` keyword"
|
||||
":kbd:`Ctrl+K`, :kbd:`P`", "Insert a ``@plot`` keyword"
|
||||
":kbd:`Ctrl+K`, :kbd:`S`", "Insert a synopsis comment"
|
||||
|
||||
@@ -40,6 +40,24 @@ Any :term:`references<reference>` in the editor can be opened in the viewer by m
|
||||
the label and pressing :kbd:`Ctrl+Return`. You can also control-click them with your mouse.
|
||||
|
||||
|
||||
Spell Checking
|
||||
--------------
|
||||
|
||||
A third party library called Enchant is used for spell checking in the editor. The controls for
|
||||
spell checking can be found in the **Tools** menu. You can also set spell checking language in
|
||||
**Project Settings**.
|
||||
|
||||
This spell checking library comes with support for custom words that you can add by selecting
|
||||
"Add Word to Dictionary" from the context menu when a word is highlighted by the spell checker as
|
||||
misspelled. The custom words are managed on a per-project basis, and can the list of words can be
|
||||
edited from the **Project Word List** tool available from the **Tools** menu.
|
||||
|
||||
.. note::
|
||||
|
||||
Generally, spell checking dictionaries are collected from your operating system, but on Windows
|
||||
they are not. See :ref:`a_custom_dict` for how to add spell checking dictionaries on Windows.
|
||||
|
||||
|
||||
Editor Auto-Completer
|
||||
---------------------
|
||||
|
||||
|
||||
2264
i18n/nw_base.ts
2292
i18n/nw_de_DE.ts
2254
i18n/nw_en_US.ts
2254
i18n/nw_es_419.ts
2254
i18n/nw_fr_FR.ts
2254
i18n/nw_it_IT.ts
2254
i18n/nw_ja_JP.ts
2254
i18n/nw_nb_NO.ts
2280
i18n/nw_nl_NL.ts
4991
i18n/nw_pl_PL.ts
Normal file
3732
i18n/nw_pt_BR.ts
4991
i18n/nw_ru_RU.ts
Normal file
2962
i18n/nw_zh_CN.ts
@@ -47,19 +47,3 @@ QT_TRANSLATE_NOOP("QPlatformTheme", "Help")
|
||||
QT_TRANSLATE_NOOP("QPlatformTheme", "Apply")
|
||||
QT_TRANSLATE_NOOP("QPlatformTheme", "Reset")
|
||||
QT_TRANSLATE_NOOP("QPlatformTheme", "Restore Defaults")
|
||||
|
||||
# QWizard
|
||||
# =======
|
||||
|
||||
QT_TRANSLATE_NOOP("QWizard", "Go Back")
|
||||
QT_TRANSLATE_NOOP("QWizard", "< &Back")
|
||||
QT_TRANSLATE_NOOP("QWizard", "Continue")
|
||||
QT_TRANSLATE_NOOP("QWizard", "&Next")
|
||||
QT_TRANSLATE_NOOP("QWizard", "&Next >")
|
||||
QT_TRANSLATE_NOOP("QWizard", "Commit")
|
||||
QT_TRANSLATE_NOOP("QWizard", "Done")
|
||||
QT_TRANSLATE_NOOP("QWizard", "&Finish")
|
||||
QT_TRANSLATE_NOOP("QWizard", "Cancel")
|
||||
QT_TRANSLATE_NOOP("QWizard", "Cancel")
|
||||
QT_TRANSLATE_NOOP("QWizard", "Help")
|
||||
QT_TRANSLATE_NOOP("QWizard", "&Help")
|
||||
|
||||
@@ -3,7 +3,7 @@ novelWriter – Init File
|
||||
=======================
|
||||
|
||||
File History:
|
||||
Created: 2018-09-22 [0.0.1]
|
||||
Created: 2018-09-22 [0.0.1] main
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
@@ -32,7 +32,7 @@ from typing import TYPE_CHECKING
|
||||
from PyQt5.QtWidgets import QApplication, QErrorMessage
|
||||
|
||||
from novelwriter.config import Config
|
||||
from novelwriter.error import exceptionHandler, logException
|
||||
from novelwriter.error import exceptionHandler
|
||||
from novelwriter.shared import SharedData
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
@@ -47,9 +47,9 @@ __license__ = "GPLv3"
|
||||
__author__ = "Veronica Berglyd Olsen"
|
||||
__maintainer__ = "Veronica Berglyd Olsen"
|
||||
__email__ = "code@vkbo.net"
|
||||
__version__ = "2.4"
|
||||
__hexversion__ = "0x020400f0"
|
||||
__date__ = "2024-04-20"
|
||||
__version__ = "2.6b2"
|
||||
__hexversion__ = "0x020600b2"
|
||||
__date__ = "2024-12-23"
|
||||
__status__ = "Stable"
|
||||
__domain__ = "novelwriter.io"
|
||||
|
||||
@@ -60,10 +60,26 @@ logger = logging.getLogger(__name__)
|
||||
# Main Program
|
||||
##
|
||||
|
||||
# Global config and data singletons
|
||||
# Globals Singletons
|
||||
CONFIG = Config()
|
||||
SHARED = SharedData()
|
||||
|
||||
# ANSI Colours
|
||||
C_RED = "\033[91m"
|
||||
C_GREEN = "\033[92m"
|
||||
C_YELLOW = "\033[93m"
|
||||
C_BLUE = "\033[94m"
|
||||
C_WHITE = "\033[97m"
|
||||
C_END = "\033[0m"
|
||||
|
||||
# Log Formats
|
||||
L_TIME = "[{asctime:}]"
|
||||
L_FILE = "{filename:>18}"
|
||||
L_LINE = "{lineno:<4d}"
|
||||
L_LVLP = "{levelname:8}"
|
||||
L_LVLC = "{levelname:17}"
|
||||
L_TEXT = "{message:}"
|
||||
|
||||
|
||||
def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
"""Parse command line, set up logging, and launch main GUI."""
|
||||
@@ -77,6 +93,7 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
"version",
|
||||
"info",
|
||||
"debug",
|
||||
"color",
|
||||
"style=",
|
||||
"config=",
|
||||
"data=",
|
||||
@@ -98,6 +115,7 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
" -v, --version Print program version and exit.\n"
|
||||
" --info Print additional runtime information.\n"
|
||||
" --debug Print debug output. Includes --info.\n"
|
||||
" --color Add ANSI colors to log output.\n"
|
||||
" --meminfo Show memory usage information in the status bar.\n"
|
||||
" --style= Sets Qt5 style flag. Defaults to 'Fusion'.\n"
|
||||
" --config= Alternative config file.\n"
|
||||
@@ -106,12 +124,12 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
|
||||
# Defaults
|
||||
logLevel = logging.WARN
|
||||
logFormat = "{levelname:8} {message:}"
|
||||
fmtFlags = 0b00
|
||||
confPath = None
|
||||
dataPath = None
|
||||
testMode = False
|
||||
qtStyle = "Fusion"
|
||||
cmdOpen = None
|
||||
qtStyle = "Fusion"
|
||||
cmdOpen = None
|
||||
|
||||
# Parse Options
|
||||
try:
|
||||
@@ -135,8 +153,10 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
logLevel = logging.INFO
|
||||
elif inOpt == "--debug":
|
||||
CONFIG.isDebug = True
|
||||
fmtFlags = fmtFlags | 0b10
|
||||
logLevel = logging.DEBUG
|
||||
logFormat = "[{asctime:}] {filename:>18}:{lineno:<4d} {levelname:8} {message:}"
|
||||
elif inOpt == "--color":
|
||||
fmtFlags = fmtFlags | 0b01
|
||||
elif inOpt == "--style":
|
||||
qtStyle = inArg
|
||||
elif inOpt == "--config":
|
||||
@@ -148,13 +168,32 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
elif inOpt == "--meminfo":
|
||||
CONFIG.memInfo = True
|
||||
|
||||
if fmtFlags & 0b01:
|
||||
# This will overwrite the default level names, and also ensure that
|
||||
# they can be converted back to integer levels
|
||||
logging.addLevelName(logging.DEBUG, f"{C_BLUE}DEBUG{C_END}")
|
||||
logging.addLevelName(logging.INFO, f"{C_GREEN}INFO{C_END}")
|
||||
logging.addLevelName(logging.WARNING, f"{C_YELLOW}WARNING{C_END}")
|
||||
logging.addLevelName(logging.ERROR, f"{C_RED}ERROR{C_END}")
|
||||
logging.addLevelName(logging.CRITICAL, f"{C_RED}CRITICAL{C_END}")
|
||||
|
||||
# Determine Log Format
|
||||
if fmtFlags == 0b00:
|
||||
logFmt = f"{L_LVLP} {L_TEXT}"
|
||||
elif fmtFlags == 0b01:
|
||||
logFmt = f"{L_LVLC} {L_TEXT}"
|
||||
elif fmtFlags == 0b10:
|
||||
logFmt = f"{L_TIME} {L_FILE}:{L_LINE} {L_LVLP} {L_TEXT}"
|
||||
elif fmtFlags == 0b11:
|
||||
logFmt = f"{L_TIME} {C_BLUE}{L_FILE}{C_END}:{C_WHITE}{L_LINE}{C_END} {L_LVLC} {L_TEXT}"
|
||||
|
||||
# Setup Logging
|
||||
pkgLogger = logging.getLogger(__package__)
|
||||
pkgLogger.setLevel(logLevel)
|
||||
if len(pkgLogger.handlers) == 0:
|
||||
# Make sure we only create one logger (mostly an issue with tests)
|
||||
cHandle = logging.StreamHandler()
|
||||
cHandle.setFormatter(logging.Formatter(fmt=logFormat, style="{"))
|
||||
cHandle.setFormatter(logging.Formatter(fmt=logFmt, style="{"))
|
||||
pkgLogger.addHandler(cHandle)
|
||||
|
||||
logger.info("Starting novelWriter %s (%s) %s", __version__, __hexversion__, __date__)
|
||||
@@ -162,19 +201,19 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
# Check Packages and Versions
|
||||
errorData = []
|
||||
errorCode = 0
|
||||
if sys.hexversion < 0x030800f0:
|
||||
if sys.hexversion < 0x030900f0:
|
||||
errorData.append(
|
||||
"At least Python 3.8 is required, found %s" % CONFIG.verPyString
|
||||
"At least Python 3.9 is required, found %s" % CONFIG.verPyString
|
||||
)
|
||||
errorCode |= 0x04
|
||||
if CONFIG.verQtValue < 0x050a00:
|
||||
if CONFIG.verQtValue < 0x050f00:
|
||||
errorData.append(
|
||||
"At least Qt5 version 5.10 is required, found %s" % CONFIG.verQtString
|
||||
"At least Qt5 version 5.15.0 is required, found %s" % CONFIG.verQtString
|
||||
)
|
||||
errorCode |= 0x08
|
||||
if CONFIG.verPyQtValue < 0x050a00:
|
||||
if CONFIG.verPyQtValue < 0x050f00:
|
||||
errorData.append(
|
||||
"At least PyQt5 version 5.10 is required, found %s" % CONFIG.verPyQtString
|
||||
"At least PyQt5 version 5.15.0 is required, found %s" % CONFIG.verPyQtString
|
||||
)
|
||||
errorCode |= 0x10
|
||||
|
||||
@@ -198,52 +237,46 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
# Finish initialising config
|
||||
CONFIG.initConfig(confPath, dataPath)
|
||||
|
||||
if CONFIG.osDarwin:
|
||||
if sys.platform == "darwin":
|
||||
try:
|
||||
from Foundation import NSBundle # type: ignore
|
||||
bundle = NSBundle.mainBundle()
|
||||
info = bundle.localizedInfoDictionary() or bundle.infoDictionary()
|
||||
info["CFBundleName"] = "novelWriter"
|
||||
except Exception:
|
||||
logger.error("Failed to set application name")
|
||||
logException()
|
||||
|
||||
elif CONFIG.osWindows:
|
||||
pass # Quietly ignore error
|
||||
elif sys.platform == "win32":
|
||||
try:
|
||||
import ctypes
|
||||
appID = f"io.novelwriter.{__version__}"
|
||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(appID) # type: ignore
|
||||
except Exception:
|
||||
logger.error("Failed to set application name")
|
||||
logException()
|
||||
pass # Quietly ignore error
|
||||
|
||||
# Import GUI (after dependency checks), and launch
|
||||
from novelwriter.guimain import GuiMain
|
||||
|
||||
if testMode:
|
||||
nwGUI = GuiMain()
|
||||
return nwGUI
|
||||
# Only used for testing where the test framework creates the app
|
||||
CONFIG.loadConfig()
|
||||
return GuiMain()
|
||||
|
||||
else:
|
||||
nwApp = QApplication([CONFIG.appName, (f"-style={qtStyle}")])
|
||||
nwApp.setApplicationName(CONFIG.appName)
|
||||
nwApp.setApplicationVersion(__version__)
|
||||
nwApp.setOrganizationDomain(__domain__)
|
||||
nwApp.setOrganizationName(__domain__)
|
||||
nwApp.setDesktopFileName(CONFIG.appName)
|
||||
app = QApplication([CONFIG.appName, (f"-style={qtStyle}")])
|
||||
app.setApplicationName(CONFIG.appName)
|
||||
app.setApplicationVersion(__version__)
|
||||
app.setOrganizationDomain(__domain__)
|
||||
app.setOrganizationName(__domain__)
|
||||
app.setDesktopFileName(CONFIG.appName)
|
||||
|
||||
# Connect the exception handler before making the main GUI
|
||||
sys.excepthook = exceptionHandler
|
||||
# Connect the exception handler before making the main GUI
|
||||
sys.excepthook = exceptionHandler
|
||||
|
||||
# Run Config steps that require the QApplication
|
||||
CONFIG.initLocalisation(nwApp)
|
||||
CONFIG.setTextFont(CONFIG.textFont, CONFIG.textSize) # Makes sure these are valid
|
||||
# Run Config steps that require the QApplication
|
||||
CONFIG.loadConfig()
|
||||
CONFIG.initLocalisation(app)
|
||||
|
||||
# Launch main GUI
|
||||
nwGUI = GuiMain()
|
||||
nwGUI.postLaunchTasks(cmdOpen)
|
||||
# Launch main GUI
|
||||
nwGUI = GuiMain()
|
||||
nwGUI.postLaunchTasks(cmdOpen)
|
||||
|
||||
sys.exit(nwApp.exec())
|
||||
|
||||
return None
|
||||
|
||||
# END Function main
|
||||
sys.exit(app.exec())
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
"Notes": "Notizen",
|
||||
"Tag": "Schlagwort",
|
||||
"Point of View": "Perspektive",
|
||||
"Focus": "Mittelpunkt",
|
||||
"Focus": "Fokus",
|
||||
"Characters": "Charaktere",
|
||||
"Plot": "Handlungen",
|
||||
"Plot": "Handlung",
|
||||
"Timeline": "Zeitleiste",
|
||||
"Locations": "Schauplätze",
|
||||
"Objects": "Objekte",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Synopsis": "Synopsis",
|
||||
"Short Description": "Short Description",
|
||||
"Footnotes": "Footnotes",
|
||||
"Comment": "Comment",
|
||||
"Notes": "Notes",
|
||||
"Tag": "Tag",
|
||||
@@ -13,6 +14,7 @@
|
||||
"Objects": "Objects",
|
||||
"Entities": "Entities",
|
||||
"Custom": "Custom",
|
||||
"New Page": "New Page",
|
||||
"0": "Zero",
|
||||
"1": "One",
|
||||
"2": "Two",
|
||||
|
||||
116
novelwriter/assets/i18n/project_pl_PL.json
Normal file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"Synopsis": "Streszczenie",
|
||||
"Short Description": "Krótki opis",
|
||||
"Comment": "Komentarz",
|
||||
"Notes": "Notatki",
|
||||
"Tag": "Znacznik",
|
||||
"Point of View": "Punkt widzenia",
|
||||
"Focus": "Skupienie",
|
||||
"Characters": "Postacie",
|
||||
"Plot": "Fabuła",
|
||||
"Timeline": "Oś czasu",
|
||||
"Locations": "Miejsca",
|
||||
"Objects": "Obiekty",
|
||||
"Entities": "Podmioty",
|
||||
"Custom": "Różne",
|
||||
"0": "zero",
|
||||
"1": "pierwszy",
|
||||
"2": "drugi",
|
||||
"3": "trzeci",
|
||||
"4": "czwarty",
|
||||
"5": "piąty",
|
||||
"6": "szósty",
|
||||
"7": "siódmy",
|
||||
"8": "ósmy",
|
||||
"9": "dziewiąty",
|
||||
"10": "dziesiąty",
|
||||
"11": "jedenasty",
|
||||
"12": "dwunasty",
|
||||
"13": "trzynasty",
|
||||
"14": "czternasty",
|
||||
"15": "piętnasty",
|
||||
"16": "szesnasty",
|
||||
"17": "siedemnasty",
|
||||
"18": "osiemnasty",
|
||||
"19": "dziewiętnasty",
|
||||
"20": "dwudziesty",
|
||||
"21": "dwudziesty pierwszy",
|
||||
"22": "dwudziesty drugi",
|
||||
"23": "dwudziesty Trzeci",
|
||||
"24": "dwudziesty czwarty",
|
||||
"25": "dwudziesty piąty",
|
||||
"26": "dwudziesty szósty",
|
||||
"27": "dwudziesty siódmy",
|
||||
"28": "dwudziesty ósmy",
|
||||
"29": "dwudziesty dziewiąty",
|
||||
"30": "trzydziesty",
|
||||
"31": "trzydziesty pierwszy",
|
||||
"32": "trzydziesty drugi",
|
||||
"33": "trzydziesty trzeci",
|
||||
"34": "trzydziesty czwarty",
|
||||
"35": "trzydziesty piąty",
|
||||
"36": "trzydziesty szósty",
|
||||
"37": "trzydziesty siódmy",
|
||||
"38": "trzydziesty ósmy",
|
||||
"39": "trzydziesty dziewiaty",
|
||||
"40": "czterdziesty",
|
||||
"41": "czterdziesty pierwszy",
|
||||
"42": "czterdziesty drugi",
|
||||
"43": "czterdziesty Trzeci",
|
||||
"44": "czterdziesty czwarty",
|
||||
"45": "czterdziesty piąty",
|
||||
"46": "czterdziesty szósty",
|
||||
"47": "czterdziesty siódmy",
|
||||
"48": "czterdziesty ósmy",
|
||||
"49": "czterdziesty dziewiąty",
|
||||
"50": "pięćdziesiąty",
|
||||
"51": "pięćdziesiąty pierwszy",
|
||||
"52": "pięćdziesiąty drugi",
|
||||
"53": "pięćdziesiąty trzeci",
|
||||
"54": "pięćdziesiąty czwarty",
|
||||
"55": "pięćdziesiąty piąty",
|
||||
"56": "pięćdziesiąty szósty",
|
||||
"57": "pięćdziesiąty siódmy",
|
||||
"58": "pięćdziesiąty ósmy",
|
||||
"59": "pięćdziesiąty dziewiąty",
|
||||
"60": "sześćdziesiąty",
|
||||
"61": "sześćdziesiąty pierwszy",
|
||||
"62": "sześćdziesiąty drugi",
|
||||
"63": "sześćdziesiąty trzeci",
|
||||
"64": "sześćdziesiąty czwarty",
|
||||
"65": "sześćdziesiąty piąty",
|
||||
"66": "sześćdziesiąty szósty",
|
||||
"67": "sześćdziesiąty siódmy",
|
||||
"68": "sześćdziesiąty ósmy",
|
||||
"69": "sześćdziesiąty dziewiąty",
|
||||
"70": "siedemdziesiąty",
|
||||
"71": "siedemdziesiąty pierwszy",
|
||||
"72": "siedemdziesiąty drugi",
|
||||
"73": "siedemdziesiąty trzeci",
|
||||
"74": "siedemdziesiąty czwarty",
|
||||
"75": "siedemdziesiąty piąty",
|
||||
"76": "siedemdziesiąty szósty",
|
||||
"77": "siedemdziesiąty siódmy",
|
||||
"78": "siedemdziesiąty ósmy",
|
||||
"79": "siedemdziesiąty dziewiąty",
|
||||
"80": "osiemdziesiąty",
|
||||
"81": "osiemdziesiąty pierwszy",
|
||||
"82": "osiemdziesiąty drugi",
|
||||
"83": "osiemdziesiąty trzeci",
|
||||
"84": "osiemdziesiąty czwarty",
|
||||
"85": "osiemdziesiąty piąty",
|
||||
"86": "osiemdziesiąty szósty",
|
||||
"87": "osiemdziesiąty siódmy",
|
||||
"88": "osiemdziesiąty ósmy",
|
||||
"89": "osiemdziesiąty dziewiąty",
|
||||
"90": "dziewięćdziesiąty",
|
||||
"91": "dziewięćdziesiąty pierwszy",
|
||||
"92": "dziewięćdziesiąty drugi",
|
||||
"93": "dziewięćdziesiąty trzeci",
|
||||
"94": "dziewięćdziesiąty czwarty",
|
||||
"95": "dziewięćdziesiąty piąty",
|
||||
"96": "dziewięćdziesiąty szósty",
|
||||
"97": "dziewięćdziesiąty siódmy",
|
||||
"98": "dziewięćdziesiąty ósmy",
|
||||
"99": "dziewięćdziesiąty dziewiąty"
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"Synopsis": "Sinopse",
|
||||
"Short Description": "Descrição breve",
|
||||
"Comment": "Comentários",
|
||||
"Comment": "Comentário",
|
||||
"Notes": "Notas",
|
||||
"Tag": "Etiqueta",
|
||||
"Point of View": "Ponto de vista",
|
||||
@@ -30,87 +30,87 @@
|
||||
"14": "Quatorze",
|
||||
"15": "Quinze",
|
||||
"16": "Dezesseis",
|
||||
"17": "Dezesete",
|
||||
"17": "Dezessete",
|
||||
"18": "Dezoito",
|
||||
"19": "Dezenove",
|
||||
"20": "Vinte",
|
||||
"21": "Vinte e Um",
|
||||
"22": "Vinte e Dois",
|
||||
"23": "Vinte e Três",
|
||||
"24": "Vinte e Quatro",
|
||||
"25": "Vinte e Cinco",
|
||||
"26": "Vinte e Seis",
|
||||
"27": "Vinte e Sete",
|
||||
"28": "Vinte e Oito",
|
||||
"29": "Vinte e Nove",
|
||||
"21": "Vinte e um",
|
||||
"22": "Vinte e dois",
|
||||
"23": "Vinte e três",
|
||||
"24": "Vinte e quatro",
|
||||
"25": "Vinte e cinco",
|
||||
"26": "Vinte e seis",
|
||||
"27": "Vinte e sete",
|
||||
"28": "Vinte e oito",
|
||||
"29": "Vinte e nove",
|
||||
"30": "Trinta",
|
||||
"31": "Trinta e Um",
|
||||
"32": "Trinta e Dois",
|
||||
"33": "Trinta e Três",
|
||||
"34": "Trinta e Quatro",
|
||||
"35": "Trinta e Cinco",
|
||||
"36": "Trinta e Seis",
|
||||
"37": "Trinta e Sete",
|
||||
"38": "Trinta e Oito",
|
||||
"39": "Trinta e Nove",
|
||||
"31": "Trinta e um",
|
||||
"32": "Trinta e dois",
|
||||
"33": "Trinta e três",
|
||||
"34": "Trinta e quatro",
|
||||
"35": "Trinta e cinco",
|
||||
"36": "Trinta e seis",
|
||||
"37": "Trinta e sete",
|
||||
"38": "Trinta e oito",
|
||||
"39": "Trinta e nove",
|
||||
"40": "Quarenta",
|
||||
"41": "Quarenta e Um",
|
||||
"42": "Quarenta e Dois",
|
||||
"43": "Quarenta e Três",
|
||||
"44": "Quarenta e Quatro",
|
||||
"45": "Quarenta e Cinco",
|
||||
"46": "Quarenta e Seis",
|
||||
"47": "Quarenta e Sete",
|
||||
"48": "Quarenta e Oito",
|
||||
"49": "Quarenta e Nove",
|
||||
"41": "Quarenta e um",
|
||||
"42": "Quarenta e dois",
|
||||
"43": "Quarenta e três",
|
||||
"44": "Quarenta e quatro",
|
||||
"45": "Quarenta e cinco",
|
||||
"46": "Quarenta e seis",
|
||||
"47": "Quarenta e sete",
|
||||
"48": "Quarenta e oito",
|
||||
"49": "Quarenta e nove",
|
||||
"50": "Cinquenta",
|
||||
"51": "Cinquenta e Um",
|
||||
"52": "Cinquenta e Dois",
|
||||
"53": "Cinquenta e Três",
|
||||
"54": "Cinquenta e Quatro",
|
||||
"55": "Cinquenta e Cinco",
|
||||
"56": "Cinquenta e Seis",
|
||||
"57": "Cinquenta e Sete",
|
||||
"58": "Cinquenta e Oito",
|
||||
"59": "Cinquenta e Nove",
|
||||
"51": "Cinquenta e um",
|
||||
"52": "Cinquenta e dois",
|
||||
"53": "Cinquenta e três",
|
||||
"54": "Cinquenta e quatro",
|
||||
"55": "Cinquenta e cinco",
|
||||
"56": "Cinquenta e seis",
|
||||
"57": "Cinquenta e sete",
|
||||
"58": "Cinquenta e oito",
|
||||
"59": "Cinquenta e nove",
|
||||
"60": "Sessenta",
|
||||
"61": "Sessenta e Um",
|
||||
"62": "Sessenta e Dois",
|
||||
"63": "Sessenta e Três",
|
||||
"64": "Sessenta e Quatro",
|
||||
"65": "Sessenta e Cinco",
|
||||
"66": "Sessenta e Seis",
|
||||
"67": "Sessenta e Sete",
|
||||
"68": "Sessenta e Oito",
|
||||
"69": "Sessenta e Nove",
|
||||
"61": "Sessenta e um",
|
||||
"62": "Sessenta e dois",
|
||||
"63": "Sessenta e três",
|
||||
"64": "Sessenta e quatro",
|
||||
"65": "Sessenta e cinco",
|
||||
"66": "Sessenta e seis",
|
||||
"67": "Sessenta e sete",
|
||||
"68": "Sessenta e oito",
|
||||
"69": "Sessenta e nove",
|
||||
"70": "Setenta",
|
||||
"71": "Setenta e Um",
|
||||
"72": "Setenta e Dois",
|
||||
"73": "Setenta e Três",
|
||||
"74": "Setenta e Quatro",
|
||||
"75": "Setenta e Cinco",
|
||||
"76": "Setenta e Seis",
|
||||
"77": "Setenta e Sete",
|
||||
"78": "Setenta e Oito",
|
||||
"79": "Setenta e Nove",
|
||||
"71": "Setenta e um",
|
||||
"72": "Setenta e dois",
|
||||
"73": "Setenta e três",
|
||||
"74": "Setenta e quatro",
|
||||
"75": "Setenta e cinco",
|
||||
"76": "Setenta e seis",
|
||||
"77": "Setenta e sete",
|
||||
"78": "Setenta e oito",
|
||||
"79": "Setenta e nove",
|
||||
"80": "Oitenta",
|
||||
"81": "Oitenta e Um",
|
||||
"82": "Oitenta e Dois",
|
||||
"83": "Oitenta e Três",
|
||||
"84": "Oitenta e Quatro",
|
||||
"85": "Oitenta e Cinco",
|
||||
"86": "Oitenta e Seis",
|
||||
"87": "Oitenta e Sete",
|
||||
"88": "Oitenta e Oito",
|
||||
"89": "Oitenta e Nove",
|
||||
"81": "Oitenta e um",
|
||||
"82": "Oitenta e dois",
|
||||
"83": "Oitenta e três",
|
||||
"84": "Oitenta e quatro",
|
||||
"85": "Oitenta e cinco",
|
||||
"86": "Oitenta e seis",
|
||||
"87": "Oitenta e sete",
|
||||
"88": "Oitenta e oito",
|
||||
"89": "Oitenta e nove",
|
||||
"90": "Noventa",
|
||||
"91": "Noventa e Um",
|
||||
"92": "Noventa e Dois",
|
||||
"93": "Noventa e Três",
|
||||
"94": "Noventa e Quatro",
|
||||
"95": "Noventa e Cinco",
|
||||
"96": "Noventa e Seis",
|
||||
"97": "Noventa e Sete",
|
||||
"98": "Noventa e Oito",
|
||||
"99": "Noventa e Nove"
|
||||
"91": "Noventa e um",
|
||||
"92": "Noventa e dois",
|
||||
"93": "Noventa e três",
|
||||
"94": "Noventa e quatro",
|
||||
"95": "Noventa e cinco",
|
||||
"96": "Noventa e seis",
|
||||
"97": "Noventa e sete",
|
||||
"98": "Noventa e oito",
|
||||
"99": "Noventa e nove"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
{
|
||||
"Synopsis": "Сводка",
|
||||
"Short Description": "Краткое описание",
|
||||
"Comment": "Комментарий",
|
||||
"Notes": "Заметки",
|
||||
"Tag": "Тэг",
|
||||
"Point of View": "Точка зрения",
|
||||
"Focus": "Фокус",
|
||||
"Characters": "Персонажей",
|
||||
"Plot": "Сюжет",
|
||||
"Timeline": "Хронология",
|
||||
"Locations": "Локации",
|
||||
"Objects": "Объекты",
|
||||
"Entities": "Сущности",
|
||||
"Custom": "Другое",
|
||||
"0": "Ноль",
|
||||
"1": "Один",
|
||||
"2": "Два",
|
||||
|
||||
@@ -44,6 +44,7 @@ cls_template = mixed_document-new.svg
|
||||
cls_timeline = typ_calendar.svg
|
||||
cls_trash = typ_trash.svg
|
||||
cls_world = typ_location.svg
|
||||
copy = mixed_copy.svg
|
||||
cross = typ_times.svg
|
||||
document = typ_document.svg
|
||||
down = typ_chevron-down.svg
|
||||
@@ -59,9 +60,14 @@ fmt_strike-md = nw_tb-strike-md.svg
|
||||
fmt_subscript = nw_tb-subscript.svg
|
||||
fmt_superscript = nw_tb-superscript.svg
|
||||
fmt_underline = nw_tb-underline.svg
|
||||
font = nw_font.svg
|
||||
forward = typ_chevron-right.svg
|
||||
import = mixed_import.svg
|
||||
list = typ_th-list.svg
|
||||
margin_bottom = mixed_margin-bottom.svg
|
||||
margin_left = mixed_margin-left.svg
|
||||
margin_right = mixed_margin-right.svg
|
||||
margin_top = mixed_margin-top.svg
|
||||
maximise = typ_arrow-maximise.svg
|
||||
menu = typ_th-dot-menu.svg
|
||||
minimise = typ_arrow-minimise.svg
|
||||
@@ -78,6 +84,7 @@ proj_scene = mixed_document-scene.svg
|
||||
proj_section = mixed_document-section.svg
|
||||
proj_stats = typ_chart-bar-grey.svg
|
||||
proj_title = mixed_document-title.svg
|
||||
quote = nw_quote.svg
|
||||
refresh = typ_refresh.svg
|
||||
remove = typ_minus.svg
|
||||
revert = typ_refresh-flipped.svg
|
||||
@@ -91,6 +98,8 @@ search_regex = nw_search-regex.svg
|
||||
search_replace = mixed_search-replace.svg
|
||||
search_word = nw_search-word.svg
|
||||
settings = typ_cog.svg
|
||||
size_height = mixed_size-height.svg
|
||||
size_width = mixed_size-width.svg
|
||||
star = typ_star.svg
|
||||
status_idle = typ_media-pause-grey.svg
|
||||
status_lang = typ_globe-grey.svg
|
||||
@@ -99,6 +108,7 @@ status_stats = typ_chart-bar-grey.svg
|
||||
status_time = typ_stopwatch-grey.svg
|
||||
sticky-off = typ_pin-outline.svg
|
||||
sticky-on = typ_pin.svg
|
||||
toolbar = nw_toolbar.svg
|
||||
unchecked = mixed_input-unchecked.svg
|
||||
unfold-hide = typ_unfold-hidden.svg
|
||||
unfold-show = typ_unfold-visible.svg
|
||||
|
||||
4
novelwriter/assets/icons/typicons_dark/mixed_copy.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m7.8824 2c-1.2988 0-2.3529 1.0541-2.3529 2.3529v2.3529h-1.1765c-1.2988 0-2.3529 1.0541-2.3529 2.3529v10.588c0 1.2988 1.0541 2.3529 2.3529 2.3529h10.588c1.2988 0 2.3529-1.0541 2.3529-2.3529v-1.1765h2.3529c1.2988 0 2.3529-1.0541 2.3529-2.3529v-11.765c0-1.2988-1.0541-2.3529-2.3529-2.3529zm0 2.3529h11.765v11.765h-2.3529v-7.0588c0-1.2988-1.0541-2.3529-2.3529-2.3529h-7.0588zm-3.5294 4.7059h10.588c0.32353 0 0-0.32353 0 0v10.588h-10.588v-9.8943z" fill="#69c" stroke-width="1.1765"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 633 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#e6e6e6" fill-opacity=".14902" stroke-linecap="round" stroke-width="2"/>
|
||||
<rect x="2" y="18" width="20" height="4" rx="1" ry="1" fill="#848484" stroke-linecap="round" stroke-width="2"/>
|
||||
<path d="m18.414 8.5959c0.78104 0.79361 0.78104 2.0837 0 2.8773l-6.4141 6.5268-6.4141-6.5268c-0.391-0.3968-0.58601-0.91769-0.58601-1.4386 0-0.52092 0.195-1.0418 0.58601-1.4386 0.78104-0.79464 2.047-0.79464 2.8281 0l3.5861 3.6475 3.5861-3.6475c0.78104-0.79464 2.047-0.79464 2.8281 0z" fill="#69c" stroke-width="1.0087"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 713 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#e6e6e6" fill-opacity=".14902" stroke-linecap="round" stroke-width="2"/>
|
||||
<rect x="2" y="2" width="4" height="20" rx="1" ry="1" fill="#848484" stroke-linecap="round" stroke-width="2"/>
|
||||
<path d="m15.404 18.5c-0.79361 0.78104-2.0837 0.78104-2.8773 0l-6.5268-6.4141 6.5268-6.4141c0.3968-0.391 0.91769-0.58601 1.4386-0.58601 0.52092 0 1.0418 0.195 1.4386 0.58601 0.79464 0.78104 0.79464 2.047 0 2.8281l-3.6475 3.5861 3.6475 3.5861c0.79464 0.78104 0.79464 2.047 0 2.8281z" fill="#69c" stroke-width="1.0087"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 711 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#e6e6e6" fill-opacity=".14902" stroke-linecap="round" stroke-width="2"/>
|
||||
<rect x="18" y="2" width="4" height="20" rx="1" ry="1" fill="#848484" stroke-linecap="round" stroke-width="2"/>
|
||||
<path d="m8.5959 18.5c0.79361 0.78104 2.0837 0.78104 2.8773 0l6.5268-6.4141-6.5268-6.4141c-0.3968-0.391-0.91769-0.58601-1.4386-0.58601-0.52092 0-1.0418 0.195-1.4386 0.58601-0.79464 0.78104-0.79464 2.047 0 2.8281l3.6475 3.5861-3.6475 3.5861c-0.79464 0.78104-0.79464 2.047 0 2.8281z" fill="#69c" stroke-width="1.0087"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 711 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#e6e6e6" fill-opacity=".14902" stroke-linecap="round" stroke-width="2"/>
|
||||
<rect x="2" y="2" width="20" height="4" rx="1" ry="1" fill="#848484" stroke-linecap="round" stroke-width="2"/>
|
||||
<path d="m18.414 15.404c0.78104-0.79361 0.78104-2.0837 0-2.8773l-6.4141-6.5268-6.4141 6.5268c-0.391 0.3968-0.58601 0.91769-0.58601 1.4386 0 0.52092 0.195 1.0418 0.58601 1.4386 0.78104 0.79464 2.047 0.79464 2.8281 0l3.5861-3.6475 3.5861 3.6475c0.78104 0.79464 2.047 0.79464 2.8281 0z" fill="#69c" stroke-width="1.0087"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 712 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#e6e6e6" fill-opacity=".14902" stroke-linecap="round" stroke-width="2"/>
|
||||
<path d="m18.414 10.404c0.78104-0.79361 0.78104-2.0837 0-2.8773l-6.4141-6.5268-6.4141 6.5268c-0.391 0.3968-0.58601 0.91769-0.58601 1.4386 0 0.52092 0.195 1.0418 0.58601 1.4386 0.78104 0.79464 2.047 0.79464 2.8281 0l3.5861-3.6475 3.5861 3.6475c0.78104 0.79464 2.047 0.79464 2.8281 0z" fill="#69c" stroke-width="1.0087"/>
|
||||
<path d="m18.414 13.596c0.78104 0.79361 0.78104 2.0837 0 2.8773l-6.4141 6.5268-6.4141-6.5268c-0.391-0.3968-0.58601-0.91769-0.58601-1.4386 0-0.52092 0.195-1.0418 0.58601-1.4386 0.78104-0.79464 2.047-0.79464 2.8281 0l3.5861 3.6475 3.5861-3.6475c0.78104-0.79464 2.047-0.79464 2.8281 0z" fill="#69c" stroke-width="1.0087"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 921 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#e6e6e6" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
|
||||
<path d="m13.596 18.414c0.79361 0.78104 2.0837 0.78104 2.8773 0l6.5268-6.4141-6.5268-6.4141c-0.3968-0.391-0.91769-0.58601-1.4386-0.58601-0.52092 0-1.0418 0.195-1.4386 0.58601-0.79464 0.78104-0.79464 2.047 0 2.8281l3.6475 3.5861-3.6475 3.5861c-0.79464 0.78104-0.79464 2.047 0 2.8281z" fill="#69c" stroke-width="1.0087"/>
|
||||
<path d="m10.404 18.414c-0.79361 0.78104-2.0837 0.78104-2.8773 0l-6.5268-6.4141 6.5268-6.4141c0.3968-0.391 0.91769-0.58601 1.4386-0.58601 0.52092 0 1.0418 0.195 1.4386 0.58601 0.79464 0.78104 0.79464 2.047 0 2.8281l-3.6475 3.5861 3.6475 3.5861c0.79464 0.78104 0.79464 2.047 0 2.8281z" fill="#69c" stroke-width="1.0087"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 919 B |
4
novelwriter/assets/icons/typicons_dark/nw_font.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m2.5744 5.8208v-4.2853h-1.4527v-1.0064h4.1067v1.0064h-1.4527v4.2853z" fill="#aeaeae" stroke-width="1.1503"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 267 B |
4
novelwriter/assets/icons/typicons_dark/nw_quote.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m1.3715 3.0659q-0.32092-0.25674-0.44928-0.44928-0.12836-0.19255-0.12837-0.44928 0-0.42361 0.28241-0.69319 0.28241-0.28241 0.68035-0.28241 0.25674 0 0.44928 0.10269 0.19255 0.089858 0.3466 0.23106 0.24391 0.4878 0.24391 1.0141 0 0.42361-0.14121 0.82157-0.12837 0.38511-0.37227 0.71886-0.23106 0.33377-0.55199 0.61618-0.30808 0.26958-0.65467 0.46213l-0.25674-0.41078q0.29525-0.21822 0.57766-0.53914 0.28241-0.33375 0.46213-0.73171zm2.7598 0q-0.32092-0.25674-0.44928-0.44928-0.12837-0.19255-0.12837-0.44928 0-0.42361 0.28241-0.69319 0.28241-0.28241 0.68035-0.28241 0.25674 0 0.44928 0.10269 0.19255 0.089858 0.3466 0.23106 0.24391 0.4878 0.24391 1.0141 0 0.42361-0.14121 0.82157-0.12837 0.38511-0.37227 0.71886-0.23106 0.33377-0.55199 0.61618-0.30808 0.26958-0.65467 0.46213l-0.25674-0.41078q0.29525-0.21822 0.57766-0.53914 0.28241-0.33375 0.46213-0.73171z" fill="#aeaeae" fill-opacity=".78039" stroke-width="1.8194"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
5
novelwriter/assets/icons/typicons_dark/nw_toolbar.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="8" y="2" width="8" height="8" rx="1" ry="1" fill="none" stroke="#69c" stroke-linecap="round" stroke-width="2"/>
|
||||
<rect x="8" y="14" width="8" height="8" rx="1" ry="1" fill="none" stroke="#69c" stroke-linecap="round" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 389 B |
@@ -44,6 +44,7 @@ cls_template = mixed_document-new.svg
|
||||
cls_timeline = typ_calendar.svg
|
||||
cls_trash = typ_trash.svg
|
||||
cls_world = typ_location.svg
|
||||
copy = mixed_copy.svg
|
||||
cross = typ_times.svg
|
||||
document = typ_document.svg
|
||||
down = typ_chevron-down.svg
|
||||
@@ -59,9 +60,14 @@ fmt_strike-md = nw_tb-strike-md.svg
|
||||
fmt_subscript = nw_tb-subscript.svg
|
||||
fmt_superscript = nw_tb-superscript.svg
|
||||
fmt_underline = nw_tb-underline.svg
|
||||
font = nw_font.svg
|
||||
forward = typ_chevron-right.svg
|
||||
import = mixed_import.svg
|
||||
list = typ_th-list.svg
|
||||
margin_bottom = mixed_margin-bottom.svg
|
||||
margin_left = mixed_margin-left.svg
|
||||
margin_right = mixed_margin-right.svg
|
||||
margin_top = mixed_margin-top.svg
|
||||
maximise = typ_arrow-maximise.svg
|
||||
menu = typ_th-dot-menu.svg
|
||||
minimise = typ_arrow-minimise.svg
|
||||
@@ -78,6 +84,7 @@ proj_scene = mixed_document-scene.svg
|
||||
proj_section = mixed_document-section.svg
|
||||
proj_stats = typ_chart-bar-grey.svg
|
||||
proj_title = mixed_document-title.svg
|
||||
quote = nw_quote.svg
|
||||
refresh = typ_refresh.svg
|
||||
remove = typ_minus.svg
|
||||
revert = typ_refresh-flipped.svg
|
||||
@@ -91,6 +98,8 @@ search_regex = nw_search-regex.svg
|
||||
search_replace = mixed_search-replace.svg
|
||||
search_word = nw_search-word.svg
|
||||
settings = typ_cog.svg
|
||||
size_height = mixed_size-height.svg
|
||||
size_width = mixed_size-width.svg
|
||||
star = typ_star.svg
|
||||
status_idle = typ_media-pause-grey.svg
|
||||
status_lang = typ_globe-grey.svg
|
||||
@@ -99,6 +108,7 @@ status_stats = typ_chart-bar-grey.svg
|
||||
status_time = typ_stopwatch-grey.svg
|
||||
sticky-off = typ_pin-outline.svg
|
||||
sticky-on = typ_pin.svg
|
||||
toolbar = nw_toolbar.svg
|
||||
unchecked = mixed_input-unchecked.svg
|
||||
unfold-hide = typ_unfold-hidden.svg
|
||||
unfold-show = typ_unfold-visible.svg
|
||||
|
||||
4
novelwriter/assets/icons/typicons_light/mixed_copy.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m7.8824 2c-1.2988 0-2.3529 1.0541-2.3529 2.3529v2.3529h-1.1765c-1.2988 0-2.3529 1.0541-2.3529 2.3529v10.588c0 1.2988 1.0541 2.3529 2.3529 2.3529h10.588c1.2988 0 2.3529-1.0541 2.3529-2.3529v-1.1765h2.3529c1.2988 0 2.3529-1.0541 2.3529-2.3529v-11.765c0-1.2988-1.0541-2.3529-2.3529-2.3529zm0 2.3529h11.765v11.765h-2.3529v-7.0588c0-1.2988-1.0541-2.3529-2.3529-2.3529h-7.0588zm-3.5294 4.7059h10.588c0.32353 0 0-0.32353 0 0v10.588h-10.588v-9.8943z" fill="#4271ae" stroke-width="1.1765"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 636 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#333" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
|
||||
<rect x="2" y="18" width="20" height="4" rx="1" ry="1" fill="#333" stroke-linecap="round" stroke-width="2"/>
|
||||
<path d="m18.414 8.5959c0.78104 0.79361 0.78104 2.0837 0 2.8773l-6.4141 6.5268-6.4141-6.5268c-0.391-0.3968-0.58601-0.91769-0.58601-1.4386 0-0.52092 0.195-1.0418 0.58601-1.4386 0.78104-0.79464 2.047-0.79464 2.8281 0l3.5861 3.6475 3.5861-3.6475c0.78104-0.79464 2.047-0.79464 2.8281 0z" fill="#4271ae" stroke-width="1.0087"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 707 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#333" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
|
||||
<rect x="2" y="2" width="4" height="20" rx="1" ry="1" fill="#333" stroke-linecap="round" stroke-width="2"/>
|
||||
<path d="m15.404 18.5c-0.79361 0.78104-2.0837 0.78104-2.8773 0l-6.5268-6.4141 6.5268-6.4141c0.3968-0.391 0.91769-0.58601 1.4386-0.58601 0.52092 0 1.0418 0.195 1.4386 0.58601 0.79464 0.78104 0.79464 2.047 0 2.8281l-3.6475 3.5861 3.6475 3.5861c0.79464 0.78104 0.79464 2.047 0 2.8281z" fill="#4271ae" stroke-width="1.0087"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 705 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#333" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
|
||||
<rect x="18" y="2" width="4" height="20" rx="1" ry="1" fill="#333" stroke-linecap="round" stroke-width="2"/>
|
||||
<path d="m8.5959 18.5c0.79361 0.78104 2.0837 0.78104 2.8773 0l6.5268-6.4141-6.5268-6.4141c-0.3968-0.391-0.91769-0.58601-1.4386-0.58601-0.52092 0-1.0418 0.195-1.4386 0.58601-0.79464 0.78104-0.79464 2.047 0 2.8281l3.6475 3.5861-3.6475 3.5861c-0.79464 0.78104-0.79464 2.047 0 2.8281z" fill="#4271ae" stroke-width="1.0087"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 705 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#333" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
|
||||
<rect x="2" y="2" width="20" height="4" rx="1" ry="1" fill="#333" stroke-linecap="round" stroke-width="2"/>
|
||||
<path d="m18.414 15.404c0.78104-0.79361 0.78104-2.0837 0-2.8773l-6.4141-6.5268-6.4141 6.5268c-0.391 0.3968-0.58601 0.91769-0.58601 1.4386 0 0.52092 0.195 1.0418 0.58601 1.4386 0.78104 0.79464 2.047 0.79464 2.8281 0l3.5861-3.6475 3.5861 3.6475c0.78104 0.79464 2.047 0.79464 2.8281 0z" fill="#4271ae" stroke-width="1.0087"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 706 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#333" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
|
||||
<path d="m18.414 10.404c0.78104-0.79361 0.78104-2.0837 0-2.8773l-6.4141-6.5268-6.4141 6.5268c-0.391 0.3968-0.58601 0.91769-0.58601 1.4386 0 0.52092 0.195 1.0418 0.58601 1.4386 0.78104 0.79464 2.047 0.79464 2.8281 0l3.5861-3.6475 3.5861 3.6475c0.78104 0.79464 2.047 0.79464 2.8281 0z" fill="#4271ae" stroke-width="1.0087"/>
|
||||
<path d="m18.414 13.596c0.78104 0.79361 0.78104 2.0837 0 2.8773l-6.4141 6.5268-6.4141-6.5268c-0.391-0.3968-0.58601-0.91769-0.58601-1.4386 0-0.52092 0.195-1.0418 0.58601-1.4386 0.78104-0.79464 2.047-0.79464 2.8281 0l3.5861 3.6475 3.5861-3.6475c0.78104-0.79464 2.047-0.79464 2.8281 0z" fill="#4271ae" stroke-width="1.0087"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 921 B |
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="2" y="2" width="20" height="20" rx="1" ry="1" fill="#333" fill-opacity=".15" stroke-linecap="round" stroke-width="2"/>
|
||||
<path d="m13.596 18.414c0.79361 0.78104 2.0837 0.78104 2.8773 0l6.5268-6.4141-6.5268-6.4141c-0.3968-0.391-0.91769-0.58601-1.4386-0.58601-0.52092 0-1.0418 0.195-1.4386 0.58601-0.79464 0.78104-0.79464 2.047 0 2.8281l3.6475 3.5861-3.6475 3.5861c-0.79464 0.78104-0.79464 2.047 0 2.8281z" fill="#4271ae" stroke-width="1.0087"/>
|
||||
<path d="m10.404 18.414c-0.79361 0.78104-2.0837 0.78104-2.8773 0l-6.5268-6.4141 6.5268-6.4141c0.3968-0.391 0.91769-0.58601 1.4386-0.58601 0.52092 0 1.0418 0.195 1.4386 0.58601 0.79464 0.78104 0.79464 2.047 0 2.8281l-3.6475 3.5861 3.6475 3.5861c0.79464 0.78104 0.79464 2.047 0 2.8281z" fill="#4271ae" stroke-width="1.0087"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 922 B |
4
novelwriter/assets/icons/typicons_light/nw_font.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m2.5744 5.8208v-4.2853h-1.4527v-1.0064h4.1067v1.0064h-1.4527v4.2853z" fill-opacity=".78039" stroke-width="1.1503"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 274 B |
4
novelwriter/assets/icons/typicons_light/nw_quote.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m1.3715 3.0659q-0.32092-0.25674-0.44928-0.44928-0.12836-0.19255-0.12837-0.44928 0-0.42361 0.28241-0.69319 0.28241-0.28241 0.68035-0.28241 0.25674 0 0.44928 0.10269 0.19255 0.089858 0.3466 0.23106 0.24391 0.4878 0.24391 1.0141 0 0.42361-0.14121 0.82157-0.12837 0.38511-0.37227 0.71886-0.23106 0.33377-0.55199 0.61618-0.30808 0.26958-0.65467 0.46213l-0.25674-0.41078q0.29525-0.21822 0.57766-0.53914 0.28241-0.33375 0.46213-0.73171zm2.7598 0q-0.32092-0.25674-0.44928-0.44928-0.12837-0.19255-0.12837-0.44928 0-0.42361 0.28241-0.69319 0.28241-0.28241 0.68035-0.28241 0.25674 0 0.44928 0.10269 0.19255 0.089858 0.3466 0.23106 0.24391 0.4878 0.24391 1.0141 0 0.42361-0.14121 0.82157-0.12837 0.38511-0.37227 0.71886-0.23106 0.33377-0.55199 0.61618-0.30808 0.26958-0.65467 0.46213l-0.25674-0.41078q0.29525-0.21822 0.57766-0.53914 0.28241-0.33375 0.46213-0.73171z" fill-opacity=".78039" stroke-width="1.8194"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
5
novelwriter/assets/icons/typicons_light/nw_toolbar.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.2" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="8" y="2" width="8" height="8" rx="1" ry="1" fill="none" stroke="#4271ae" stroke-linecap="round" stroke-width="2"/>
|
||||
<rect x="8" y="14" width="8" height="8" rx="1" ry="1" fill="none" stroke="#4271ae" stroke-linecap="round" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 395 B |
@@ -12,15 +12,17 @@ link = 77, 077, 255
|
||||
headertext = 255, 255, 255
|
||||
headertag = 50, 0, 180
|
||||
emphasis = 0, 255, 255
|
||||
straightquotes = 7, 27, 219
|
||||
doublequotes = 0, 255, 0
|
||||
singlequotes = 0, 140, 255
|
||||
dialog = 0, 255, 0
|
||||
altdialog = 0, 140, 255
|
||||
note = 150, 150, 150
|
||||
hidden = 77, 77, 100
|
||||
shortcode = 255, 255, 0
|
||||
keyword = 255, 100, 255
|
||||
tag = 255, 150, 10
|
||||
value = 255, 150, 10
|
||||
spellcheckline = 242, 72, 23
|
||||
errorline = 186, 218, 4
|
||||
replacetag = 0, 0, 180
|
||||
modifier = 144, 142, 176
|
||||
optional = 180, 180, 180
|
||||
texthighlight = 255, 255, 132, 96
|
||||
|
||||
@@ -6,23 +6,37 @@ url = https://github.com/vkbo/novelWriter
|
||||
license = CC BY-SA 4.0
|
||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
##
|
||||
# Colours:
|
||||
# Background = 2a2a2a : 42, 42, 42
|
||||
# Foreground = cccccc : 204, 204, 204
|
||||
# Comment = 969696 : 150, 150, 150
|
||||
# Red = e64250 : 230, 66, 80
|
||||
# Orange = f99157 : 249, 145, 87
|
||||
# Yellow = ffff84 : 255, 255, 132
|
||||
# Green = 99cc99 : 153, 204, 153
|
||||
# Blue = 288ed7 : 102, 153, 204
|
||||
# Purple = 8c56d7 : 140, 86, 215
|
||||
##
|
||||
|
||||
[Syntax]
|
||||
background = 54, 54, 54
|
||||
text = 199, 207, 208
|
||||
link = 184, 200, 0
|
||||
headertext = 0, 155, 200
|
||||
headertag = 0, 105, 135
|
||||
emphasis = 200, 120, 0
|
||||
straightquotes = 200, 46, 0
|
||||
doublequotes = 184, 200, 0
|
||||
singlequotes = 136, 200, 0
|
||||
background = 42, 42, 42
|
||||
text = 204, 204, 204
|
||||
link = 102, 153, 204
|
||||
headertext = 153, 204, 153
|
||||
headertag = 153, 204, 153, 160
|
||||
emphasis = 249, 145, 87
|
||||
dialog = 102, 153, 204
|
||||
altdialog = 102, 153, 204
|
||||
note = 255, 255, 216
|
||||
hidden = 150, 150, 150
|
||||
shortcode = 0, 155, 200
|
||||
keyword = 200, 46, 0
|
||||
value = 184, 200, 0
|
||||
optional = 0, 155, 200
|
||||
spellcheckline = 200, 46, 0
|
||||
errorline = 46, 200, 0
|
||||
replacetag = 0, 184, 46
|
||||
modifier = 200, 120, 0
|
||||
texthighlight = 136, 200, 0, 96
|
||||
shortcode = 153, 204, 153
|
||||
keyword = 230, 66, 80
|
||||
tag = 153, 204, 153
|
||||
value = 102, 153, 204
|
||||
optional = 153, 204, 153
|
||||
spellcheckline = 230, 66, 80
|
||||
errorline = 153, 204, 153
|
||||
replacetag = 153, 204, 153
|
||||
modifier = 153, 204, 153
|
||||
texthighlight = 255, 255, 132, 96
|
||||
|
||||
@@ -6,23 +6,37 @@ url = https://github.com/vkbo/novelWriter
|
||||
license = CC BY-SA 4.0
|
||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
##
|
||||
# Colours:
|
||||
# Background = ffffff : 255, 255, 255
|
||||
# Foreground = 000000 : 0, 0, 0
|
||||
# Comment = 646464 : 100, 100, 100
|
||||
# Red = c83232 : 200, 50, 50
|
||||
# Orange = ae6e1e : 174, 110, 30
|
||||
# Yellow = 969600 : 150, 150, 0
|
||||
# Green = 006400 : 0, 100, 0
|
||||
# Blue = 0000c8 : 0, 0, 200
|
||||
# Purple = 6400ae : 100, 0, 174
|
||||
##
|
||||
|
||||
[Syntax]
|
||||
background = 255, 255, 255
|
||||
text = 0, 0, 0
|
||||
link = 0, 0, 200
|
||||
headertext = 0, 100, 0
|
||||
headertag = 50, 100, 50
|
||||
emphasis = 150, 110, 30
|
||||
straightquotes = 200, 0, 0
|
||||
doublequotes = 0, 0, 200
|
||||
singlequotes = 0, 0, 200
|
||||
headertag = 0, 100, 0, 160
|
||||
emphasis = 174, 110, 30
|
||||
dialog = 0, 0, 200
|
||||
altdialog = 0, 0, 200
|
||||
note = 100, 100, 0
|
||||
hidden = 100, 100, 100
|
||||
shortcode = 0, 100, 0
|
||||
keyword = 200, 50, 50
|
||||
value = 50, 150, 50
|
||||
tag = 0, 100, 0
|
||||
value = 0, 0, 200
|
||||
optional = 0, 100, 0
|
||||
spellcheckline = 200, 0, 0
|
||||
errorline = 0, 150, 0
|
||||
replacetag = 0, 150, 0
|
||||
modifier = 150, 110, 30
|
||||
spellcheckline = 200, 50, 50
|
||||
errorline = 0, 100, 0
|
||||
replacetag = 0, 100, 0
|
||||
modifier = 0, 100, 0
|
||||
texthighlight = 150, 150, 0, 96
|
||||
|
||||
44
novelwriter/assets/syntax/dracula.conf
Normal file
@@ -0,0 +1,44 @@
|
||||
[Main]
|
||||
name = Dracula
|
||||
author = Veronica Berglyd Olsen (adaptation)
|
||||
credit = Zeno Rocha
|
||||
url = https://draculatheme.com
|
||||
license = MIT
|
||||
licenseurl = https://github.com/dracula/dracula-theme/blob/main/LICENSE
|
||||
|
||||
##
|
||||
# Colours:
|
||||
# Background = 282a36 : 40, 42, 54
|
||||
# Foreground = f8f8f2 : 248, 248, 242
|
||||
# Comment = 6272a4 : 98, 114, 164
|
||||
# Cyan = 8be9fd : 139, 233, 253
|
||||
# Green = 50fa7b : 80, 250, 123
|
||||
# Orange = ffb86c : 255, 184, 108
|
||||
# Pink = ff79c6 : 255, 121, 198
|
||||
# Purple = bd93f9 : 189, 147, 249
|
||||
# Red = ff5555 : 255, 85, 85
|
||||
# Yellow = f1fa8c : 241, 250, 140
|
||||
##
|
||||
|
||||
[Syntax]
|
||||
# See: https://spec.draculatheme.com/
|
||||
background = 40, 42, 54
|
||||
text = 248, 248, 242
|
||||
link = 255, 121, 198
|
||||
headertext = 189, 147, 249
|
||||
headertag = 189, 147, 249, 160
|
||||
emphasis = 255, 184, 108
|
||||
dialog = 80, 250, 123
|
||||
altdialog = 241, 250, 140
|
||||
note = 255, 204, 233
|
||||
hidden = 98, 114, 164
|
||||
shortcode = 139, 233, 253
|
||||
keyword = 255, 121, 198
|
||||
tag = 255, 184, 108
|
||||
value = 255, 184, 108
|
||||
optional = 80, 250, 123
|
||||
spellcheckline = 255, 85, 85
|
||||
errorline = 80, 250, 123
|
||||
replacetag = 241, 250, 140
|
||||
modifier = 139, 233, 253
|
||||
texthighlight = 241, 250, 140, 96
|
||||
@@ -11,14 +11,15 @@ background = 54, 54, 54
|
||||
text = 200, 200, 200
|
||||
link = 200, 200, 200
|
||||
headertext = 225, 225, 225
|
||||
headertag = 225, 225, 225
|
||||
headertag = 225, 225, 225, 160
|
||||
emphasis = 200, 200, 200
|
||||
straightquotes = 200, 200, 200
|
||||
doublequotes = 200, 200, 200
|
||||
singlequotes = 200, 200, 200
|
||||
dialog = 200, 200, 200
|
||||
altdialog = 200, 200, 200
|
||||
note = 200, 200, 200
|
||||
hidden = 150, 150, 150
|
||||
shortcode = 225, 225, 225
|
||||
keyword = 225, 225, 225
|
||||
tag = 200, 200, 200
|
||||
value = 200, 200, 200
|
||||
optional = 225, 225, 225
|
||||
spellcheckline = 200, 46, 0
|
||||
|
||||
@@ -11,14 +11,15 @@ background = 255, 255, 255
|
||||
text = 20, 20, 20
|
||||
link = 20, 20, 20
|
||||
headertext = 0, 0, 0
|
||||
headertag = 0, 0, 0
|
||||
headertag = 0, 0, 0, 160
|
||||
emphasis = 20, 20, 20
|
||||
straightquotes = 20, 20, 20
|
||||
doublequotes = 20, 20, 20
|
||||
singlequotes = 20, 20, 20
|
||||
dialog = 20, 20, 20
|
||||
altdialog = 20, 20, 20
|
||||
note = 20, 20, 20
|
||||
hidden = 100, 100, 100
|
||||
shortcode = 0, 0, 0
|
||||
keyword = 0, 0, 0
|
||||
tag = 20, 20, 20
|
||||
value = 20, 20, 20
|
||||
optional = 0, 0, 0
|
||||
spellcheckline = 200, 0, 0
|
||||
|
||||
@@ -31,18 +31,19 @@ background = 251, 251, 251
|
||||
text = 64, 63, 82
|
||||
link = 40, 142, 215
|
||||
headertext = 40, 142, 215
|
||||
headertag = 40, 142, 215
|
||||
headertag = 40, 142, 215, 160
|
||||
emphasis = 224, 175, 5
|
||||
straightquotes = 222, 61, 58
|
||||
doublequotes = 8, 145, 106
|
||||
singlequotes = 255, 235, 149
|
||||
dialog = 8, 145, 106
|
||||
altdialog = 218, 170, 1
|
||||
note = 128, 118, 75
|
||||
hidden = 152, 159, 177
|
||||
shortcode = 40, 142, 215
|
||||
keyword = 222, 61, 58
|
||||
value = 150, 74, 193
|
||||
tag = 150, 74, 193
|
||||
value = 224, 175, 5
|
||||
optional = 40, 142, 215
|
||||
spellcheckline = 222, 61, 58
|
||||
errorline = 8, 145, 106
|
||||
replacetag = 42, 162, 152
|
||||
modifier = 224, 175, 5
|
||||
modifier = 8, 145, 106
|
||||
texthighlight = 218, 170, 1, 96
|
||||
|
||||
@@ -31,18 +31,19 @@ background = 1, 22, 39
|
||||
text = 214, 222, 235
|
||||
link = 130, 170, 255
|
||||
headertext = 130, 170, 255
|
||||
headertag = 130, 170, 255
|
||||
headertag = 130, 170, 255, 160
|
||||
emphasis = 236, 196, 141
|
||||
straightquotes = 247, 140, 108
|
||||
doublequotes = 173, 219, 103
|
||||
singlequotes = 255, 235, 149
|
||||
dialog = 173, 219, 103
|
||||
altdialog = 255, 235, 149
|
||||
note = 255, 249, 202
|
||||
hidden = 99, 119, 119
|
||||
shortcode = 130, 170, 255
|
||||
keyword = 247, 140, 108
|
||||
value = 199, 146, 234
|
||||
tag = 199, 146, 234
|
||||
value = 255, 235, 149
|
||||
optional = 130, 170, 255
|
||||
spellcheckline = 247, 140, 108
|
||||
errorline = 173, 219, 103
|
||||
replacetag = 127, 219, 202
|
||||
modifier = 236, 196, 141
|
||||
modifier = 173, 219, 103
|
||||
texthighlight = 255, 235, 149, 96
|
||||
|
||||
42
novelwriter/assets/syntax/snazzy.conf
Normal file
@@ -0,0 +1,42 @@
|
||||
[Main]
|
||||
name = Snazzy Light
|
||||
author = Veronica Berglyd Olsen (adaptation)
|
||||
credit = Florian Reuschel (color theme)
|
||||
url = https://github.com/loilo/vscode-snazzy-light
|
||||
license = MIT License
|
||||
licenseurl = https://github.com/loilo/vscode-snazzy-light/blob/master/LICENSE
|
||||
|
||||
##
|
||||
# Colours:
|
||||
# Background = fafbfc : 250, 251, 252
|
||||
# Foreground = 565869 : 86, 88, 105
|
||||
# Comment = 9194a2 : 145, 148, 162
|
||||
# Yellow = cf9c00 : 207, 156, 0
|
||||
# Red = ff5c57 : 255, 92, 87
|
||||
# Pink = f767bb : 247, 103, 187
|
||||
# Blue = 09a1ed : 9, 161, 237
|
||||
# Cyan = 13bbb7 : 19, 187, 183
|
||||
# Green = 2dae58 : 45, 174, 88
|
||||
##
|
||||
|
||||
[Syntax]
|
||||
background = 250, 251, 252
|
||||
text = 86, 88, 105
|
||||
link = 9, 161, 237
|
||||
headertext = 45, 174, 88
|
||||
headertag = 45, 174, 88, 160
|
||||
emphasis = 19, 187, 183
|
||||
dialog = 207, 156, 0
|
||||
altdialog = 207, 156, 0
|
||||
note = 120, 187, 185
|
||||
hidden = 145, 148, 162
|
||||
shortcode = 247, 103, 187
|
||||
keyword = 9, 161, 237
|
||||
tag = 45, 174, 88
|
||||
value = 9, 161, 237
|
||||
optional = 207, 156, 0
|
||||
spellcheckline = 255, 92, 87
|
||||
errorline = 45, 174, 88
|
||||
replacetag = 19, 187, 183
|
||||
modifier = 247, 103, 187
|
||||
texthighlight = 207, 156, 0, 96
|
||||
@@ -13,12 +13,13 @@ link = 38, 139, 210
|
||||
headertext = 147, 161, 161
|
||||
headertag = 42, 161, 152
|
||||
emphasis = 38, 139, 210
|
||||
straightquotes = 211, 54, 130
|
||||
doublequotes = 42, 161, 152
|
||||
singlequotes = 42, 161, 152
|
||||
dialog = 42, 161, 152
|
||||
altdialog = 42, 161, 152
|
||||
note = 101, 161, 156
|
||||
hidden = 147, 161, 161
|
||||
shortcode = 147, 161, 161
|
||||
keyword = 133, 153, 0
|
||||
tag = 203, 75, 22
|
||||
value = 203, 75, 22
|
||||
optional = 147, 161, 161
|
||||
spellcheckline = 203, 75, 22
|
||||
|
||||
@@ -13,12 +13,13 @@ link = 38, 139, 210
|
||||
headertext = 88, 110, 117
|
||||
headertag = 42, 161, 152
|
||||
emphasis = 38, 139, 210
|
||||
straightquotes = 211, 54, 130
|
||||
doublequotes = 42, 161, 152
|
||||
singlequotes = 42, 161, 152
|
||||
dialog = 42, 161, 152
|
||||
altdialog = 42, 161, 152
|
||||
note = 27, 102, 96
|
||||
hidden = 88, 110, 117
|
||||
shortcode = 88, 110, 117
|
||||
keyword = 133, 153, 0
|
||||
tag = 203, 75, 22
|
||||
value = 203, 75, 22
|
||||
optional = 88, 110, 117
|
||||
spellcheckline = 203, 75, 22
|
||||
|
||||
@@ -2,22 +2,38 @@
|
||||
name = Tango
|
||||
author = Veronica Berglyd Olsen (adaptation)
|
||||
|
||||
##
|
||||
# Colours:
|
||||
# Background = 30302f : 48, 48, 47
|
||||
# Foreground = eeeeec : 238, 238, 236
|
||||
# Comment = 8f8f8d : 143, 143, 141
|
||||
# Red = ef2929 : 239, 41, 41
|
||||
# Orange = c4a000 : 196, 160, 0
|
||||
# Yellow = fce94f : 252, 233, 79
|
||||
# Green = 8ae234 : 138, 226, 52
|
||||
# Cyan = 34e2e2 : 52, 226, 226
|
||||
# Blue = 3465a4 : 114, 159, 207
|
||||
# Purple = ad7fa8 : 173, 127, 168
|
||||
##
|
||||
|
||||
[Syntax]
|
||||
background = 48, 48, 47
|
||||
text = 238, 238, 236
|
||||
link = 115, 159, 207
|
||||
headertext = 115, 159, 207
|
||||
headertag = 52, 101, 164
|
||||
link = 114, 159, 207
|
||||
headertext = 114, 159, 207
|
||||
headertag = 114, 159, 207, 160
|
||||
emphasis = 196, 160, 0
|
||||
straightquotes = 239, 41, 41
|
||||
doublequotes = 138, 226, 52
|
||||
singlequotes = 252, 233, 79
|
||||
dialog = 138, 226, 52
|
||||
altdialog = 252, 233, 79
|
||||
note = 252, 242, 164
|
||||
hidden = 143, 143, 141
|
||||
shortcode = 115, 159, 207
|
||||
shortcode = 114, 159, 207
|
||||
keyword = 239, 41, 41
|
||||
value = 173, 127, 168
|
||||
optional = 115, 159, 207
|
||||
tag = 173, 127, 168
|
||||
value = 239, 41, 41
|
||||
optional = 114, 159, 207
|
||||
spellcheckline = 239, 41, 41
|
||||
errorline = 138, 226, 52
|
||||
replacetag = 51, 226, 226
|
||||
modifier = 196, 160, 0
|
||||
replacetag = 52, 226, 226
|
||||
modifier = 114, 159, 207
|
||||
texthighlight = 252, 233, 79, 96
|
||||
|
||||
@@ -31,15 +31,16 @@ background = 255, 255, 255
|
||||
text = 77, 77, 76
|
||||
link = 66, 113, 174
|
||||
headertext = 66, 113, 174
|
||||
headertag = 66, 113, 174
|
||||
headertag = 66, 113, 174, 160
|
||||
emphasis = 245, 135, 31
|
||||
straightquotes = 240, 40, 41
|
||||
doublequotes = 113, 140, 0
|
||||
singlequotes = 234, 183, 0
|
||||
dialog = 113, 140, 0
|
||||
altdialog = 234, 183, 0
|
||||
note = 115, 90, 0
|
||||
hidden = 142, 144, 140
|
||||
shortcode = 66, 113, 174
|
||||
keyword = 240, 40, 41
|
||||
value = 137, 89, 168
|
||||
tag = 137, 89, 168
|
||||
value = 234, 183, 0
|
||||
optional = 66, 113, 174
|
||||
spellcheckline = 240, 40, 41
|
||||
errorline = 113, 140, 0
|
||||
|
||||
@@ -29,17 +29,18 @@ licenseurl = https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.
|
||||
[Syntax]
|
||||
background = 29, 31, 33
|
||||
text = 197, 200, 198
|
||||
link = 129, 162, 190
|
||||
link = 197, 200, 198, 160
|
||||
headertext = 129, 162, 190
|
||||
headertag = 129, 162, 190
|
||||
headertag = 94, 119, 139
|
||||
emphasis = 222, 147, 95
|
||||
straightquotes = 204, 102, 102
|
||||
doublequotes = 181, 189, 104
|
||||
singlequotes = 240, 198, 116
|
||||
dialog = 181, 189, 104
|
||||
altdialog = 240, 198, 116
|
||||
note = 240, 219, 178
|
||||
hidden = 150, 152, 150
|
||||
shortcode = 129, 162, 190
|
||||
keyword = 204, 102, 102
|
||||
value = 178, 148, 187
|
||||
tag = 178, 148, 187
|
||||
value = 240, 198, 116
|
||||
optional = 129, 162, 190
|
||||
spellcheckline = 204, 102, 102
|
||||
errorline = 181, 189, 104
|
||||
|
||||
@@ -31,15 +31,16 @@ background = 0, 36, 81
|
||||
text = 255, 255, 255
|
||||
link = 187, 218, 255
|
||||
headertext = 187, 218, 255
|
||||
headertag = 187, 218, 255
|
||||
headertag = 187, 218, 255, 160
|
||||
emphasis = 255, 197, 143
|
||||
straightquotes = 255, 157, 164
|
||||
doublequotes = 209, 241, 169
|
||||
singlequotes = 255, 238, 173
|
||||
dialog = 209, 241, 169
|
||||
altdialog = 255, 238, 173
|
||||
note = 255, 247, 214
|
||||
hidden = 114, 133, 183
|
||||
shortcode = 187, 218, 255
|
||||
keyword = 255, 157, 164
|
||||
value = 235, 187, 255
|
||||
tag = 235, 187, 255
|
||||
value = 255, 238, 173
|
||||
optional = 187, 218, 255
|
||||
spellcheckline = 255, 157, 164
|
||||
errorline = 209, 241, 169
|
||||
|
||||
@@ -31,15 +31,16 @@ background = 0, 0, 0
|
||||
text = 234, 234, 234
|
||||
link = 122, 166, 218
|
||||
headertext = 122, 166, 218
|
||||
headertag = 122, 166, 218
|
||||
headertag = 122, 166, 218, 160
|
||||
emphasis = 231, 140, 69
|
||||
straightquotes = 213, 78, 83
|
||||
doublequotes = 185, 202, 74
|
||||
singlequotes = 231, 197, 71
|
||||
dialog = 185, 202, 74
|
||||
altdialog = 231, 197, 71
|
||||
note = 231, 214, 150
|
||||
hidden = 150, 152, 150
|
||||
shortcode = 122, 166, 218
|
||||
keyword = 213, 78, 83
|
||||
value = 195, 151, 216
|
||||
tag = 195, 151, 216
|
||||
value = 231, 197, 71
|
||||
optional = 122, 166, 218
|
||||
spellcheckline = 213, 78, 83
|
||||
errorline = 185, 202, 74
|
||||
|
||||
@@ -31,15 +31,16 @@ background = 45, 45, 45
|
||||
text = 204, 204, 204
|
||||
link = 102, 153, 204
|
||||
headertext = 102, 153, 204
|
||||
headertag = 102, 153, 204
|
||||
headertag = 102, 153, 204, 160
|
||||
emphasis = 249, 145, 57
|
||||
straightquotes = 242, 119, 122
|
||||
doublequotes = 153, 204, 153
|
||||
singlequotes = 255, 204, 102
|
||||
dialog = 153, 204, 153
|
||||
altdialog = 255, 204, 102
|
||||
note = 255, 230, 179
|
||||
hidden = 153, 153, 153
|
||||
shortcode = 102, 153, 204
|
||||
keyword = 242, 119, 122
|
||||
value = 204, 153, 204
|
||||
tag = 204, 153, 204
|
||||
value = 255, 204, 102
|
||||
optional = 102, 153, 204
|
||||
spellcheckline = 242, 119, 122
|
||||
errorline = 153, 204, 153
|
||||
|
||||
@@ -1,81 +1,93 @@
|
||||
<!DOCTYPE html public "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<h3>Main Developer</h3>
|
||||
<p>Veronica Berglyd Olsen (<a href="https://github.com/vkbo">@vkbo</a>)</p>
|
||||
|
||||
<p>Veronica Berglyd Olsen</p>
|
||||
|
||||
<h3>Contributors</h3>
|
||||
|
||||
<p>
|
||||
• <b>Concept:</b> Marian Lückhof (<a href="https://github.com/Number042">@Number042</a>)<br>
|
||||
• <b>Internationalisation:</b> Bruno Meneguello (<a href="https://github.com/bkmeneguello">@bkmeneguello</a>)<br>
|
||||
• <b>Setup and Packaging:</b> Rachel Powers (<a href="https://github.com/Ryex">@Ryex</a>)
|
||||
</p>
|
||||
<ul>
|
||||
<li><b>Early Concept:</b> Marian Lückhof</li>
|
||||
<li><b>Internationalisation:</b> Bruno Meneguello</li>
|
||||
<li><b>Setup and Packaging:</b> Rachel Powers</li>
|
||||
</ul>
|
||||
|
||||
<p>For other contributions, see the project's
|
||||
<a href="https://github.com/vkbo/novelWriter/graphs/contributors">Contributors</a> page.</p>
|
||||
|
||||
<h3>Artwork</h3>
|
||||
|
||||
<p>The artwork on the Welcome dialog was created by <a href="https://louisdurrant.art">Louis Durrant</a>.</p>
|
||||
<p>The artwork on the Welcome dialog was created by Louis Durrant.</p>
|
||||
|
||||
<h3>Translations</h3>
|
||||
|
||||
<p>The default language is English (UK) with English (US) as an option. These are the original
|
||||
translators for the languages currently available:</p>
|
||||
<p>
|
||||
• <b>Dutch:</b> Martijn van der Kleijn (<a href="https://github.com/mvdkleijn">@mvdkleijn</a>)<br>
|
||||
• <b>French:</b> Jan Lüdke (<a href="https://github.com/jyhelle">@jyhelle</a>)<br>
|
||||
• <b>German:</b> Myian (<a href="https://github.com/heymyian">@heymyian</a>)<br>
|
||||
• <b>Italian:</b> Riccardo Mangili<br>
|
||||
• <b>Japanese:</b> hebekeg (<a href="https://github.com/hebekeg">@hebekeg</a>)<br>
|
||||
• <b>Latin American Spanish:</b> Tommy Marplatt (<a href="https://github.com/tmarplatt">@tmarplatt</a>)<br>
|
||||
• <b>Norwegian:</b> Veronica Berglyd Olsen (<a href="https://github.com/vkbo">@vkbo</a>)<br>
|
||||
• <b>Portuguese:</b> Bruno Meneguello (<a href="https://github.com/bkmeneguello">@bkmeneguello</a>)<br>
|
||||
• <b>Simplified Chinese:</b> Qianzhi Long (<a href="https://github.com/longqzh">@longqzh</a>)
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><b>Dutch:</b> Martijn van der Kleijn (mvdkleijn)</li>
|
||||
<li><b>French:</b> Jan Lüdke (jyhelle)</li>
|
||||
<li><b>German:</b> Myian (HeyMyian)</li>
|
||||
<li><b>Italian:</b> Riccardo Mangili</li>
|
||||
<li><b>Japanese:</b> hebekeg</li>
|
||||
<li><b>Latin American Spanish:</b> Tommy Marplatt (tmarplatt)</li>
|
||||
<li><b>Norwegian:</b> Veronica Berglyd Olsen (vkbo)</li>
|
||||
<li><b>Polish:</b> Anna Maria Polak (Nauthiz)</li>
|
||||
<li><b>Portuguese:</b> Bruno Meneguello (bkmeneguello)</li>
|
||||
<li><b>Russian:</b> Konstantin Tan (k1kimosha)</li>
|
||||
<li><b>Simplified Chinese:</b> Qianzhi Long (longqzh)</li>
|
||||
</ul>
|
||||
|
||||
<p>Additional larger translation contributions:</p>
|
||||
<p>
|
||||
• <b>French:</b> Albert Aribaud (<a href="https://github.com/aaribaud">@aaribaud</a>)
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><b>French:</b> Albert Aribaud (aaribaud)</li>
|
||||
<li><b>Portuguese:</b> Oli Maia (olimaia)</li>
|
||||
</ul>
|
||||
|
||||
<p>Translations are managed on <a href="https://crowdin.com/project/novelwriter">Crowdin</a>, and
|
||||
more contributions are listed on the project's <a href="https://crowdin.com/project/novelwriter/members">Members</a> page.</p>
|
||||
more contributions are listed on the project's Members page.</p>
|
||||
|
||||
<h3>Libraries</h3>
|
||||
|
||||
<p>The following libraries are dependencies of novelWriter:</p>
|
||||
<p>
|
||||
• <a href="https://www.qt.io">Qt5</a> by Qt Company<br>
|
||||
• <a href="https://www.riverbankcomputing.com/software/pyqt">PyQt5</a> by Riverbank Computing<br>
|
||||
• <a href="https://abiword.github.io/enchant">Enchant</a> by Dom Lachowicz<br>
|
||||
• <a href="https://pyenchant.github.io/pyenchant">PyEnchant</a> by Dimitri Merejkowsky
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><b>Qt5</b> by Qt Company</li>
|
||||
<li><b>PyQt5</b> by Riverbank Computing</li>
|
||||
<li><b>Enchant</b> by Dom Lachowicz</li>
|
||||
<li><b>PyEnchant</b> by Dimitri Merejkowsky</li>
|
||||
</ul>
|
||||
|
||||
<h3>Assets</h3>
|
||||
|
||||
<p>Some of the assets bundled with novelWriter were adapted from the following sources:</p>
|
||||
<p>
|
||||
• <a href="https://github.com/stephenhutchings/typicons.font">Typicons</a> icons by Stephen Hutchings (CC BY-SA 4.0)<br>
|
||||
• <a href="https://github.com/chriskempson/base16">Tomorrow</a> syntax themes by Chris Kempson (MIT License)<br>
|
||||
• <a href="https://github.com/sdras/night-owl-vscode-theme">Owl</a> syntax themes by Sarah Drasner (MIT License)<br>
|
||||
• <a href="https://github.com/altercation/solarized">Solarized</a> themes by Ethan Schoonover (MIT License)
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><b>Typicons</b> icons by Stephen Hutchings (CC BY-SA 4.0)</li>
|
||||
<li><b>Tomorrow</b> syntax themes by Chris Kempson (MIT License)</li>
|
||||
<li><b>Owl</b> syntax themes by Sarah Drasner (MIT License)</li>
|
||||
<li><b>Solarized</b> themes by Ethan Schoonover (MIT License)</li>
|
||||
<li><b>Cyberpunk Night</b> theme by Anders Lemvigh (CC BY-SA 4.0)</li>
|
||||
<li><b>Dracula</b> theme by Zeno Rocha (MIT License)</li>
|
||||
<li><b>Snazzy Light</b> theme by Florian Reuschel (MIT License)</li>
|
||||
</ul>
|
||||
|
||||
<h3>Fonts</h3>
|
||||
|
||||
<p>The font used for the main novelWriter logo, mimetype and text banners is Pridi. Other fonts are
|
||||
used on buttons and icons.</p>
|
||||
<p>
|
||||
• Pridi by Cadson Demak (Open Font License, Version 1.1)<br>
|
||||
• Source Sans Pro by Paul D. Hunt (SIL Open Font License)
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><b>Pridi</b> by Cadson Demak (Open Font License, Version 1.1)</li>
|
||||
<li><b>Source Sans Pro</b> by Paul D. Hunt (SIL Open Font License)</li>
|
||||
</ul>
|
||||
|
||||
<h3>Special Mentions</h3>
|
||||
|
||||
<p>Additional thanks to <a href="https://github.com/johnblommers">@johnblommers</a> who was an early user and who has provided a lot
|
||||
of very useful feedback over the years.</p>
|
||||
<p>Additional thanks to John Blommers who was an early user and who has provided a lot of very
|
||||
useful feedback over the years.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -24,6 +24,9 @@ link = 77, 77, 255
|
||||
linkvisited = 50, 0, 80
|
||||
|
||||
[GUI]
|
||||
helptext = 97, 97, 97
|
||||
fadedtext = 97, 97, 97
|
||||
errortext = 255, 77, 77
|
||||
statusnone = 50, 50, 50
|
||||
statussaved = 77, 255, 77
|
||||
statusunsaved = 255, 77, 77
|
||||
|
||||
@@ -26,6 +26,8 @@ linkvisited = 102, 153, 204
|
||||
|
||||
[GUI]
|
||||
helptext = 164, 164, 164
|
||||
fadedtext = 148, 148, 148
|
||||
errortext = 255, 164, 164
|
||||
statusnone = 150, 152, 150
|
||||
statussaved = 39, 135, 78
|
||||
statusunsaved = 138, 32, 32
|
||||
|
||||
@@ -26,6 +26,8 @@ linkvisited = 66, 113, 174
|
||||
|
||||
[GUI]
|
||||
helptext = 92, 92, 92
|
||||
fadedtext = 108, 108, 108
|
||||
errortext = 255, 92, 92
|
||||
statusnone = 120, 120, 120
|
||||
statussaved = 200, 15, 39
|
||||
statusunsaved = 2, 133, 37
|
||||
statussaved = 2, 133, 37
|
||||
statusunsaved = 200, 15, 39
|
||||
|
||||
48
novelwriter/assets/themes/dracula.conf
Normal file
@@ -0,0 +1,48 @@
|
||||
[Main]
|
||||
name = Dracula
|
||||
description = A dark theme with bright colours
|
||||
author = Veronica Berglyd Olsen (adaptation)
|
||||
credit = Zeno Rocha
|
||||
url = https://draculatheme.com
|
||||
license = MIT
|
||||
licenseurl = https://github.com/dracula/dracula-theme/blob/main/LICENSE
|
||||
icontheme = typicons_dark
|
||||
|
||||
##
|
||||
# Colours:
|
||||
# Background = 282a36 : 40, 42, 54
|
||||
# Foreground = f8f8f2 : 248, 248, 242
|
||||
# Current Line = 44475A : 68, 71, 90
|
||||
# Comment = 6272a4 : 98, 114, 164
|
||||
# Cyan = 8be9fd : 139, 233, 253
|
||||
# Green = 50fa7b : 80, 250, 123
|
||||
# Orange = ffb86c : 255, 184, 108
|
||||
# Pink = ff79c6 : 255, 121, 198
|
||||
# Purple = bd93f9 : 189, 147, 249
|
||||
# Red = ff5555 : 255, 85, 85
|
||||
# Yellow = f1fa8c : 241, 250, 140
|
||||
##
|
||||
|
||||
[Palette]
|
||||
window = 68, 71, 90
|
||||
windowtext = 248, 248, 242
|
||||
base = 40, 42, 54
|
||||
alternatebase = 51, 54, 69
|
||||
text = 248, 248, 242
|
||||
tooltipbase = 241, 250, 140
|
||||
tooltiptext = 40, 42, 54
|
||||
button = 80, 83, 105
|
||||
buttontext = 248, 248, 242
|
||||
brighttext = 68, 71, 90
|
||||
highlight = 166, 129, 218
|
||||
highlightedtext = 248, 248, 242
|
||||
link = 139, 233, 253
|
||||
linkvisited = 139, 233, 253
|
||||
|
||||
[GUI]
|
||||
helptext = 204, 172, 249
|
||||
fadedtext = 98, 114, 164
|
||||
errortext = 255, 85, 85
|
||||
statusnone = 98, 114, 164
|
||||
statussaved = 80, 250, 123
|
||||
statusunsaved = 255, 85, 85
|
||||
@@ -25,6 +25,8 @@ linkvisited = 38, 139, 210
|
||||
|
||||
[GUI]
|
||||
helptext = 166, 161, 149
|
||||
fadedtext = 166, 161, 149
|
||||
errortext = 255, 161, 149
|
||||
statusnone = 88, 110, 117
|
||||
statussaved = 42, 161, 152
|
||||
statusunsaved = 203, 75, 22
|
||||
|
||||
@@ -25,6 +25,8 @@ linkvisited = 38, 139, 210
|
||||
|
||||
[GUI]
|
||||
helptext = 78, 91, 95
|
||||
fadedtext = 78, 91, 95
|
||||
errortext = 255, 91, 95
|
||||
statusnone = 88, 110, 117
|
||||
statussaved = 42, 161, 152
|
||||
statusunsaved = 203, 75, 22
|
||||
|
||||
@@ -24,30 +24,33 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import uuid
|
||||
import logging
|
||||
import unicodedata
|
||||
import uuid
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Literal
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from collections.abc import Callable
|
||||
from configparser import ConfigParser
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Literal, TypeVar
|
||||
from urllib.parse import urljoin
|
||||
from urllib.request import pathname2url
|
||||
|
||||
from PyQt5.QtGui import QColor, QDesktopServices
|
||||
from PyQt5.QtCore import QCoreApplication, QUrl
|
||||
from PyQt5.QtCore import QCoreApplication, QMimeData, QUrl
|
||||
from PyQt5.QtGui import QColor, QDesktopServices, QFont, QFontDatabase, QFontInfo
|
||||
|
||||
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.constants import nwConst, nwLabels, nwUnicode, trConst
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from typing import TypeGuard # Requires Python 3.10
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_Type = TypeVar("_Type")
|
||||
|
||||
|
||||
##
|
||||
# Checker Functions
|
||||
@@ -172,6 +175,11 @@ def isItemLayout(value: Any) -> TypeGuard[str]:
|
||||
return isinstance(value, str) and value in nwItemLayout.__members__
|
||||
|
||||
|
||||
def isListInstance(data: Any, check: type[_Type]) -> TypeGuard[list[_Type]]:
|
||||
"""Check that all items of a list is of a given type."""
|
||||
return isinstance(data, list) and all(isinstance(item, check) for item in data)
|
||||
|
||||
|
||||
def hexToInt(value: Any, default: int = 0) -> int:
|
||||
"""Convert a hex string to an integer."""
|
||||
if isinstance(value, str):
|
||||
@@ -197,6 +205,14 @@ def checkIntTuple(value: int, valid: tuple | list | set, default: int) -> int:
|
||||
return default
|
||||
|
||||
|
||||
def firstFloat(*args: Any) -> float:
|
||||
"""Return the first value that is a float."""
|
||||
for arg in args:
|
||||
if isinstance(arg, float):
|
||||
return arg
|
||||
return 0.0
|
||||
|
||||
|
||||
##
|
||||
# Formatting Functions
|
||||
##
|
||||
@@ -272,6 +288,23 @@ def simplified(text: str) -> str:
|
||||
return " ".join(str(text).strip().split())
|
||||
|
||||
|
||||
def compact(text: str) -> str:
|
||||
"""Compact a string by removing spaces."""
|
||||
return "".join(str(text).split())
|
||||
|
||||
|
||||
def uniqueCompact(text: str) -> str:
|
||||
"""Return a unique, compact and sorted string."""
|
||||
return "".join(sorted(set(compact(text))))
|
||||
|
||||
|
||||
def elide(text: str, length: int) -> str:
|
||||
"""Elide a piece of text to a maximum length."""
|
||||
if len(text) > (cut := max(4, length)):
|
||||
return f"{text[:cut-4].rstrip()} ..."
|
||||
return text
|
||||
|
||||
|
||||
def yesNo(value: int | bool | None) -> Literal["yes", "no"]:
|
||||
"""Convert a boolean evaluated variable to a yes or no."""
|
||||
return "yes" if value else "no"
|
||||
@@ -382,11 +415,67 @@ def numberToRoman(value: int, toLower: bool = False) -> str:
|
||||
return roman.lower() if toLower else roman
|
||||
|
||||
|
||||
##
|
||||
# Qt Helpers
|
||||
##
|
||||
|
||||
def cssCol(col: QColor, alpha: int | None = None) -> str:
|
||||
"""Convert a QColor object to an rgba entry to use in CSS."""
|
||||
return f"rgba({col.red()}, {col.green()}, {col.blue()}, {alpha or col.alpha()})"
|
||||
|
||||
|
||||
def describeFont(font: QFont) -> str:
|
||||
"""Describe a font in a way that can be displayed on the GUI."""
|
||||
if isinstance(font, QFont):
|
||||
info = QFontInfo(font)
|
||||
family = info.family()
|
||||
styles = [v for v in info.styleName().split() if v not in family]
|
||||
return " ".join([f"{info.pointSize()} pt", family] + styles)
|
||||
return "Error"
|
||||
|
||||
|
||||
def fontMatcher(font: QFont) -> QFont:
|
||||
"""Make sure the font is the correct family, if possible. This
|
||||
ensures that Qt doesn't re-use another font under the hood. The
|
||||
default Qt5 font matching algorithm doesn't handle well changing
|
||||
application fonts at runtime.
|
||||
"""
|
||||
info = QFontInfo(font)
|
||||
if (famRequest := font.family()) != (famActual := info.family()):
|
||||
logger.warning("Font mismatch: Requested '%s', but got '%s'", famRequest, famActual)
|
||||
db = QFontDatabase()
|
||||
if famRequest in db.families():
|
||||
styleRequest, sizeRequest = font.styleName(), font.pointSize()
|
||||
logger.info("Lookup: %s, %s, %d pt", famRequest, styleRequest, sizeRequest)
|
||||
temp = db.font(famRequest, styleRequest, sizeRequest)
|
||||
temp.setPointSize(sizeRequest) # Make sure it isn't changed
|
||||
famFound, styleFound, sizeFound = temp.family(), temp.styleName(), temp.pointSize()
|
||||
if famFound == famRequest:
|
||||
logger.info("Found: %s, %s, %d pt", famFound, styleFound, sizeFound)
|
||||
return temp
|
||||
logger.warning("Could not find a font match in the font database")
|
||||
logger.warning("If you just changed font, you may need to restart the application")
|
||||
return font
|
||||
|
||||
|
||||
def qtLambda(func: Callable, *args: Any, **kwargs: Any) -> Callable:
|
||||
"""A replacement for Python lambdas that works for Qt slots."""
|
||||
def wrapper(*a_: Any) -> None:
|
||||
func(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
def encodeMimeHandles(mimeData: QMimeData, handles: list[str]) -> None:
|
||||
"""Encode handles into a mime data object."""
|
||||
mimeData.setData(nwConst.MIME_HANDLE, b"|".join(h.encode() for h in handles))
|
||||
return
|
||||
|
||||
|
||||
def decodeMimeHandles(mimeData: QMimeData) -> list[str]:
|
||||
"""Decode and split a mime data object with handles."""
|
||||
return mimeData.data(nwConst.MIME_HANDLE).data().decode().split("|")
|
||||
|
||||
|
||||
##
|
||||
# Encoder Functions
|
||||
##
|
||||
@@ -438,6 +527,10 @@ def jsonEncode(data: dict | list | tuple, n: int = 0, nmax: int = 0) -> str:
|
||||
return "".join(buffer)
|
||||
|
||||
|
||||
##
|
||||
# XML Helpers
|
||||
##
|
||||
|
||||
def xmlIndent(tree: ET.Element | ET.ElementTree) -> None:
|
||||
"""A modified version of the XML indent function in the standard
|
||||
library. It behaves more closely to how the one from lxml does.
|
||||
@@ -481,6 +574,45 @@ def xmlIndent(tree: ET.Element | ET.ElementTree) -> None:
|
||||
return
|
||||
|
||||
|
||||
def xmlElement(
|
||||
tag: str,
|
||||
text: str | int | float | bool | None = None,
|
||||
*,
|
||||
attrib: dict | None = None,
|
||||
tail: str | None = None,
|
||||
) -> ET.Element:
|
||||
"""A custom implementation of Element with more arguments."""
|
||||
xSub = ET.Element(tag, attrib=attrib or {})
|
||||
if text is not None:
|
||||
if isinstance(text, bool):
|
||||
xSub.text = str(text).lower()
|
||||
else:
|
||||
xSub.text = str(text)
|
||||
if tail is not None:
|
||||
xSub.tail = tail
|
||||
return xSub
|
||||
|
||||
|
||||
def xmlSubElem(
|
||||
parent: ET.Element,
|
||||
tag: str,
|
||||
text: str | int | float | bool | None = None,
|
||||
*,
|
||||
attrib: dict | None = None,
|
||||
tail: str | None = None,
|
||||
) -> ET.Element:
|
||||
"""A custom implementation of SubElement with more arguments."""
|
||||
xSub = ET.SubElement(parent, tag, attrib=attrib or {})
|
||||
if text is not None:
|
||||
if isinstance(text, bool):
|
||||
xSub.text = str(text).lower()
|
||||
else:
|
||||
xSub.text = str(text)
|
||||
if tail is not None:
|
||||
xSub.tail = tail
|
||||
return xSub
|
||||
|
||||
|
||||
##
|
||||
# File and File System Functions
|
||||
##
|
||||
@@ -499,12 +631,11 @@ def readTextFile(path: str | Path) -> str:
|
||||
|
||||
|
||||
def makeFileNameSafe(text: str) -> str:
|
||||
"""Return a filename safe string.
|
||||
"""Return a filename-safe string.
|
||||
See: https://unicode.org/reports/tr15/#Norm_Forms
|
||||
"""
|
||||
text = unicodedata.normalize("NFKC", text).strip()
|
||||
allowed = (" ", ".", "-", "_")
|
||||
return "".join(c for c in text if c.isalnum() or c in allowed)
|
||||
return "".join(c for c in text if c.isprintable() and c not in r'\/:*?"<>|')
|
||||
|
||||
|
||||
def getFileSize(path: Path) -> int:
|
||||
@@ -589,5 +720,3 @@ class NWConfigParser(ConfigParser):
|
||||
for i in range(min(len(data), len(result))):
|
||||
result[i] = checkInt(data[i].strip(), result[i])
|
||||
return result
|
||||
|
||||
# END Class NWConfigParser
|
||||
|
||||
@@ -5,6 +5,7 @@ novelWriter – Config Class
|
||||
File History:
|
||||
Created: 2018-09-22 [0.0.1] Config
|
||||
Created: 2022-11-09 [2.0rc2] RecentProjects
|
||||
Created: 2024-06-16 [2.5rc1] RecentPaths
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
@@ -24,24 +25,27 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from time import time
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
|
||||
from PyQt5.QtGui import QFontDatabase
|
||||
from PyQt5.QtCore import (
|
||||
PYQT_VERSION, PYQT_VERSION_STR, QT_VERSION, QT_VERSION_STR, QLibraryInfo,
|
||||
QLocale, QStandardPaths, QSysInfo, QTranslator
|
||||
)
|
||||
from PyQt5.QtGui import QFont, QFontDatabase
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
from novelwriter.error import formatException, logException
|
||||
from novelwriter.common import NWConfigParser, checkInt, checkPath, formatTimeStamp
|
||||
from novelwriter.common import (
|
||||
NWConfigParser, checkInt, checkPath, describeFont, fontMatcher,
|
||||
formatTimeStamp
|
||||
)
|
||||
from novelwriter.constants import nwFiles, nwUnicode
|
||||
from novelwriter.error import formatException, logException
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -103,18 +107,19 @@ class Config:
|
||||
# User Settings
|
||||
# =============
|
||||
|
||||
self._recentObj = RecentProjects(self)
|
||||
self._recentProjects = RecentProjects(self)
|
||||
self._recentPaths = RecentPaths(self)
|
||||
|
||||
# General GUI Settings
|
||||
self.guiLocale = self._qLocale.name()
|
||||
self.guiTheme = "default" # GUI theme
|
||||
self.guiSyntax = "default_light" # Syntax theme
|
||||
self.guiFont = "" # Defaults to system default font in theme class
|
||||
self.guiFontSize = 11 # Is overridden if system default is loaded
|
||||
self.guiScale = 1.0 # Set automatically by Theme class
|
||||
self.hideVScroll = False # Hide vertical scroll bars on main widgets
|
||||
self.hideHScroll = False # Hide horizontal scroll bars on main widgets
|
||||
self.lastNotes = "0x0" # The latest release notes that have been shown
|
||||
self.guiLocale = self._qLocale.name()
|
||||
self.guiTheme = "default" # GUI theme
|
||||
self.guiSyntax = "default_light" # Syntax theme
|
||||
self.guiFont = QFont() # Main GUI font
|
||||
self.guiScale = 1.0 # Set automatically by Theme class
|
||||
self.hideVScroll = False # Hide vertical scroll bars on main widgets
|
||||
self.hideHScroll = False # Hide horizontal scroll bars on main widgets
|
||||
self.lastNotes = "0x0" # The latest release notes that have been shown
|
||||
self.nativeFont = True # Use native font dialog
|
||||
|
||||
# Size Settings
|
||||
self._mainWinSize = [1200, 650] # Last size of the main GUI window
|
||||
@@ -132,40 +137,43 @@ class Config:
|
||||
self.askBeforeBackup = True # Flag for asking before running automatic backup
|
||||
|
||||
# Text Editor Settings
|
||||
self.textFont = "" # Editor font
|
||||
self.textSize = 12 # Editor font size
|
||||
self.textWidth = 700 # Editor text width
|
||||
self.textMargin = 40 # Editor/viewer text margin
|
||||
self.tabWidth = 40 # Editor tabulator width
|
||||
self.textFont = QFont() # Editor font
|
||||
self.textWidth = 700 # Editor text width
|
||||
self.textMargin = 40 # Editor/viewer text margin
|
||||
self.tabWidth = 40 # Editor tabulator width
|
||||
|
||||
self.focusWidth = 800 # Focus Mode text width
|
||||
self.hideFocusFooter = False # Hide document footer in Focus Mode
|
||||
self.showFullPath = True # Show full document path in editor header
|
||||
self.autoSelect = True # Auto-select word when applying format with no selection
|
||||
self.focusWidth = 800 # Focus Mode text width
|
||||
self.hideFocusFooter = False # Hide document footer in Focus Mode
|
||||
self.showFullPath = True # Show full document path in editor header
|
||||
self.autoSelect = True # Auto-select word when applying format with no selection
|
||||
|
||||
self.doJustify = False # Justify text
|
||||
self.showTabsNSpaces = False # Show tabs and spaces in editor
|
||||
self.showLineEndings = False # Show line endings in editor
|
||||
self.showMultiSpaces = True # Highlight multiple spaces in the text
|
||||
self.doJustify = False # Justify text
|
||||
self.showTabsNSpaces = False # Show tabs and spaces in editor
|
||||
self.showLineEndings = False # Show line endings in editor
|
||||
self.showMultiSpaces = True # Highlight multiple spaces in the text
|
||||
|
||||
self.doReplace = True # Enable auto-replace as you type
|
||||
self.doReplaceSQuote = True # Smart single quotes
|
||||
self.doReplaceDQuote = True # Smart double quotes
|
||||
self.doReplaceDash = True # Replace multiple hyphens with dashes
|
||||
self.doReplaceDots = True # Replace three dots with ellipsis
|
||||
self.doReplace = True # Enable auto-replace as you type
|
||||
self.doReplaceSQuote = True # Smart single quotes
|
||||
self.doReplaceDQuote = True # Smart double quotes
|
||||
self.doReplaceDash = True # Replace multiple hyphens with dashes
|
||||
self.doReplaceDots = True # Replace three dots with ellipsis
|
||||
|
||||
self.autoScroll = False # Typewriter-like scrolling
|
||||
self.autoScrollPos = 30 # Start point for typewriter-like scrolling
|
||||
self.scrollPastEnd = True # Scroll past end of document, and centre cursor
|
||||
self.autoScroll = False # Typewriter-like scrolling
|
||||
self.autoScrollPos = 30 # Start point for typewriter-like scrolling
|
||||
self.scrollPastEnd = True # Scroll past end of document, and centre cursor
|
||||
|
||||
self.highlightQuotes = True # Highlight text in quotes
|
||||
self.allowOpenSQuote = False # Allow open-ended single quotes
|
||||
self.allowOpenDQuote = True # Allow open-ended double quotes
|
||||
self.highlightEmph = True # Add colour to text emphasis
|
||||
self.dialogStyle = 2 # Quote type to use for dialogue
|
||||
self.allowOpenDial = True # Allow open-ended dialogue quotes
|
||||
self.dialogLine = "" # Symbol to use for dialogue line
|
||||
self.narratorBreak = "" # Symbol to use for narrator break
|
||||
self.narratorDialog = "" # Symbol for alternating between dialogue and narrator
|
||||
self.altDialogOpen = "" # Alternative dialog symbol, open
|
||||
self.altDialogClose = "" # Alternative dialog symbol, close
|
||||
self.highlightEmph = True # Add colour to text emphasis
|
||||
|
||||
self.stopWhenIdle = True # Stop the status bar clock when the user is idle
|
||||
self.userIdleTime = 300 # Time of inactivity to consider user idle
|
||||
self.incNotesWCount = True # The status bar word count includes notes
|
||||
self.stopWhenIdle = True # Stop the status bar clock when the user is idle
|
||||
self.userIdleTime = 300 # Time of inactivity to consider user idle
|
||||
self.incNotesWCount = True # The status bar word count includes notes
|
||||
|
||||
# User-Selected Symbol Settings
|
||||
self.fmtApostrophe = nwUnicode.U_RSQUO
|
||||
@@ -178,7 +186,6 @@ class Config:
|
||||
self.fmtPadThin = False
|
||||
|
||||
# User Paths
|
||||
self._lastPath = self._homePath # The user's last used path
|
||||
self._backupPath = self._backPath # Backup path to use, can be none
|
||||
|
||||
# Spell Checking Settings
|
||||
@@ -249,9 +256,13 @@ class Config:
|
||||
def hasError(self) -> bool:
|
||||
return self._hasError
|
||||
|
||||
@property
|
||||
def locale(self) -> QLocale:
|
||||
return self._dLocale
|
||||
|
||||
@property
|
||||
def recentProjects(self) -> RecentProjects:
|
||||
return self._recentObj
|
||||
return self._recentProjects
|
||||
|
||||
@property
|
||||
def mainWinSize(self) -> list[int]:
|
||||
@@ -341,7 +352,7 @@ class Config:
|
||||
self._outlnPanePos = [int(x/self.guiScale) for x in pos]
|
||||
return
|
||||
|
||||
def setLastPath(self, path: str | Path) -> None:
|
||||
def setLastPath(self, key: str, path: str | Path) -> None:
|
||||
"""Set the last used path. Only the folder is saved, so if the
|
||||
path is not a folder, the parent of the path is used instead.
|
||||
"""
|
||||
@@ -350,8 +361,7 @@ class Config:
|
||||
if not path.is_dir():
|
||||
path = path.parent
|
||||
if path.is_dir():
|
||||
self._lastPath = path
|
||||
logger.debug("Last path updated: %s" % self._lastPath)
|
||||
self._recentPaths.setPath(key, path)
|
||||
return
|
||||
|
||||
def setBackupPath(self, path: Path | str) -> None:
|
||||
@@ -359,23 +369,53 @@ class Config:
|
||||
self._backupPath = checkPath(path, self._backPath)
|
||||
return
|
||||
|
||||
def setTextFont(self, family: str | None, pointSize: int = 12) -> None:
|
||||
def setGuiFont(self, value: QFont | str | None) -> None:
|
||||
"""Update the GUI's font style from settings."""
|
||||
if isinstance(value, QFont):
|
||||
self.guiFont = fontMatcher(value)
|
||||
elif value and isinstance(value, str):
|
||||
font = QFont()
|
||||
font.fromString(value)
|
||||
self.guiFont = fontMatcher(font)
|
||||
else:
|
||||
font = QFont()
|
||||
fontDB = QFontDatabase()
|
||||
if self.osWindows and "Arial" in fontDB.families():
|
||||
# On Windows we default to Arial if possible
|
||||
font.setFamily("Arial")
|
||||
font.setPointSize(10)
|
||||
else:
|
||||
font = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont)
|
||||
self.guiFont = fontMatcher(font)
|
||||
logger.debug("GUI font set to: %s", describeFont(font))
|
||||
QApplication.setFont(self.guiFont)
|
||||
return
|
||||
|
||||
def setTextFont(self, value: QFont | str | None) -> None:
|
||||
"""Set the text font if it exists. If it doesn't, or is None,
|
||||
set to default font.
|
||||
"""
|
||||
fontDB = QFontDatabase()
|
||||
fontFam = fontDB.families()
|
||||
self.textSize = pointSize
|
||||
if family is None or family not in fontFam:
|
||||
logger.warning("Unknown font '%s'", family)
|
||||
if self.osWindows and "Arial" in fontFam:
|
||||
self.textFont = "Arial"
|
||||
elif self.osDarwin and "Helvetica" in fontFam:
|
||||
self.textFont = "Helvetica"
|
||||
else:
|
||||
self.textFont = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont).family()
|
||||
if isinstance(value, QFont):
|
||||
self.textFont = fontMatcher(value)
|
||||
elif value and isinstance(value, str):
|
||||
font = QFont()
|
||||
font.fromString(value)
|
||||
self.textFont = fontMatcher(font)
|
||||
else:
|
||||
self.textFont = family
|
||||
fontDB = QFontDatabase()
|
||||
fontFam = fontDB.families()
|
||||
if self.osWindows and "Arial" in fontFam:
|
||||
font = QFont()
|
||||
font.setFamily("Arial")
|
||||
font.setPointSize(12)
|
||||
elif self.osDarwin and "Helvetica" in fontFam:
|
||||
font = QFont()
|
||||
font.setFamily("Helvetica")
|
||||
font.setPointSize(12)
|
||||
else:
|
||||
font = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont)
|
||||
self.textFont = fontMatcher(font)
|
||||
logger.debug("Text font set to: %s", describeFont(self.textFont))
|
||||
return
|
||||
|
||||
##
|
||||
@@ -406,11 +446,12 @@ class Config:
|
||||
return self._appPath / "assets" / target
|
||||
return self._appPath / "assets"
|
||||
|
||||
def lastPath(self) -> Path:
|
||||
def lastPath(self, key: str) -> Path:
|
||||
"""Return the last path used by the user, if it exists."""
|
||||
if isinstance(self._lastPath, Path):
|
||||
if self._lastPath.is_dir():
|
||||
return self._lastPath
|
||||
if path := self._recentPaths.getPath(key):
|
||||
asPath = Path(path)
|
||||
if asPath.is_dir():
|
||||
return asPath
|
||||
return self._homePath
|
||||
|
||||
def backupPath(self) -> Path:
|
||||
@@ -484,7 +525,6 @@ class Config:
|
||||
logger.debug("Data Path: %s", self._dataPath)
|
||||
logger.debug("App Root: %s", self._appRoot)
|
||||
logger.debug("App Path: %s", self._appPath)
|
||||
logger.debug("Last Path: %s", self._lastPath)
|
||||
logger.debug("PDF Manual: %s", self.pdfDocs)
|
||||
|
||||
# If the config and data folders don't exist, create them
|
||||
@@ -499,13 +539,8 @@ class Config:
|
||||
(self._dataPath / "syntax").mkdir(exist_ok=True)
|
||||
(self._dataPath / "themes").mkdir(exist_ok=True)
|
||||
|
||||
# Check if config file exists, and load it. If not, we save defaults
|
||||
if (self._confPath / nwFiles.CONF_FILE).is_file():
|
||||
self.loadConfig()
|
||||
else:
|
||||
self.saveConfig()
|
||||
|
||||
self._recentObj.loadCache()
|
||||
self._recentPaths.loadCache()
|
||||
self._recentProjects.loadCache()
|
||||
self._checkOptionalPackages()
|
||||
|
||||
logger.debug("Config instance initialised")
|
||||
@@ -545,6 +580,14 @@ class Config:
|
||||
|
||||
conf = NWConfigParser()
|
||||
cnfPath = self._confPath / nwFiles.CONF_FILE
|
||||
|
||||
if not cnfPath.exists():
|
||||
# Initial file, so we just create one from defaults
|
||||
self.setGuiFont(None)
|
||||
self.setTextFont(None)
|
||||
self.saveConfig()
|
||||
return True
|
||||
|
||||
try:
|
||||
with open(cnfPath, mode="r", encoding="utf-8") as inFile:
|
||||
conf.read_file(inFile)
|
||||
@@ -558,15 +601,14 @@ class Config:
|
||||
|
||||
# Main
|
||||
sec = "Main"
|
||||
self.setGuiFont(conf.rdStr(sec, "font", ""))
|
||||
self.guiTheme = conf.rdStr(sec, "theme", self.guiTheme)
|
||||
self.guiSyntax = conf.rdStr(sec, "syntax", self.guiSyntax)
|
||||
self.guiFont = conf.rdStr(sec, "font", self.guiFont)
|
||||
self.guiFontSize = conf.rdInt(sec, "fontsize", self.guiFontSize)
|
||||
self.guiLocale = conf.rdStr(sec, "localisation", self.guiLocale)
|
||||
self.hideVScroll = conf.rdBool(sec, "hidevscroll", self.hideVScroll)
|
||||
self.hideHScroll = conf.rdBool(sec, "hidehscroll", self.hideHScroll)
|
||||
self.lastNotes = conf.rdStr(sec, "lastnotes", self.lastNotes)
|
||||
self._lastPath = conf.rdPath(sec, "lastpath", self._lastPath)
|
||||
self.nativeFont = conf.rdBool(sec, "nativefont", self.nativeFont)
|
||||
|
||||
# Sizes
|
||||
sec = "Sizes"
|
||||
@@ -588,8 +630,7 @@ class Config:
|
||||
|
||||
# Editor
|
||||
sec = "Editor"
|
||||
self.textFont = conf.rdStr(sec, "textfont", self.textFont)
|
||||
self.textSize = conf.rdInt(sec, "textsize", self.textSize)
|
||||
self.setTextFont(conf.rdStr(sec, "textfont", ""))
|
||||
self.textWidth = conf.rdInt(sec, "width", self.textWidth)
|
||||
self.textMargin = conf.rdInt(sec, "margin", self.textMargin)
|
||||
self.tabWidth = conf.rdInt(sec, "tabwidth", self.tabWidth)
|
||||
@@ -618,9 +659,13 @@ class Config:
|
||||
self.showMultiSpaces = conf.rdBool(sec, "showmultispaces", self.showMultiSpaces)
|
||||
self.incNotesWCount = conf.rdBool(sec, "incnoteswcount", self.incNotesWCount)
|
||||
self.showFullPath = conf.rdBool(sec, "showfullpath", self.showFullPath)
|
||||
self.highlightQuotes = conf.rdBool(sec, "highlightquotes", self.highlightQuotes)
|
||||
self.allowOpenSQuote = conf.rdBool(sec, "allowopensquote", self.allowOpenSQuote)
|
||||
self.allowOpenDQuote = conf.rdBool(sec, "allowopendquote", self.allowOpenDQuote)
|
||||
self.dialogStyle = conf.rdInt(sec, "dialogstyle", self.dialogStyle)
|
||||
self.allowOpenDial = conf.rdBool(sec, "allowopendial", self.allowOpenDial)
|
||||
self.dialogLine = conf.rdStr(sec, "dialogline", self.dialogLine)
|
||||
self.narratorBreak = conf.rdStr(sec, "narratorbreak", self.narratorBreak)
|
||||
self.narratorDialog = conf.rdStr(sec, "narratordialog", self.narratorDialog)
|
||||
self.altDialogOpen = conf.rdStr(sec, "altdialogopen", self.altDialogOpen)
|
||||
self.altDialogClose = conf.rdStr(sec, "altdialogclose", self.altDialogClose)
|
||||
self.highlightEmph = conf.rdBool(sec, "highlightemph", self.highlightEmph)
|
||||
self.stopWhenIdle = conf.rdBool(sec, "stopwhenidle", self.stopWhenIdle)
|
||||
self.userIdleTime = conf.rdInt(sec, "useridletime", self.userIdleTime)
|
||||
@@ -666,15 +711,14 @@ class Config:
|
||||
}
|
||||
|
||||
conf["Main"] = {
|
||||
"font": self.guiFont.toString(),
|
||||
"theme": str(self.guiTheme),
|
||||
"syntax": str(self.guiSyntax),
|
||||
"font": str(self.guiFont),
|
||||
"fontsize": str(self.guiFontSize),
|
||||
"localisation": str(self.guiLocale),
|
||||
"hidevscroll": str(self.hideVScroll),
|
||||
"hidehscroll": str(self.hideHScroll),
|
||||
"lastnotes": str(self.lastNotes),
|
||||
"lastpath": str(self._lastPath),
|
||||
"nativefont": str(self.nativeFont),
|
||||
}
|
||||
|
||||
conf["Sizes"] = {
|
||||
@@ -696,8 +740,7 @@ class Config:
|
||||
}
|
||||
|
||||
conf["Editor"] = {
|
||||
"textfont": str(self.textFont),
|
||||
"textsize": str(self.textSize),
|
||||
"textfont": self.textFont.toString(),
|
||||
"width": str(self.textWidth),
|
||||
"margin": str(self.textMargin),
|
||||
"tabwidth": str(self.tabWidth),
|
||||
@@ -726,9 +769,13 @@ class Config:
|
||||
"showmultispaces": str(self.showMultiSpaces),
|
||||
"incnoteswcount": str(self.incNotesWCount),
|
||||
"showfullpath": str(self.showFullPath),
|
||||
"highlightquotes": str(self.highlightQuotes),
|
||||
"allowopensquote": str(self.allowOpenSQuote),
|
||||
"allowopendquote": str(self.allowOpenDQuote),
|
||||
"dialogstyle": str(self.dialogStyle),
|
||||
"allowopendial": str(self.allowOpenDial),
|
||||
"dialogline": str(self.dialogLine),
|
||||
"narratorbreak": str(self.narratorBreak),
|
||||
"narratordialog": str(self.narratorDialog),
|
||||
"altdialogopen": str(self.altDialogOpen),
|
||||
"altdialogclose": str(self.altDialogClose),
|
||||
"highlightemph": str(self.highlightEmph),
|
||||
"stopwhenidle": str(self.stopWhenIdle),
|
||||
"useridletime": str(self.userIdleTime),
|
||||
@@ -773,7 +820,7 @@ class Config:
|
||||
"""Pack a list of items into a comma-separated string for saving
|
||||
to the config file.
|
||||
"""
|
||||
return ", ".join([str(inVal) for inVal in data])
|
||||
return ", ".join(str(inVal) for inVal in data)
|
||||
|
||||
def _checkOptionalPackages(self) -> None:
|
||||
"""Check optional packages used by some features."""
|
||||
@@ -787,8 +834,6 @@ class Config:
|
||||
logger.debug("Checking package 'pyenchant': OK")
|
||||
return
|
||||
|
||||
# END Class Config
|
||||
|
||||
|
||||
class RecentProjects:
|
||||
|
||||
@@ -858,4 +903,55 @@ class RecentProjects:
|
||||
self.saveCache()
|
||||
return
|
||||
|
||||
# END Class RecentProjects
|
||||
|
||||
class RecentPaths:
|
||||
|
||||
KEYS = ["default", "project", "import", "outline", "stats"]
|
||||
|
||||
def __init__(self, config: Config) -> None:
|
||||
self._conf = config
|
||||
self._data = {}
|
||||
return
|
||||
|
||||
def setPath(self, key: str, path: Path | str) -> None:
|
||||
"""Set a path for a given key, and save the cache."""
|
||||
if key in self.KEYS:
|
||||
self._data[key] = str(path)
|
||||
self.saveCache()
|
||||
return
|
||||
|
||||
def getPath(self, key: str) -> str | None:
|
||||
"""Get a path for a given key, or return None."""
|
||||
return self._data.get(key)
|
||||
|
||||
def loadCache(self) -> bool:
|
||||
"""Load the cache file for recent paths."""
|
||||
self._data = {}
|
||||
cacheFile = self._conf.dataPath(nwFiles.RECENT_PATH)
|
||||
if cacheFile.is_file():
|
||||
try:
|
||||
with open(cacheFile, mode="r", encoding="utf-8") as inFile:
|
||||
data = json.load(inFile)
|
||||
if isinstance(data, dict):
|
||||
for key, path in data.items():
|
||||
if key in self.KEYS and isinstance(path, str):
|
||||
self._data[key] = path
|
||||
except Exception:
|
||||
logger.error("Could not load recent paths cache")
|
||||
logException()
|
||||
return False
|
||||
return True
|
||||
|
||||
def saveCache(self) -> bool:
|
||||
"""Save the cache dictionary of recent paths."""
|
||||
cacheFile = self._conf.dataPath(nwFiles.RECENT_PATH)
|
||||
cacheTemp = cacheFile.with_suffix(".tmp")
|
||||
try:
|
||||
with open(cacheTemp, mode="w+", encoding="utf-8") as outFile:
|
||||
json.dump(self._data, outFile, indent=2)
|
||||
cacheTemp.replace(cacheFile)
|
||||
except Exception:
|
||||
logger.error("Could not save recent paths cache")
|
||||
logException()
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -23,9 +23,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication, QT_TRANSLATE_NOOP
|
||||
from PyQt5.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
|
||||
|
||||
from novelwriter.enum import nwBuildFmt, nwItemClass, nwItemLayout, nwOutline
|
||||
from novelwriter.enum import (
|
||||
nwBuildFmt, nwComment, nwItemClass, nwItemLayout, nwOutline, nwStatusShape
|
||||
)
|
||||
|
||||
|
||||
def trConst(text: str) -> str:
|
||||
@@ -51,25 +53,24 @@ class nwConst:
|
||||
# Requests
|
||||
USER_AGENT = "Mozilla/5.0 (compatible; novelWriter (Python))"
|
||||
|
||||
# Mime Types
|
||||
MIME_HANDLE = "text/vnd.novelwriter.handle"
|
||||
|
||||
# Gui Settings
|
||||
STATUS_MSG_TIMEOUT = 15000 # milliseconds
|
||||
MAX_SEARCH_RESULT = 1000
|
||||
|
||||
# Dialogs
|
||||
DLG_FINISHED = 2
|
||||
|
||||
# END Class nwConst
|
||||
|
||||
|
||||
class nwRegEx:
|
||||
|
||||
URL = r"https?://(?:www\.|(?!www))[\w/()@:%_\+-.~#?&=]+"
|
||||
WORDS = r"\b[^\s\-\+\/–—\[\]:]+\b"
|
||||
BREAK = r"(?i)(?<!\\)(\[br\]\n?)"
|
||||
FMT_EI = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
FMT_EB = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
FMT_SC = r"(?i)(?<!\\)(\[[\/\!]?(?:i|b|s|u|m|sup|sub)\])"
|
||||
FMT_SV = r"(?<!\\)(\[(?i)(?:fn|footnote):)(.+?)(?<!\\)(\])"
|
||||
|
||||
# END Class nwRegEx
|
||||
FMT_EB = r"(?<![\w\\])(\*{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
FMT_ST = r"(?<![\w\\])(~{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
FMT_SC = r"(?i)(?<!\\)(\[(?:b|/b|i|/i|s|/s|u|/u|m|/m|sup|/sup|sub|/sub|br)\])"
|
||||
FMT_SV = r"(?i)(?<!\\)(\[(?:footnote|field):)(.+?)(?<!\\)(\])"
|
||||
|
||||
|
||||
class nwShortcode:
|
||||
@@ -88,16 +89,48 @@ class nwShortcode:
|
||||
SUP_C = "[/sup]"
|
||||
SUB_O = "[sub]"
|
||||
SUB_C = "[/sub]"
|
||||
BREAK = "[br]"
|
||||
|
||||
# END Class nwShortcode
|
||||
FOOTNOTE_B = "[footnote:"
|
||||
FIELD_B = "[field:"
|
||||
|
||||
COMMENT_STYLES = {
|
||||
nwComment.FOOTNOTE: "[footnote:{0}]",
|
||||
nwComment.COMMENT: "[comment:{0}]",
|
||||
}
|
||||
|
||||
FIELD_VALUE = "[field:{0}]"
|
||||
|
||||
|
||||
class nwHeaders:
|
||||
class nwStyles:
|
||||
|
||||
H_VALID = ("H0", "H1", "H2", "H3", "H4")
|
||||
H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
|
||||
H_SIZES = {0: 2.50, 1: 2.00, 2: 1.75, 3: 1.50, 4: 1.25}
|
||||
|
||||
# END Class nwHeaders
|
||||
T_NORMAL = 1.0
|
||||
T_SMALL = 0.8
|
||||
|
||||
T_LABEL = {
|
||||
"H0": QT_TRANSLATE_NOOP("Constant", "Title"),
|
||||
"H1": QT_TRANSLATE_NOOP("Constant", "Heading 1 (Partition)"),
|
||||
"H2": QT_TRANSLATE_NOOP("Constant", "Heading 2 (Chapter)"),
|
||||
"H3": QT_TRANSLATE_NOOP("Constant", "Heading 3 (Scene)"),
|
||||
"H4": QT_TRANSLATE_NOOP("Constant", "Heading 4 (Section)"),
|
||||
"TT": QT_TRANSLATE_NOOP("Constant", "Text Paragraph"),
|
||||
"SP": QT_TRANSLATE_NOOP("Constant", "Scene Separator"),
|
||||
}
|
||||
T_MARGIN = {
|
||||
"H0": (1.50, 0.60), # Title margins (top, bottom)
|
||||
"H1": (1.50, 0.60), # Heading 1 margins (top, bottom)
|
||||
"H2": (1.50, 0.60), # Heading 2 margins (top, bottom)
|
||||
"H3": (1.20, 0.60), # Heading 3 margins (top, bottom)
|
||||
"H4": (1.20, 0.60), # Heading 4 margins (top, bottom)
|
||||
"TT": (0.00, 0.60), # Text margins (top, bottom)
|
||||
"SP": (1.20, 1.20), # Separator margins (top, bottom)
|
||||
"MT": (0.00, 0.60), # Meta margins (top, bottom)
|
||||
"FT": (1.40, 0.40), # Footnote margins (left, bottom)
|
||||
}
|
||||
|
||||
|
||||
class nwFiles:
|
||||
@@ -105,6 +138,7 @@ class nwFiles:
|
||||
# Config Files
|
||||
CONF_FILE = "novelwriter.conf"
|
||||
RECENT_FILE = "recentProjects.json"
|
||||
RECENT_PATH = "recentPaths.json"
|
||||
|
||||
# Project Root Files
|
||||
PROJ_FILE = "nwProject.nwx"
|
||||
@@ -118,43 +152,45 @@ class nwFiles:
|
||||
DICT_FILE = "userdict.json"
|
||||
SESS_FILE = "sessions.jsonl"
|
||||
|
||||
# END Class nwFiles
|
||||
|
||||
|
||||
class nwKeyWords:
|
||||
|
||||
TAG_KEY = "@tag"
|
||||
POV_KEY = "@pov"
|
||||
FOCUS_KEY = "@focus"
|
||||
CHAR_KEY = "@char"
|
||||
PLOT_KEY = "@plot"
|
||||
TIME_KEY = "@time"
|
||||
WORLD_KEY = "@location"
|
||||
OBJECT_KEY = "@object"
|
||||
ENTITY_KEY = "@entity"
|
||||
CUSTOM_KEY = "@custom"
|
||||
TAG_KEY = "@tag"
|
||||
POV_KEY = "@pov"
|
||||
FOCUS_KEY = "@focus"
|
||||
CHAR_KEY = "@char"
|
||||
PLOT_KEY = "@plot"
|
||||
TIME_KEY = "@time"
|
||||
WORLD_KEY = "@location"
|
||||
OBJECT_KEY = "@object"
|
||||
ENTITY_KEY = "@entity"
|
||||
CUSTOM_KEY = "@custom"
|
||||
STORY_KEY = "@story"
|
||||
MENTION_KEY = "@mention"
|
||||
|
||||
# Note: The order here affects the order of menu entries
|
||||
ALL_KEYS = [
|
||||
TAG_KEY, POV_KEY, FOCUS_KEY, CHAR_KEY, PLOT_KEY, TIME_KEY, WORLD_KEY,
|
||||
OBJECT_KEY, ENTITY_KEY, CUSTOM_KEY, STORY_KEY, MENTION_KEY,
|
||||
]
|
||||
|
||||
# Set of Valid Keys
|
||||
VALID_KEYS = {
|
||||
TAG_KEY, POV_KEY, FOCUS_KEY, CHAR_KEY, PLOT_KEY, TIME_KEY,
|
||||
WORLD_KEY, OBJECT_KEY, ENTITY_KEY, CUSTOM_KEY
|
||||
}
|
||||
VALID_KEYS = set(ALL_KEYS)
|
||||
|
||||
# Map from Keys to Item Class
|
||||
KEY_CLASS = {
|
||||
POV_KEY: nwItemClass.CHARACTER,
|
||||
FOCUS_KEY: nwItemClass.CHARACTER,
|
||||
CHAR_KEY: nwItemClass.CHARACTER,
|
||||
PLOT_KEY: nwItemClass.PLOT,
|
||||
TIME_KEY: nwItemClass.TIMELINE,
|
||||
WORLD_KEY: nwItemClass.WORLD,
|
||||
OBJECT_KEY: nwItemClass.OBJECT,
|
||||
ENTITY_KEY: nwItemClass.ENTITY,
|
||||
CUSTOM_KEY: nwItemClass.CUSTOM,
|
||||
POV_KEY: nwItemClass.CHARACTER,
|
||||
FOCUS_KEY: nwItemClass.CHARACTER,
|
||||
CHAR_KEY: nwItemClass.CHARACTER,
|
||||
PLOT_KEY: nwItemClass.PLOT,
|
||||
TIME_KEY: nwItemClass.TIMELINE,
|
||||
WORLD_KEY: nwItemClass.WORLD,
|
||||
OBJECT_KEY: nwItemClass.OBJECT,
|
||||
ENTITY_KEY: nwItemClass.ENTITY,
|
||||
CUSTOM_KEY: nwItemClass.CUSTOM,
|
||||
STORY_KEY: nwItemClass.NOVEL,
|
||||
}
|
||||
|
||||
# END Class nwKeyWords
|
||||
|
||||
|
||||
class nwLists:
|
||||
|
||||
@@ -168,7 +204,28 @@ class nwLists:
|
||||
nwItemClass.CUSTOM,
|
||||
]
|
||||
|
||||
# END Class nwLists
|
||||
|
||||
class nwStats:
|
||||
|
||||
CHARS_ALL = "allChars"
|
||||
CHARS_TEXT = "textChars"
|
||||
CHARS_TITLE = "titleChars"
|
||||
PARAGRAPHS = "paragraphCount"
|
||||
TITLES = "titleCount"
|
||||
WCHARS_ALL = "allWordChars"
|
||||
WCHARS_TEXT = "textWordChars"
|
||||
WCHARS_TITLE = "titleWordChars"
|
||||
WORDS_ALL = "allWords"
|
||||
WORDS_TEXT = "textWords"
|
||||
WORDS_TITLE = "titleWords"
|
||||
|
||||
# Note: The order here affects the order of menu entries
|
||||
ALL_FIELDS = [
|
||||
WORDS_ALL, WORDS_TEXT, WORDS_TITLE,
|
||||
CHARS_ALL, CHARS_TEXT, CHARS_TITLE,
|
||||
WCHARS_ALL, WCHARS_TEXT, WCHARS_TITLE,
|
||||
PARAGRAPHS, TITLES,
|
||||
]
|
||||
|
||||
|
||||
class nwLabels:
|
||||
@@ -217,57 +274,125 @@ class nwLabels:
|
||||
"doc_h4": QT_TRANSLATE_NOOP("Constant", "Novel Section"),
|
||||
"note": QT_TRANSLATE_NOOP("Constant", "Project Note"),
|
||||
}
|
||||
ACTIVE_NAME = {
|
||||
"checked": QT_TRANSLATE_NOOP("Constant", "Active"),
|
||||
"unchecked": QT_TRANSLATE_NOOP("Constant", "Inactive"),
|
||||
}
|
||||
KEY_NAME = {
|
||||
nwKeyWords.TAG_KEY: QT_TRANSLATE_NOOP("Constant", "Tag"),
|
||||
nwKeyWords.POV_KEY: QT_TRANSLATE_NOOP("Constant", "Point of View"),
|
||||
nwKeyWords.FOCUS_KEY: QT_TRANSLATE_NOOP("Constant", "Focus"),
|
||||
nwKeyWords.CHAR_KEY: QT_TRANSLATE_NOOP("Constant", "Characters"),
|
||||
nwKeyWords.PLOT_KEY: QT_TRANSLATE_NOOP("Constant", "Plot"),
|
||||
nwKeyWords.TIME_KEY: QT_TRANSLATE_NOOP("Constant", "Timeline"),
|
||||
nwKeyWords.WORLD_KEY: QT_TRANSLATE_NOOP("Constant", "Locations"),
|
||||
nwKeyWords.OBJECT_KEY: QT_TRANSLATE_NOOP("Constant", "Objects"),
|
||||
nwKeyWords.ENTITY_KEY: QT_TRANSLATE_NOOP("Constant", "Entities"),
|
||||
nwKeyWords.CUSTOM_KEY: QT_TRANSLATE_NOOP("Constant", "Custom"),
|
||||
nwKeyWords.TAG_KEY: QT_TRANSLATE_NOOP("Constant", "Tag"),
|
||||
nwKeyWords.POV_KEY: QT_TRANSLATE_NOOP("Constant", "Point of View"),
|
||||
nwKeyWords.FOCUS_KEY: QT_TRANSLATE_NOOP("Constant", "Focus"),
|
||||
nwKeyWords.CHAR_KEY: QT_TRANSLATE_NOOP("Constant", "Characters"),
|
||||
nwKeyWords.PLOT_KEY: QT_TRANSLATE_NOOP("Constant", "Plot"),
|
||||
nwKeyWords.TIME_KEY: QT_TRANSLATE_NOOP("Constant", "Timeline"),
|
||||
nwKeyWords.WORLD_KEY: QT_TRANSLATE_NOOP("Constant", "Locations"),
|
||||
nwKeyWords.OBJECT_KEY: QT_TRANSLATE_NOOP("Constant", "Objects"),
|
||||
nwKeyWords.ENTITY_KEY: QT_TRANSLATE_NOOP("Constant", "Entities"),
|
||||
nwKeyWords.CUSTOM_KEY: QT_TRANSLATE_NOOP("Constant", "Custom"),
|
||||
nwKeyWords.STORY_KEY: QT_TRANSLATE_NOOP("Constant", "Story"),
|
||||
nwKeyWords.MENTION_KEY: QT_TRANSLATE_NOOP("Constant", "Mentions"),
|
||||
}
|
||||
KEY_SHORTCUT = {
|
||||
nwKeyWords.TAG_KEY: "Ctrl+K, G",
|
||||
nwKeyWords.POV_KEY: "Ctrl+K, V",
|
||||
nwKeyWords.FOCUS_KEY: "Ctrl+K, F",
|
||||
nwKeyWords.CHAR_KEY: "Ctrl+K, C",
|
||||
nwKeyWords.PLOT_KEY: "Ctrl+K, P",
|
||||
nwKeyWords.TIME_KEY: "Ctrl+K, T",
|
||||
nwKeyWords.WORLD_KEY: "Ctrl+K, L",
|
||||
nwKeyWords.OBJECT_KEY: "Ctrl+K, O",
|
||||
nwKeyWords.ENTITY_KEY: "Ctrl+K, E",
|
||||
nwKeyWords.CUSTOM_KEY: "Ctrl+K, X",
|
||||
nwKeyWords.STORY_KEY: "Ctrl+K, N",
|
||||
nwKeyWords.MENTION_KEY: "Ctrl+K, M",
|
||||
}
|
||||
OUTLINE_COLS = {
|
||||
nwOutline.TITLE: QT_TRANSLATE_NOOP("Constant", "Title"),
|
||||
nwOutline.LEVEL: QT_TRANSLATE_NOOP("Constant", "Level"),
|
||||
nwOutline.LABEL: QT_TRANSLATE_NOOP("Constant", "Document"),
|
||||
nwOutline.LINE: QT_TRANSLATE_NOOP("Constant", "Line"),
|
||||
nwOutline.CCOUNT: QT_TRANSLATE_NOOP("Constant", "Chars"),
|
||||
nwOutline.WCOUNT: QT_TRANSLATE_NOOP("Constant", "Words"),
|
||||
nwOutline.PCOUNT: QT_TRANSLATE_NOOP("Constant", "Pars"),
|
||||
nwOutline.POV: QT_TRANSLATE_NOOP("Constant", "POV"),
|
||||
nwOutline.FOCUS: QT_TRANSLATE_NOOP("Constant", "Focus"),
|
||||
nwOutline.CHAR: KEY_NAME[nwKeyWords.CHAR_KEY],
|
||||
nwOutline.PLOT: KEY_NAME[nwKeyWords.PLOT_KEY],
|
||||
nwOutline.WORLD: KEY_NAME[nwKeyWords.WORLD_KEY],
|
||||
nwOutline.TIME: KEY_NAME[nwKeyWords.TIME_KEY],
|
||||
nwOutline.OBJECT: KEY_NAME[nwKeyWords.OBJECT_KEY],
|
||||
nwOutline.ENTITY: KEY_NAME[nwKeyWords.ENTITY_KEY],
|
||||
nwOutline.CUSTOM: KEY_NAME[nwKeyWords.CUSTOM_KEY],
|
||||
nwOutline.SYNOP: QT_TRANSLATE_NOOP("Constant", "Synopsis"),
|
||||
nwOutline.TITLE: QT_TRANSLATE_NOOP("Constant", "Title"),
|
||||
nwOutline.LEVEL: QT_TRANSLATE_NOOP("Constant", "Level"),
|
||||
nwOutline.LABEL: QT_TRANSLATE_NOOP("Constant", "Document"),
|
||||
nwOutline.LINE: QT_TRANSLATE_NOOP("Constant", "Line"),
|
||||
nwOutline.STATUS: QT_TRANSLATE_NOOP("Constant", "Status"),
|
||||
nwOutline.CCOUNT: QT_TRANSLATE_NOOP("Constant", "Chars"),
|
||||
nwOutline.WCOUNT: QT_TRANSLATE_NOOP("Constant", "Words"),
|
||||
nwOutline.PCOUNT: QT_TRANSLATE_NOOP("Constant", "Pars"),
|
||||
nwOutline.POV: QT_TRANSLATE_NOOP("Constant", "POV"),
|
||||
nwOutline.FOCUS: QT_TRANSLATE_NOOP("Constant", "Focus"),
|
||||
nwOutline.CHAR: KEY_NAME[nwKeyWords.CHAR_KEY],
|
||||
nwOutline.PLOT: KEY_NAME[nwKeyWords.PLOT_KEY],
|
||||
nwOutline.WORLD: KEY_NAME[nwKeyWords.WORLD_KEY],
|
||||
nwOutline.TIME: KEY_NAME[nwKeyWords.TIME_KEY],
|
||||
nwOutline.OBJECT: KEY_NAME[nwKeyWords.OBJECT_KEY],
|
||||
nwOutline.ENTITY: KEY_NAME[nwKeyWords.ENTITY_KEY],
|
||||
nwOutline.CUSTOM: KEY_NAME[nwKeyWords.CUSTOM_KEY],
|
||||
nwOutline.STORY: KEY_NAME[nwKeyWords.STORY_KEY],
|
||||
nwOutline.MENTION: KEY_NAME[nwKeyWords.MENTION_KEY],
|
||||
nwOutline.SYNOP: QT_TRANSLATE_NOOP("Constant", "Synopsis"),
|
||||
}
|
||||
STATS_NAME = {
|
||||
nwStats.CHARS_ALL: QT_TRANSLATE_NOOP("Constant", "Characters"),
|
||||
nwStats.CHARS_TEXT: QT_TRANSLATE_NOOP("Constant", "Characters in Text"),
|
||||
nwStats.CHARS_TITLE: QT_TRANSLATE_NOOP("Constant", "Characters in Headings"),
|
||||
nwStats.PARAGRAPHS: QT_TRANSLATE_NOOP("Constant", "Paragraphs"),
|
||||
nwStats.TITLES: QT_TRANSLATE_NOOP("Constant", "Headings"),
|
||||
nwStats.WCHARS_ALL: QT_TRANSLATE_NOOP("Constant", "Characters, No Spaces"),
|
||||
nwStats.WCHARS_TEXT: QT_TRANSLATE_NOOP("Constant", "Characters in Text, No Spaces"),
|
||||
nwStats.WCHARS_TITLE: QT_TRANSLATE_NOOP("Constant", "Characters in Headings, No Spaces"),
|
||||
nwStats.WORDS_ALL: QT_TRANSLATE_NOOP("Constant", "Words"),
|
||||
nwStats.WORDS_TEXT: QT_TRANSLATE_NOOP("Constant", "Words in Text"),
|
||||
nwStats.WORDS_TITLE: QT_TRANSLATE_NOOP("Constant", "Words in Headings"),
|
||||
}
|
||||
BUILD_FMT = {
|
||||
nwBuildFmt.ODT: QT_TRANSLATE_NOOP("Constant", "Open Document (.odt)"),
|
||||
nwBuildFmt.FODT: QT_TRANSLATE_NOOP("Constant", "Flat Open Document (.fodt)"),
|
||||
nwBuildFmt.HTML: QT_TRANSLATE_NOOP("Constant", "novelWriter HTML (.html)"),
|
||||
nwBuildFmt.DOCX: QT_TRANSLATE_NOOP("Constant", "Microsoft Word Document (.docx)"),
|
||||
nwBuildFmt.HTML: QT_TRANSLATE_NOOP("Constant", "HTML 5 (.html)"),
|
||||
nwBuildFmt.NWD: QT_TRANSLATE_NOOP("Constant", "novelWriter Markup (.txt)"),
|
||||
nwBuildFmt.STD_MD: QT_TRANSLATE_NOOP("Constant", "Standard Markdown (.md)"),
|
||||
nwBuildFmt.EXT_MD: QT_TRANSLATE_NOOP("Constant", "Extended Markdown (.md)"),
|
||||
nwBuildFmt.J_HTML: QT_TRANSLATE_NOOP("Constant", "JSON + novelWriter HTML (.json)"),
|
||||
nwBuildFmt.PDF: QT_TRANSLATE_NOOP("Constant", "Portable Document Format (.pdf)"),
|
||||
nwBuildFmt.J_HTML: QT_TRANSLATE_NOOP("Constant", "JSON + HTML 5 (.json)"),
|
||||
nwBuildFmt.J_NWD: QT_TRANSLATE_NOOP("Constant", "JSON + novelWriter Markup (.json)"),
|
||||
}
|
||||
BUILD_EXT = {
|
||||
nwBuildFmt.ODT: ".odt",
|
||||
nwBuildFmt.FODT: ".fodt",
|
||||
nwBuildFmt.DOCX: ".docx",
|
||||
nwBuildFmt.HTML: ".html",
|
||||
nwBuildFmt.NWD: ".txt",
|
||||
nwBuildFmt.STD_MD: ".md",
|
||||
nwBuildFmt.EXT_MD: ".md",
|
||||
nwBuildFmt.PDF: ".pdf",
|
||||
nwBuildFmt.J_HTML: ".json",
|
||||
nwBuildFmt.J_NWD: ".json",
|
||||
}
|
||||
SHAPES_PLAIN = {
|
||||
nwStatusShape.SQUARE: QT_TRANSLATE_NOOP("Constant", "Square"),
|
||||
nwStatusShape.TRIANGLE: QT_TRANSLATE_NOOP("Constant", "Triangle"),
|
||||
nwStatusShape.NABLA: QT_TRANSLATE_NOOP("Constant", "Nabla"),
|
||||
nwStatusShape.DIAMOND: QT_TRANSLATE_NOOP("Constant", "Diamond"),
|
||||
nwStatusShape.PENTAGON: QT_TRANSLATE_NOOP("Constant", "Pentagon"),
|
||||
nwStatusShape.HEXAGON: QT_TRANSLATE_NOOP("Constant", "Hexagon"),
|
||||
nwStatusShape.STAR: QT_TRANSLATE_NOOP("Constant", "Star"),
|
||||
nwStatusShape.PACMAN: QT_TRANSLATE_NOOP("Constant", "Pacman"),
|
||||
}
|
||||
SHAPES_CIRCLE = {
|
||||
nwStatusShape.CIRCLE_Q: QT_TRANSLATE_NOOP("Constant", "1/4 Circle"),
|
||||
nwStatusShape.CIRCLE_H: QT_TRANSLATE_NOOP("Constant", "Half Circle"),
|
||||
nwStatusShape.CIRCLE_T: QT_TRANSLATE_NOOP("Constant", "3/4 Circle"),
|
||||
nwStatusShape.CIRCLE: QT_TRANSLATE_NOOP("Constant", "Full Circle"),
|
||||
}
|
||||
SHAPES_BARS = {
|
||||
nwStatusShape.BARS_1: QT_TRANSLATE_NOOP("Constant", "1 Bar"),
|
||||
nwStatusShape.BARS_2: QT_TRANSLATE_NOOP("Constant", "2 Bars"),
|
||||
nwStatusShape.BARS_3: QT_TRANSLATE_NOOP("Constant", "3 Bars"),
|
||||
nwStatusShape.BARS_4: QT_TRANSLATE_NOOP("Constant", "4 Bars"),
|
||||
}
|
||||
SHAPES_BLOCKS = {
|
||||
nwStatusShape.BLOCK_1: QT_TRANSLATE_NOOP("Constant", "1 Block"),
|
||||
nwStatusShape.BLOCK_2: QT_TRANSLATE_NOOP("Constant", "2 Blocks"),
|
||||
nwStatusShape.BLOCK_3: QT_TRANSLATE_NOOP("Constant", "3 Blocks"),
|
||||
nwStatusShape.BLOCK_4: QT_TRANSLATE_NOOP("Constant", "4 Blocks"),
|
||||
}
|
||||
FILE_FILTERS = {
|
||||
"*.txt": QT_TRANSLATE_NOOP("Constant", "Text files"),
|
||||
"*.md": QT_TRANSLATE_NOOP("Constant", "Markdown files"),
|
||||
@@ -302,8 +427,6 @@ class nwLabels:
|
||||
"Custom": (-1.0, -1.0),
|
||||
}
|
||||
|
||||
# END Class nwLabels
|
||||
|
||||
|
||||
class nwHeadFmt:
|
||||
|
||||
@@ -323,13 +446,11 @@ class nwHeadFmt:
|
||||
CHAR_POV, CHAR_FOCUS
|
||||
]
|
||||
|
||||
# ODT Document Page Header
|
||||
ODT_PROJECT = "{Project}"
|
||||
ODT_AUTHOR = "{Author}"
|
||||
ODT_PAGE = "{Page}"
|
||||
ODT_AUTO = "{Project} / {Author} / {Page}"
|
||||
|
||||
# END Class nwHeadFmt
|
||||
# Document Page Header
|
||||
DOC_PROJECT = "{Project}"
|
||||
DOC_AUTHOR = "{Author}"
|
||||
DOC_PAGE = "{Page}"
|
||||
DOC_AUTO = "{Project} / {Author} / {Page}"
|
||||
|
||||
|
||||
class nwQuotes:
|
||||
@@ -361,8 +482,6 @@ class nwQuotes:
|
||||
"\u300f": QT_TRANSLATE_NOOP("Constant", "Right white corner bracket"),
|
||||
}
|
||||
|
||||
# END Class nwQuotes
|
||||
|
||||
|
||||
class nwUnicode:
|
||||
"""Supported unicode character constants and their HTML equivalents."""
|
||||
@@ -396,7 +515,7 @@ class nwUnicode:
|
||||
U_EMDASH = "\u2014" # Long dash
|
||||
U_HBAR = "\u2015" # Horizontal bar
|
||||
U_HELLIP = "\u2026" # Ellipsis
|
||||
U_MAPOSS = "\u02bc" # Modifier letter single apostrophe
|
||||
U_MAPOS = "\u02bc" # Modifier letter single apostrophe
|
||||
U_PRIME = "\u2032" # Prime
|
||||
U_DPRIME = "\u2033" # Double prime
|
||||
|
||||
@@ -433,6 +552,11 @@ class nwUnicode:
|
||||
U_LTRI = "\u25c0" # Left-pointing triangle
|
||||
U_LTRIS = "\u25c2" # Left-pointing triangle, small
|
||||
|
||||
# Special
|
||||
U_UNKN = "\ufffd" # Unknown character
|
||||
U_NAC1 = "\ufffe" # Not a character
|
||||
U_NAC2 = "\uffff" # Not a character
|
||||
|
||||
# HTML Equivalents
|
||||
# ================
|
||||
|
||||
@@ -463,7 +587,7 @@ class nwUnicode:
|
||||
H_EMDASH = "—"
|
||||
H_HBAR = "―"
|
||||
H_HELLIP = "…"
|
||||
H_MAPOSS = "ʼ"
|
||||
H_MAPOS = "ʼ"
|
||||
H_PRIME = "′"
|
||||
H_DPRIME = "″"
|
||||
|
||||
@@ -497,8 +621,6 @@ class nwUnicode:
|
||||
H_LTRI = "◀"
|
||||
H_LTRIS = "◂"
|
||||
|
||||
# END Class nwUnicode
|
||||
|
||||
|
||||
class nwHtmlUnicode():
|
||||
|
||||
@@ -530,7 +652,7 @@ class nwHtmlUnicode():
|
||||
nwUnicode.U_EMDASH: nwUnicode.H_EMDASH,
|
||||
nwUnicode.U_HBAR: nwUnicode.H_HBAR,
|
||||
nwUnicode.U_HELLIP: nwUnicode.H_HELLIP,
|
||||
nwUnicode.U_MAPOSS: nwUnicode.H_MAPOSS,
|
||||
nwUnicode.U_MAPOS: nwUnicode.H_MAPOS,
|
||||
nwUnicode.U_PRIME: nwUnicode.H_PRIME,
|
||||
nwUnicode.U_DPRIME: nwUnicode.H_DPRIME,
|
||||
|
||||
@@ -554,5 +676,3 @@ class nwHtmlUnicode():
|
||||
nwUnicode.U_TIMES: nwUnicode.H_TIMES,
|
||||
nwUnicode.U_DIVIDE: nwUnicode.H_DIVIDE,
|
||||
}
|
||||
|
||||
# END Class nwHtmlUnicode
|
||||
|
||||
@@ -25,49 +25,50 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import uuid
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
from collections.abc import Iterable
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from collections.abc import Iterable
|
||||
|
||||
from PyQt5.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.common import checkUuid, isHandle, jsonEncode
|
||||
from novelwriter.constants import nwFiles, nwHeadFmt, nwStyles
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.enum import nwBuildFmt
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.common import checkUuid, isHandle, jsonEncode
|
||||
from novelwriter.constants import nwFiles, nwHeadFmt
|
||||
from novelwriter.core.project import NWProject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# The Settings Template
|
||||
# =====================
|
||||
# Each entry contains a tuple on the form:
|
||||
# (type, default, [min value, max value])
|
||||
# Each entry contains a tuple on the form: (type, default)
|
||||
|
||||
SETTINGS_TEMPLATE = {
|
||||
SETTINGS_TEMPLATE: dict[str, tuple[type, str | int | float | bool]] = {
|
||||
"filter.includeNovel": (bool, True),
|
||||
"filter.includeNotes": (bool, False),
|
||||
"filter.includeInactive": (bool, False),
|
||||
"headings.fmtTitle": (str, nwHeadFmt.TITLE),
|
||||
"headings.fmtPart": (str, nwHeadFmt.TITLE),
|
||||
"headings.fmtChapter": (str, nwHeadFmt.TITLE),
|
||||
"headings.fmtUnnumbered": (str, nwHeadFmt.TITLE),
|
||||
"headings.fmtScene": (str, "* * *"),
|
||||
"headings.fmtAltScene": (str, ""),
|
||||
"headings.fmtSection": (str, ""),
|
||||
"headings.hideTitle": (bool, False),
|
||||
"headings.hidePart": (bool, False),
|
||||
"headings.hideChapter": (bool, False),
|
||||
"headings.hideUnnumbered": (bool, False),
|
||||
"headings.hideScene": (bool, False),
|
||||
"headings.hideAltScene": (bool, False),
|
||||
"headings.hideSection": (bool, True),
|
||||
"headings.centerTitle": (bool, True),
|
||||
"headings.centerPart": (bool, True),
|
||||
"headings.centerChapter": (bool, False),
|
||||
"headings.centerScene": (bool, False),
|
||||
"headings.breakTitle": (bool, True),
|
||||
"headings.breakTitle": (bool, False),
|
||||
"headings.breakPart": (bool, True),
|
||||
"headings.breakChapter": (bool, True),
|
||||
"headings.breakScene": (bool, False),
|
||||
"text.includeSynopsis": (bool, False),
|
||||
@@ -76,12 +77,30 @@ SETTINGS_TEMPLATE = {
|
||||
"text.includeBodyText": (bool, True),
|
||||
"text.ignoredKeywords": (str, ""),
|
||||
"text.addNoteHeadings": (bool, True),
|
||||
"format.textFont": (str, CONFIG.textFont),
|
||||
"format.textSize": (int, 12),
|
||||
"format.lineHeight": (float, 1.15, 0.75, 3.0),
|
||||
"format.textFont": (str, CONFIG.textFont.toString()),
|
||||
"format.lineHeight": (float, 1.15),
|
||||
"format.justifyText": (bool, False),
|
||||
"format.stripUnicode": (bool, False),
|
||||
"format.replaceTabs": (bool, False),
|
||||
"format.keepBreaks": (bool, True),
|
||||
"format.showDialogue": (bool, False),
|
||||
"format.firstLineIndent": (bool, False),
|
||||
"format.firstIndentWidth": (float, 1.4),
|
||||
"format.indentFirstPar": (bool, False),
|
||||
"format.titleMarginT": (float, nwStyles.T_MARGIN["H0"][0]),
|
||||
"format.titleMarginB": (float, nwStyles.T_MARGIN["H0"][1]),
|
||||
"format.h1MarginT": (float, nwStyles.T_MARGIN["H1"][0]),
|
||||
"format.h1MarginB": (float, nwStyles.T_MARGIN["H1"][1]),
|
||||
"format.h2MarginT": (float, nwStyles.T_MARGIN["H2"][0]),
|
||||
"format.h2MarginB": (float, nwStyles.T_MARGIN["H2"][1]),
|
||||
"format.h3MarginT": (float, nwStyles.T_MARGIN["H3"][0]),
|
||||
"format.h3MarginB": (float, nwStyles.T_MARGIN["H3"][1]),
|
||||
"format.h4MarginT": (float, nwStyles.T_MARGIN["H4"][0]),
|
||||
"format.h4MarginB": (float, nwStyles.T_MARGIN["H4"][1]),
|
||||
"format.textMarginT": (float, nwStyles.T_MARGIN["TT"][0]),
|
||||
"format.textMarginB": (float, nwStyles.T_MARGIN["TT"][1]),
|
||||
"format.sepMarginT": (float, nwStyles.T_MARGIN["SP"][0]),
|
||||
"format.sepMarginB": (float, nwStyles.T_MARGIN["SP"][1]),
|
||||
"format.pageUnit": (str, "cm"),
|
||||
"format.pageSize": (str, "A4"),
|
||||
"format.pageWidth": (float, 21.0),
|
||||
@@ -90,68 +109,78 @@ SETTINGS_TEMPLATE = {
|
||||
"format.bottomMargin": (float, 2.0),
|
||||
"format.leftMargin": (float, 2.0),
|
||||
"format.rightMargin": (float, 2.0),
|
||||
"odt.addColours": (bool, True),
|
||||
"odt.pageHeader": (str, nwHeadFmt.ODT_AUTO),
|
||||
"odt.pageCountOffset": (int, 0),
|
||||
"odt.firstLineIndent": (bool, False),
|
||||
"md.preserveBreaks": (bool, True),
|
||||
"doc.pageHeader": (str, nwHeadFmt.DOC_AUTO),
|
||||
"doc.pageCountOffset": (int, 0),
|
||||
"doc.colorHeadings": (bool, True),
|
||||
"doc.scaleHeadings": (bool, True),
|
||||
"doc.boldHeadings": (bool, True),
|
||||
"html.addStyles": (bool, True),
|
||||
"html.preserveTabs": (bool, False),
|
||||
}
|
||||
|
||||
SETTINGS_LABELS = {
|
||||
"filter": QT_TRANSLATE_NOOP("Builds", "Document Filters"),
|
||||
"filter.includeNovel": QT_TRANSLATE_NOOP("Builds", "Novel Documents"),
|
||||
"filter.includeNotes": QT_TRANSLATE_NOOP("Builds", "Project Notes"),
|
||||
"filter.includeInactive": QT_TRANSLATE_NOOP("Builds", "Inactive Documents"),
|
||||
"filter": QT_TRANSLATE_NOOP("Builds", "Document Filters"),
|
||||
"filter.includeNovel": QT_TRANSLATE_NOOP("Builds", "Novel Documents"),
|
||||
"filter.includeNotes": QT_TRANSLATE_NOOP("Builds", "Project Notes"),
|
||||
"filter.includeInactive": QT_TRANSLATE_NOOP("Builds", "Inactive Documents"),
|
||||
|
||||
"headings": QT_TRANSLATE_NOOP("Builds", "Headings"),
|
||||
"headings.fmtTitle": QT_TRANSLATE_NOOP("Builds", "Partition Format"),
|
||||
"headings.fmtChapter": QT_TRANSLATE_NOOP("Builds", "Chapter Format"),
|
||||
"headings.fmtUnnumbered": QT_TRANSLATE_NOOP("Builds", "Unnumbered Format"),
|
||||
"headings.fmtScene": QT_TRANSLATE_NOOP("Builds", "Scene Format"),
|
||||
"headings.fmtAltScene": QT_TRANSLATE_NOOP("Builds", "Alt. Scene Format"),
|
||||
"headings.fmtSection": QT_TRANSLATE_NOOP("Builds", "Section Format"),
|
||||
"headings": QT_TRANSLATE_NOOP("Builds", "Headings"),
|
||||
"headings.fmtPart": QT_TRANSLATE_NOOP("Builds", "Partition Format"),
|
||||
"headings.fmtChapter": QT_TRANSLATE_NOOP("Builds", "Chapter Format"),
|
||||
"headings.fmtUnnumbered": QT_TRANSLATE_NOOP("Builds", "Unnumbered Format"),
|
||||
"headings.fmtScene": QT_TRANSLATE_NOOP("Builds", "Scene Format"),
|
||||
"headings.fmtAltScene": QT_TRANSLATE_NOOP("Builds", "Alt. Scene Format"),
|
||||
"headings.fmtSection": QT_TRANSLATE_NOOP("Builds", "Section Format"),
|
||||
"headings.styleTitle": QT_TRANSLATE_NOOP("Builds", "Title Styling"),
|
||||
"headings.stylePart": QT_TRANSLATE_NOOP("Builds", "Partition Styling"),
|
||||
"headings.styleChapter": QT_TRANSLATE_NOOP("Builds", "Chapter Styling"),
|
||||
"headings.styleScene": QT_TRANSLATE_NOOP("Builds", "Scene Styling"),
|
||||
|
||||
"text.grpContent": QT_TRANSLATE_NOOP("Builds", "Text Content"),
|
||||
"text.includeSynopsis": QT_TRANSLATE_NOOP("Builds", "Include Synopsis"),
|
||||
"text.includeComments": QT_TRANSLATE_NOOP("Builds", "Include Comments"),
|
||||
"text.includeKeywords": QT_TRANSLATE_NOOP("Builds", "Include Keywords"),
|
||||
"text.includeBodyText": QT_TRANSLATE_NOOP("Builds", "Include Body Text"),
|
||||
"text.ignoredKeywords": QT_TRANSLATE_NOOP("Builds", "Ignore These Keywords"),
|
||||
"text.grpInsert": QT_TRANSLATE_NOOP("Builds", "Insert Content"),
|
||||
"text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"),
|
||||
"text.grpContent": QT_TRANSLATE_NOOP("Builds", "Text Content"),
|
||||
"text.includeSynopsis": QT_TRANSLATE_NOOP("Builds", "Include Synopsis"),
|
||||
"text.includeComments": QT_TRANSLATE_NOOP("Builds", "Include Comments"),
|
||||
"text.includeKeywords": QT_TRANSLATE_NOOP("Builds", "Include Keywords"),
|
||||
"text.includeBodyText": QT_TRANSLATE_NOOP("Builds", "Include Body Text"),
|
||||
"text.ignoredKeywords": QT_TRANSLATE_NOOP("Builds", "Ignore These Keywords"),
|
||||
"text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"),
|
||||
|
||||
"format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"),
|
||||
"format.textFont": QT_TRANSLATE_NOOP("Builds", "Font Family"),
|
||||
"format.textSize": QT_TRANSLATE_NOOP("Builds", "Font Size"),
|
||||
"format.lineHeight": QT_TRANSLATE_NOOP("Builds", "Line Height"),
|
||||
"format.grpOptions": QT_TRANSLATE_NOOP("Builds", "Text Options"),
|
||||
"format.justifyText": QT_TRANSLATE_NOOP("Builds", "Justify Text Margins"),
|
||||
"format.stripUnicode": QT_TRANSLATE_NOOP("Builds", "Replace Unicode Characters"),
|
||||
"format.replaceTabs": QT_TRANSLATE_NOOP("Builds", "Replace Tabs with Spaces"),
|
||||
"format.grpPage": QT_TRANSLATE_NOOP("Builds", "Page Layout"),
|
||||
"format.pageUnit": QT_TRANSLATE_NOOP("Builds", "Unit"),
|
||||
"format.pageSize": QT_TRANSLATE_NOOP("Builds", "Page Size"),
|
||||
"format.pageWidth": QT_TRANSLATE_NOOP("Builds", "Page Width"),
|
||||
"format.pageHeight": QT_TRANSLATE_NOOP("Builds", "Page Height"),
|
||||
"format.topMargin": QT_TRANSLATE_NOOP("Builds", "Top Margin"),
|
||||
"format.bottomMargin": QT_TRANSLATE_NOOP("Builds", "Bottom Margin"),
|
||||
"format.leftMargin": QT_TRANSLATE_NOOP("Builds", "Left Margin"),
|
||||
"format.rightMargin": QT_TRANSLATE_NOOP("Builds", "Right Margin"),
|
||||
"format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"),
|
||||
"format.textFont": QT_TRANSLATE_NOOP("Builds", "Text Font"),
|
||||
"format.lineHeight": QT_TRANSLATE_NOOP("Builds", "Line Height"),
|
||||
"format.justifyText": QT_TRANSLATE_NOOP("Builds", "Justify Text Margins"),
|
||||
"format.stripUnicode": QT_TRANSLATE_NOOP("Builds", "Replace Unicode Characters"),
|
||||
"format.replaceTabs": QT_TRANSLATE_NOOP("Builds", "Replace Tabs with Spaces"),
|
||||
"format.keepBreaks": QT_TRANSLATE_NOOP("Builds", "Preserve Hard Line Breaks"),
|
||||
"format.showDialogue": QT_TRANSLATE_NOOP("Builds", "Apply Dialogue Highlighting"),
|
||||
|
||||
"odt": QT_TRANSLATE_NOOP("Builds", "Open Document (.odt)"),
|
||||
"odt.addColours": QT_TRANSLATE_NOOP("Builds", "Add Highlight Colours"),
|
||||
"odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"),
|
||||
"odt.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"),
|
||||
"odt.firstLineIndent": QT_TRANSLATE_NOOP("Builds", "First Line Indent"),
|
||||
"format.grpParIndent": QT_TRANSLATE_NOOP("Builds", "First Line Indent"),
|
||||
"format.firstLineIndent": QT_TRANSLATE_NOOP("Builds", "Enable Indent"),
|
||||
"format.firstIndentWidth": QT_TRANSLATE_NOOP("Builds", "Indent Width"),
|
||||
"format.indentFirstPar": QT_TRANSLATE_NOOP("Builds", "Indent First Paragraph"),
|
||||
|
||||
"md": QT_TRANSLATE_NOOP("Builds", "Markdown (.md)"),
|
||||
"md.preserveBreaks": QT_TRANSLATE_NOOP("Builds", "Preserve Hard Line Breaks"),
|
||||
"format.grpMargins": QT_TRANSLATE_NOOP("Builds", "Text Margins"),
|
||||
|
||||
"html": QT_TRANSLATE_NOOP("Builds", "HTML (.html)"),
|
||||
"html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"),
|
||||
"html.preserveTabs": QT_TRANSLATE_NOOP("Builds", "Preserve Tab Characters"),
|
||||
"format.grpPage": QT_TRANSLATE_NOOP("Builds", "Page Layout"),
|
||||
"format.pageUnit": QT_TRANSLATE_NOOP("Builds", "Unit"),
|
||||
"format.pageSize": QT_TRANSLATE_NOOP("Builds", "Page Size"),
|
||||
"format.pageMargins": QT_TRANSLATE_NOOP("Builds", "Page Margins"),
|
||||
|
||||
"doc": QT_TRANSLATE_NOOP("Builds", "Document Style"),
|
||||
"doc.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"),
|
||||
"doc.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"),
|
||||
"doc.colorHeadings": QT_TRANSLATE_NOOP("Builds", "Add Colours to Headings"),
|
||||
"doc.scaleHeadings": QT_TRANSLATE_NOOP("Builds", "Increase Size of Headings"),
|
||||
"doc.boldHeadings": QT_TRANSLATE_NOOP("Builds", "Bold Headings"),
|
||||
|
||||
"html": QT_TRANSLATE_NOOP("Builds", "HTML Options"),
|
||||
"html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"),
|
||||
"html.preserveTabs": QT_TRANSLATE_NOOP("Builds", "Preserve Tab Characters"),
|
||||
}
|
||||
|
||||
RENAMED = {
|
||||
"odt.addColours": "doc.addColours",
|
||||
"odt.pageHeader": "doc.pageHeader",
|
||||
"odt.pageCountOffset": "doc.pageCountOffset",
|
||||
}
|
||||
|
||||
|
||||
@@ -165,8 +194,6 @@ class FilterMode(Enum):
|
||||
SKIPPED = 4
|
||||
ROOT = 5
|
||||
|
||||
# END Enum FilterMode
|
||||
|
||||
|
||||
class BuildSettings:
|
||||
"""Core: Build Settings Class
|
||||
@@ -216,7 +243,7 @@ class BuildSettings:
|
||||
return self._order
|
||||
|
||||
@property
|
||||
def lastPath(self) -> Path:
|
||||
def lastBuildPath(self) -> Path:
|
||||
"""The last used build path."""
|
||||
if self._path.is_dir():
|
||||
return self._path
|
||||
@@ -290,7 +317,7 @@ class BuildSettings:
|
||||
self._order = value
|
||||
return
|
||||
|
||||
def setLastPath(self, path: Path | str | None) -> None:
|
||||
def setLastBuildPath(self, path: Path | str | None) -> None:
|
||||
"""Set the last used build path."""
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
@@ -345,18 +372,12 @@ class BuildSettings:
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def setValue(self, key: str, value: str | int | bool | float) -> bool:
|
||||
def setValue(self, key: str, value: str | int | float | bool) -> None:
|
||||
"""Set a specific value for a build setting."""
|
||||
if key not in SETTINGS_TEMPLATE:
|
||||
return False
|
||||
definition = SETTINGS_TEMPLATE[key]
|
||||
if not isinstance(value, definition[0]):
|
||||
return False
|
||||
if len(definition) == 4 and isinstance(value, (int, float)):
|
||||
value = min(max(value, definition[2]), definition[3])
|
||||
self._changed = value != self._settings[key]
|
||||
self._settings[key] = value
|
||||
return True
|
||||
if (d := SETTINGS_TEMPLATE.get(key)) and len(d) == 2 and isinstance(value, d[0]):
|
||||
self._changed = value != self._settings[key]
|
||||
self._settings[key] = value
|
||||
return
|
||||
|
||||
##
|
||||
# Methods
|
||||
@@ -458,7 +479,7 @@ class BuildSettings:
|
||||
self.setName(data.get("name", ""))
|
||||
self.setBuildID(data.get("uuid", ""))
|
||||
self.setOrder(data.get("order", 0))
|
||||
self.setLastPath(data.get("path", None))
|
||||
self.setLastBuildPath(data.get("path", None))
|
||||
self.setLastBuildName(data.get("build", ""))
|
||||
|
||||
buildFmt = str(data.get("format", ""))
|
||||
@@ -475,13 +496,20 @@ class BuildSettings:
|
||||
self._settings = {k: v[1] for k, v in SETTINGS_TEMPLATE.items()}
|
||||
if isinstance(settings, dict):
|
||||
for key, value in settings.items():
|
||||
self.setValue(key, value)
|
||||
self.setValue(RENAMED.get(key, key), value)
|
||||
|
||||
self._changed = False
|
||||
|
||||
return
|
||||
|
||||
# END Class BuildSettings
|
||||
@classmethod
|
||||
def duplicate(cls, source: BuildSettings) -> BuildSettings:
|
||||
"""Make a copy of another build."""
|
||||
cls = BuildSettings()
|
||||
cls.unpack(source.pack())
|
||||
cls._uuid = str(uuid.uuid4())
|
||||
cls._name = f"{source.name} 2"
|
||||
return cls
|
||||
|
||||
|
||||
class BuildCollection:
|
||||
@@ -630,5 +658,3 @@ class BuildCollection:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# END Class BuildCollection
|
||||
|
||||
@@ -27,6 +27,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import re
|
||||
import shutil
|
||||
|
||||
from collections.abc import Iterable
|
||||
@@ -34,11 +35,11 @@ from functools import partial
|
||||
from pathlib import Path
|
||||
from zipfile import ZipFile, is_zipfile
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication, QRegularExpression
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.common import isHandle, minmax, simplified
|
||||
from novelwriter.constants import nwConst, nwFiles, nwItemClass
|
||||
from novelwriter.constants import nwConst, nwFiles, nwItemClass, nwStats
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.storage import NWStorageCreate
|
||||
@@ -55,10 +56,17 @@ class DocMerger:
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
self._project = project
|
||||
self._error = ""
|
||||
self._targetDoc = None
|
||||
self._targetText = []
|
||||
self._target = None
|
||||
self._text = []
|
||||
return
|
||||
|
||||
@property
|
||||
def targetHandle(self) -> str | None:
|
||||
"""Get the handle of the target document."""
|
||||
if self._target:
|
||||
return self._target.itemHandle
|
||||
return None
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
@@ -71,65 +79,56 @@ class DocMerger:
|
||||
"""Set the target document for the merging. Calling this
|
||||
function resets the class.
|
||||
"""
|
||||
self._targetDoc = tHandle
|
||||
self._targetText = []
|
||||
self._target = self._project.tree[tHandle]
|
||||
self._text = []
|
||||
return
|
||||
|
||||
def newTargetDoc(self, srcHandle: str, docLabel: str) -> str | None:
|
||||
def newTargetDoc(self, sHandle: str, label: str) -> None:
|
||||
"""Create a brand new target document based on a source handle
|
||||
and a new doc label. Calling this function resets the class.
|
||||
"""
|
||||
srcItem = self._project.tree[srcHandle]
|
||||
if srcItem is None or srcItem.itemParent is None:
|
||||
return None
|
||||
sItem = self._project.tree[sHandle]
|
||||
if sItem and sItem.itemParent:
|
||||
tHandle = self._project.newFile(label, sItem.itemParent)
|
||||
if nwItem := self._project.tree[tHandle]:
|
||||
nwItem.setLayout(sItem.itemLayout)
|
||||
nwItem.setStatus(sItem.itemStatus)
|
||||
nwItem.setImport(sItem.itemImport)
|
||||
nwItem.notifyToRefresh()
|
||||
self._target = nwItem
|
||||
self._text = []
|
||||
return
|
||||
|
||||
newHandle = self._project.newFile(docLabel, srcItem.itemParent)
|
||||
newItem = self._project.tree[newHandle]
|
||||
if isinstance(newItem, NWItem):
|
||||
newItem.setLayout(srcItem.itemLayout)
|
||||
newItem.setStatus(srcItem.itemStatus)
|
||||
newItem.setImport(srcItem.itemImport)
|
||||
|
||||
self._targetDoc = newHandle
|
||||
self._targetText = []
|
||||
|
||||
return newHandle
|
||||
|
||||
def appendText(self, srcHandle: str, addComment: bool, cmtPrefix: str) -> bool:
|
||||
def appendText(self, sHandle: str, addComment: bool, cmtPrefix: str) -> None:
|
||||
"""Append text from an existing document to the text buffer."""
|
||||
srcItem = self._project.tree[srcHandle]
|
||||
if srcItem is None:
|
||||
return False
|
||||
|
||||
docText = self._project.storage.getDocumentText(srcHandle).rstrip("\n")
|
||||
if addComment:
|
||||
docInfo = srcItem.describeMe()
|
||||
docSt, _ = srcItem.getImportStatus(incIcon=False)
|
||||
cmtLine = f"% {cmtPrefix} {docInfo}: {srcItem.itemName} [{docSt}]\n\n"
|
||||
docText = cmtLine + docText
|
||||
|
||||
self._targetText.append(docText)
|
||||
|
||||
return True
|
||||
if item := self._project.tree[sHandle]:
|
||||
text = self._project.storage.getDocumentText(sHandle).rstrip("\n")
|
||||
if addComment:
|
||||
info = item.describeMe()
|
||||
status, _ = item.getImportStatus()
|
||||
text = f"% {cmtPrefix} {info}: {item.itemName} [{status}]\n\n{text}"
|
||||
self._text.append(text)
|
||||
return
|
||||
|
||||
def writeTargetDoc(self) -> bool:
|
||||
"""Write the accumulated text into the designated target
|
||||
document, appending any existing text.
|
||||
"""
|
||||
if self._targetDoc is None:
|
||||
return False
|
||||
if self._target:
|
||||
outDoc = self._project.storage.getDocument(self._target.itemHandle)
|
||||
if text := (outDoc.readDocument() or "").rstrip("\n"):
|
||||
self._text.insert(0, text)
|
||||
|
||||
outDoc = self._project.storage.getDocument(self._targetDoc)
|
||||
if text := (outDoc.readDocument() or "").rstrip("\n"):
|
||||
self._targetText.insert(0, text)
|
||||
status = outDoc.writeDocument("\n\n".join(self._text) + "\n\n")
|
||||
if not status:
|
||||
self._error = outDoc.getError()
|
||||
|
||||
status = outDoc.writeDocument("\n\n".join(self._targetText) + "\n\n")
|
||||
if not status:
|
||||
self._error = outDoc.getError()
|
||||
self._project.index.reIndexHandle(self._target.itemHandle)
|
||||
self._target.notifyToRefresh()
|
||||
|
||||
return status
|
||||
return status
|
||||
|
||||
# END Class DocMerger
|
||||
return False
|
||||
|
||||
|
||||
class DocSplitter:
|
||||
@@ -173,23 +172,19 @@ class DocSplitter:
|
||||
self._inFolder = False
|
||||
return
|
||||
|
||||
def newParentFolder(self, pHandle: str, folderLabel: str) -> str | None:
|
||||
def newParentFolder(self, pHandle: str, folderLabel: str) -> None:
|
||||
"""Create a new folder that will be the top level parent item
|
||||
for the new documents.
|
||||
"""
|
||||
if self._srcItem is None:
|
||||
return None
|
||||
|
||||
newHandle = self._project.newFolder(folderLabel, pHandle)
|
||||
newItem = self._project.tree[newHandle]
|
||||
if isinstance(newItem, NWItem):
|
||||
newItem.setStatus(self._srcItem.itemStatus)
|
||||
newItem.setImport(self._srcItem.itemImport)
|
||||
|
||||
self._parHandle = newHandle
|
||||
self._inFolder = True
|
||||
|
||||
return newHandle
|
||||
if self._srcItem:
|
||||
nHandle = self._project.newFolder(folderLabel, pHandle)
|
||||
if nwItem := self._project.tree[nHandle]:
|
||||
nwItem.setStatus(self._srcItem.itemStatus)
|
||||
nwItem.setImport(self._srcItem.itemImport)
|
||||
nwItem.notifyToRefresh()
|
||||
self._parHandle = nHandle
|
||||
self._inFolder = True
|
||||
return
|
||||
|
||||
def splitDocument(self, splitData: list, splitText: list[str]) -> None:
|
||||
"""Loop through the split data record and perform the split job
|
||||
@@ -203,62 +198,52 @@ class DocSplitter:
|
||||
self._rawData.insert(0, (chunk, hLevel, hLabel))
|
||||
return
|
||||
|
||||
def writeDocuments(self, docHierarchy: bool) -> Iterable[tuple[bool, str | None, str | None]]:
|
||||
def writeDocuments(self, docHierarchy: bool) -> Iterable[bool]:
|
||||
"""An iterator that will write each document in the buffer, and
|
||||
return its new handle, parent handle, and sibling handle.
|
||||
"""
|
||||
if self._srcHandle is None or self._srcItem is None or self._parHandle is None:
|
||||
return
|
||||
if self._srcHandle and self._srcItem and self._parHandle:
|
||||
pHandle = self._parHandle
|
||||
hHandle = [self._parHandle, None, None, None, None]
|
||||
pLevel = 0
|
||||
for docText, hLevel, docLabel in self._rawData:
|
||||
|
||||
pHandle = self._parHandle
|
||||
nHandle = self._parHandle if self._inFolder else self._srcHandle
|
||||
hHandle = [self._parHandle, None, None, None, None]
|
||||
hLevel = minmax(hLevel, 1, 4)
|
||||
if pLevel == 0:
|
||||
pLevel = hLevel
|
||||
|
||||
pLevel = 0
|
||||
for docText, hLevel, docLabel in self._rawData:
|
||||
if docHierarchy:
|
||||
if hLevel == 1:
|
||||
pHandle = self._parHandle
|
||||
elif hLevel == 2:
|
||||
pHandle = hHandle[1] or hHandle[0]
|
||||
elif hLevel == 3:
|
||||
pHandle = hHandle[2] or hHandle[1] or hHandle[0]
|
||||
elif hLevel == 4:
|
||||
pHandle = hHandle[3] or hHandle[2] or hHandle[1] or hHandle[0]
|
||||
|
||||
hLevel = minmax(hLevel, 1, 4)
|
||||
if pLevel == 0:
|
||||
pLevel = hLevel
|
||||
if (
|
||||
(dHandle := self._project.newFile(docLabel, pHandle))
|
||||
and (nwItem := self._project.tree[dHandle])
|
||||
):
|
||||
hHandle[hLevel] = dHandle
|
||||
nwItem.setStatus(self._srcItem.itemStatus)
|
||||
nwItem.setImport(self._srcItem.itemImport)
|
||||
|
||||
if docHierarchy:
|
||||
if hLevel == 1:
|
||||
pHandle = self._parHandle
|
||||
elif hLevel == 2:
|
||||
pHandle = hHandle[1] or hHandle[0]
|
||||
elif hLevel == 3:
|
||||
pHandle = hHandle[2] or hHandle[1] or hHandle[0]
|
||||
elif hLevel == 4:
|
||||
pHandle = hHandle[3] or hHandle[2] or hHandle[1] or hHandle[0]
|
||||
outDoc = self._project.storage.getDocument(dHandle)
|
||||
status = outDoc.writeDocument("\n".join(docText))
|
||||
if not status:
|
||||
self._error = outDoc.getError()
|
||||
|
||||
if hLevel < pLevel:
|
||||
nHandle = hHandle[hLevel] or hHandle[0]
|
||||
elif hLevel > pLevel:
|
||||
nHandle = pHandle
|
||||
self._project.index.reIndexHandle(dHandle)
|
||||
nwItem.notifyToRefresh()
|
||||
|
||||
dHandle = self._project.newFile(docLabel, pHandle)
|
||||
hHandle[hLevel] = dHandle
|
||||
|
||||
newItem = self._project.tree[dHandle]
|
||||
if isinstance(newItem, NWItem):
|
||||
newItem.setStatus(self._srcItem.itemStatus)
|
||||
newItem.setImport(self._srcItem.itemImport)
|
||||
|
||||
outDoc = self._project.storage.getDocument(dHandle)
|
||||
status = outDoc.writeDocument("\n".join(docText))
|
||||
if not status:
|
||||
self._error = outDoc.getError()
|
||||
|
||||
yield status, dHandle, nHandle
|
||||
|
||||
hHandle[hLevel] = dHandle
|
||||
nHandle = dHandle
|
||||
pLevel = hLevel
|
||||
yield status
|
||||
|
||||
hHandle[hLevel] = dHandle
|
||||
pLevel = hLevel
|
||||
return
|
||||
|
||||
# END Class DocSplitter
|
||||
|
||||
|
||||
class DocDuplicator:
|
||||
"""A class that will duplicate all documents and folders starting
|
||||
@@ -273,38 +258,34 @@ class DocDuplicator:
|
||||
# Methods
|
||||
##
|
||||
|
||||
def duplicate(self, items: list[str]) -> Iterable[tuple[str, str | None]]:
|
||||
def duplicate(self, items: list[str]) -> list[str]:
|
||||
"""Run through a list of items, duplicate them, and copy the
|
||||
text content if they are documents.
|
||||
"""
|
||||
result = []
|
||||
after = True
|
||||
if items:
|
||||
nHandle = items[0]
|
||||
hMap: dict[str, str | None] = {t: None for t in items}
|
||||
for tHandle in items:
|
||||
newItem = self._project.tree.duplicate(tHandle)
|
||||
if newItem is None:
|
||||
return
|
||||
hMap[tHandle] = newItem.itemHandle
|
||||
if newItem.itemParent in hMap:
|
||||
newItem.setParent(hMap[newItem.itemParent])
|
||||
self._project.tree.updateItemData(newItem.itemHandle)
|
||||
if newItem.isFileType():
|
||||
newDoc = self._project.storage.getDocument(newItem.itemHandle)
|
||||
if newDoc.fileExists():
|
||||
return
|
||||
newDoc.writeDocument(self._project.storage.getDocumentText(tHandle))
|
||||
yield newItem.itemHandle, nHandle
|
||||
nHandle = None
|
||||
return
|
||||
|
||||
# END Class DocDuplicator
|
||||
if oldItem := self._project.tree[tHandle]:
|
||||
pHandle = hMap.get(oldItem.itemParent or "") or oldItem.itemParent
|
||||
if newItem := self._project.tree.duplicate(tHandle, pHandle, after):
|
||||
hMap[tHandle] = newItem.itemHandle
|
||||
if newItem.isFileType():
|
||||
self._project.copyFileContent(newItem.itemHandle, tHandle)
|
||||
newItem.notifyToRefresh()
|
||||
result.append(newItem.itemHandle)
|
||||
after = False
|
||||
else:
|
||||
break
|
||||
return result
|
||||
|
||||
|
||||
class DocSearch:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._regEx = QRegularExpression()
|
||||
self.setCaseSensitive(False)
|
||||
self._regEx = re.compile("")
|
||||
self._opts = re.UNICODE | re.IGNORECASE
|
||||
self._words = False
|
||||
self._escape = True
|
||||
return
|
||||
@@ -315,10 +296,9 @@ class DocSearch:
|
||||
|
||||
def setCaseSensitive(self, state: bool) -> None:
|
||||
"""Set the case sensitive search flag."""
|
||||
opts = QRegularExpression.PatternOption.UseUnicodePropertiesOption
|
||||
self._opts = re.UNICODE
|
||||
if not state:
|
||||
opts |= QRegularExpression.PatternOption.CaseInsensitiveOption
|
||||
self._regEx.setPatternOptions(opts)
|
||||
self._opts |= re.IGNORECASE
|
||||
return
|
||||
|
||||
def setWholeWords(self, state: bool) -> None:
|
||||
@@ -335,8 +315,8 @@ class DocSearch:
|
||||
self, project: NWProject, search: str
|
||||
) -> Iterable[tuple[NWItem, list[tuple[int, int, str]], bool]]:
|
||||
"""Iteratively search through documents in a project."""
|
||||
self._regEx.setPattern(self._buildPattern(search))
|
||||
logger.debug("Searching with pattern '%s'", self._regEx.pattern())
|
||||
self._regEx = re.compile(self._buildPattern(search), self._opts)
|
||||
logger.debug("Searching with pattern '%s'", self._regEx.pattern)
|
||||
storage = project.storage
|
||||
for item in project.tree:
|
||||
if item.isFileType():
|
||||
@@ -346,15 +326,15 @@ class DocSearch:
|
||||
|
||||
def searchText(self, text: str) -> tuple[list[tuple[int, int, str]], bool]:
|
||||
"""Search a piece of text for RegEx matches."""
|
||||
rxItt = self._regEx.globalMatch(text)
|
||||
count = 0
|
||||
capped = False
|
||||
results = []
|
||||
while rxItt.hasNext():
|
||||
rxMatch = rxItt.next()
|
||||
pos = rxMatch.capturedStart()
|
||||
num = rxMatch.capturedLength()
|
||||
context = text[pos:pos+100].partition("\n")[0]
|
||||
for res in self._regEx.finditer(text):
|
||||
pos = res.start(0)
|
||||
num = len(res.group(0))
|
||||
lim = text[:pos].rfind("\n") + 1
|
||||
cut = text[lim:pos].rfind(" ") + lim + 1
|
||||
context = text[cut:cut+100].partition("\n")[0]
|
||||
if context:
|
||||
results.append((pos, num, context))
|
||||
count += 1
|
||||
@@ -370,23 +350,11 @@ class DocSearch:
|
||||
def _buildPattern(self, search: str) -> str:
|
||||
"""Build the search pattern string."""
|
||||
if self._escape:
|
||||
if CONFIG.verQtValue >= 0x050f00:
|
||||
search = QRegularExpression.escape(search)
|
||||
else:
|
||||
# For older Qt versions, we escape manually
|
||||
escaped = ""
|
||||
for c in search:
|
||||
if c.isalnum() or c == "_":
|
||||
escaped += c
|
||||
else:
|
||||
escaped += f"\\{c}"
|
||||
search = escaped
|
||||
search = re.escape(search)
|
||||
if self._words:
|
||||
search = f"(?:^|\\b){search}(?:$|\\b)"
|
||||
return search
|
||||
|
||||
# END Class DocSearch
|
||||
|
||||
|
||||
class ProjectBuilder:
|
||||
"""A class to build a new project from a set of user-defined
|
||||
@@ -446,7 +414,6 @@ class ProjectBuilder:
|
||||
|
||||
lblNewProject = self.tr("New Project")
|
||||
lblTitlePage = self.tr("Title Page")
|
||||
lblByAuthors = self.tr("By")
|
||||
|
||||
# Settings
|
||||
project.data.setUuid(None)
|
||||
@@ -459,14 +426,29 @@ class ProjectBuilder:
|
||||
# Add Root Folders
|
||||
hNovelRoot = project.newRoot(nwItemClass.NOVEL)
|
||||
hTitlePage = project.newFile(lblTitlePage, hNovelRoot)
|
||||
novelTitle = project.data.name
|
||||
|
||||
titlePage = f"#! {novelTitle}\n\n"
|
||||
if project.data.author:
|
||||
titlePage += f">> {lblByAuthors} {project.data.author} <<\n\n"
|
||||
|
||||
# Generate Title Page
|
||||
aDoc = project.storage.getDocument(hTitlePage)
|
||||
aDoc.writeDocument(titlePage)
|
||||
aDoc.writeDocument((
|
||||
"{author}[br]\n"
|
||||
"{address} 1[br]\n"
|
||||
"{address} 2 <<\n"
|
||||
"\n"
|
||||
"[vspace:5]\n"
|
||||
"\n"
|
||||
"#! {title}\n"
|
||||
"\n"
|
||||
">> **{by} {author}** <<\n"
|
||||
"\n"
|
||||
">> {count}: [field:{field}] <<\n"
|
||||
).format(
|
||||
author=project.data.author or "None",
|
||||
address=self.tr("Address"),
|
||||
title=project.data.name or "None",
|
||||
by=self.tr("By"),
|
||||
count=self.tr("Word Count"),
|
||||
field=nwStats.WORDS_TEXT,
|
||||
))
|
||||
|
||||
# Create a project structure based on selected root folders
|
||||
# and a number of chapters and scenes selected in the
|
||||
@@ -527,7 +509,7 @@ class ProjectBuilder:
|
||||
|
||||
# Also add the archive and trash folders
|
||||
project.newRoot(nwItemClass.ARCHIVE)
|
||||
project.trashFolder()
|
||||
project.tree.trash # Triggers the creation of Trash
|
||||
|
||||
project.saveProject()
|
||||
project.closeProject()
|
||||
@@ -619,5 +601,3 @@ class ProjectBuilder:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# END Class ProjectBuilder
|
||||
|
||||
@@ -25,22 +25,25 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt5.QtGui import QFont, QFontInfo
|
||||
from PyQt5.QtGui import QFont
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.constants import nwLabels
|
||||
from novelwriter.core.buildsettings import BuildSettings
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.enum import nwBuildFmt
|
||||
from novelwriter.error import formatException, logException
|
||||
from novelwriter.constants import nwLabels
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.core.tomd import ToMarkdown
|
||||
from novelwriter.core.toodt import ToOdt
|
||||
from novelwriter.core.tohtml import ToHtml
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.tokenizer import Tokenizer
|
||||
from novelwriter.core.buildsettings import BuildSettings
|
||||
from novelwriter.formats.todocx import ToDocX
|
||||
from novelwriter.formats.tohtml import ToHtml
|
||||
from novelwriter.formats.tokenizer import Tokenizer
|
||||
from novelwriter.formats.tomarkdown import ToMarkdown
|
||||
from novelwriter.formats.toodt import ToOdt
|
||||
from novelwriter.formats.toqdoc import ToQTextDocument
|
||||
from novelwriter.formats.toraw import ToRaw
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -54,7 +57,7 @@ class NWBuildDocument:
|
||||
|
||||
__slots__ = (
|
||||
"_project", "_build", "_queue", "_error", "_cache", "_count",
|
||||
"_outline", "_preview"
|
||||
"_outline",
|
||||
)
|
||||
|
||||
def __init__(self, project: NWProject, build: BuildSettings) -> None:
|
||||
@@ -65,7 +68,6 @@ class NWBuildDocument:
|
||||
self._cache = None
|
||||
self._count = False
|
||||
self._outline = False
|
||||
self._preview = False
|
||||
return
|
||||
|
||||
##
|
||||
@@ -85,29 +87,6 @@ class NWBuildDocument:
|
||||
"""
|
||||
return self._cache
|
||||
|
||||
##
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setCountEnabled(self, state: bool) -> None:
|
||||
"""Turn on/off stats for builds."""
|
||||
self._count = state
|
||||
return
|
||||
|
||||
def setBuildOutline(self, state: bool) -> None:
|
||||
"""Turn on/off outline for builds."""
|
||||
self._outline = state
|
||||
return
|
||||
|
||||
def setPreviewMode(self, state: bool) -> None:
|
||||
"""Set the preview mode of the build. This also enables stats
|
||||
count and outline mode.
|
||||
"""
|
||||
self._preview = state
|
||||
self._outline = state
|
||||
self._count = state
|
||||
return
|
||||
|
||||
##
|
||||
# Special Methods
|
||||
##
|
||||
@@ -134,164 +113,117 @@ class NWBuildDocument:
|
||||
self._queue.append(item.itemHandle)
|
||||
return
|
||||
|
||||
def iterBuild(self, path: Path, bFormat: nwBuildFmt) -> Iterable[tuple[int, bool]]:
|
||||
"""Wrapper for builders based on format."""
|
||||
if bFormat in (nwBuildFmt.ODT, nwBuildFmt.FODT):
|
||||
yield from self.iterBuildOpenDocument(path, bFormat == nwBuildFmt.FODT)
|
||||
elif bFormat in (nwBuildFmt.HTML, nwBuildFmt.J_HTML):
|
||||
yield from self.iterBuildHTML(path, asJson=bFormat == nwBuildFmt.J_HTML)
|
||||
elif bFormat in (nwBuildFmt.STD_MD, nwBuildFmt.EXT_MD):
|
||||
yield from self.iterBuildMarkdown(path, bFormat == nwBuildFmt.EXT_MD)
|
||||
elif bFormat in (nwBuildFmt.NWD, nwBuildFmt.J_NWD):
|
||||
yield from self.iterBuildNWD(path, asJson=bFormat == nwBuildFmt.J_NWD)
|
||||
return
|
||||
|
||||
def iterBuildOpenDocument(self, path: Path, isFlat: bool) -> Iterable[tuple[int, bool]]:
|
||||
"""Build an Open Document file."""
|
||||
makeObj = ToOdt(self._project, isFlat=isFlat)
|
||||
def iterBuildPreview(self, newPage: bool) -> Iterable[tuple[int, bool]]:
|
||||
"""Build a preview QTextDocument."""
|
||||
makeObj = ToQTextDocument(self._project)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
makeObj.initDocument()
|
||||
|
||||
for i, tHandle in enumerate(self._queue):
|
||||
self._error = None
|
||||
if filtered.get(tHandle, (False, 0))[0]:
|
||||
yield i, self._doBuild(makeObj, tHandle)
|
||||
else:
|
||||
yield i, False
|
||||
|
||||
makeObj.setShowNewPage(newPage)
|
||||
self._outline = True
|
||||
yield from self._iterBuild(makeObj, filtered)
|
||||
makeObj.closeDocument()
|
||||
|
||||
self._error = None
|
||||
self._cache = makeObj
|
||||
|
||||
try:
|
||||
if isFlat:
|
||||
makeObj.saveFlatXML(path)
|
||||
else:
|
||||
makeObj.saveOpenDocText(path)
|
||||
except Exception as exc:
|
||||
logException()
|
||||
self._error = formatException(exc)
|
||||
|
||||
return
|
||||
|
||||
def iterBuildHTML(self, path: Path | None, asJson: bool = False) -> Iterable[tuple[int, bool]]:
|
||||
"""Build an HTML file. If path is None, no file is saved. This
|
||||
is used for generating build previews.
|
||||
"""
|
||||
makeObj = ToHtml(self._project)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
|
||||
makeObj.setPreview(self._preview)
|
||||
makeObj.setLinkHeadings(self._preview)
|
||||
for i, tHandle in enumerate(self._queue):
|
||||
self._error = None
|
||||
if filtered.get(tHandle, (False, 0))[0]:
|
||||
yield i, self._doBuild(makeObj, tHandle)
|
||||
else:
|
||||
yield i, False
|
||||
|
||||
if not (self._build.getBool("html.preserveTabs") or self._preview):
|
||||
makeObj.replaceTabs()
|
||||
|
||||
def iterBuildDocument(self, path: Path, bFormat: nwBuildFmt) -> Iterable[tuple[int, bool]]:
|
||||
"""Wrapper for builders based on format."""
|
||||
self._error = None
|
||||
self._cache = makeObj
|
||||
self._cache = None
|
||||
|
||||
if isinstance(path, Path):
|
||||
try:
|
||||
if asJson:
|
||||
makeObj.saveHtmlJson(path)
|
||||
else:
|
||||
makeObj.saveHtml5(path)
|
||||
except Exception as exc:
|
||||
logException()
|
||||
self._error = formatException(exc)
|
||||
if bFormat in (nwBuildFmt.J_HTML, nwBuildFmt.J_NWD):
|
||||
# Ensure that JSON output has the correct extension
|
||||
path = path.with_suffix(".json")
|
||||
|
||||
return
|
||||
if bFormat in (nwBuildFmt.ODT, nwBuildFmt.FODT):
|
||||
makeObj = ToOdt(self._project, bFormat == nwBuildFmt.FODT)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
makeObj.initDocument()
|
||||
yield from self._iterBuild(makeObj, filtered)
|
||||
makeObj.closeDocument()
|
||||
|
||||
def iterBuildMarkdown(self, path: Path, extendedMd: bool) -> Iterable[tuple[int, bool]]:
|
||||
"""Build a Markdown file."""
|
||||
makeObj = ToMarkdown(self._project)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
elif bFormat in (nwBuildFmt.HTML, nwBuildFmt.J_HTML):
|
||||
makeObj = ToHtml(self._project)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
makeObj.initDocument()
|
||||
yield from self._iterBuild(makeObj, filtered)
|
||||
makeObj.closeDocument()
|
||||
if not self._build.getBool("html.preserveTabs"):
|
||||
makeObj.replaceTabs()
|
||||
|
||||
elif bFormat in (nwBuildFmt.STD_MD, nwBuildFmt.EXT_MD):
|
||||
makeObj = ToMarkdown(self._project, bFormat == nwBuildFmt.EXT_MD)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
yield from self._iterBuild(makeObj, filtered)
|
||||
makeObj.closeDocument()
|
||||
if self._build.getBool("format.replaceTabs"):
|
||||
makeObj.replaceTabs(nSpaces=4, spaceChar=" ")
|
||||
|
||||
elif bFormat in (nwBuildFmt.NWD, nwBuildFmt.J_NWD):
|
||||
makeObj = ToRaw(self._project)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
yield from self._iterBuild(makeObj, filtered)
|
||||
makeObj.closeDocument()
|
||||
if self._build.getBool("format.replaceTabs"):
|
||||
makeObj.replaceTabs(nSpaces=4, spaceChar=" ")
|
||||
|
||||
elif bFormat == nwBuildFmt.DOCX:
|
||||
makeObj = ToDocX(self._project)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
makeObj.initDocument()
|
||||
yield from self._iterBuild(makeObj, filtered)
|
||||
makeObj.closeDocument()
|
||||
|
||||
elif bFormat == nwBuildFmt.PDF:
|
||||
makeObj = ToQTextDocument(self._project)
|
||||
makeObj.disableAnchors()
|
||||
filtered = self._setupBuild(makeObj)
|
||||
makeObj.initDocument(pdf=True)
|
||||
yield from self._iterBuild(makeObj, filtered)
|
||||
makeObj.closeDocument()
|
||||
|
||||
if extendedMd:
|
||||
makeObj.setExtendedMarkdown()
|
||||
else:
|
||||
makeObj.setStandardMarkdown()
|
||||
|
||||
if self._build.getBool("format.replaceTabs"):
|
||||
makeObj.replaceTabs(nSpaces=4, spaceChar=" ")
|
||||
|
||||
makeObj.setPreserveBreaks(self._build.getBool("md.preserveBreaks"))
|
||||
|
||||
for i, tHandle in enumerate(self._queue):
|
||||
self._error = None
|
||||
if filtered.get(tHandle, (False, 0))[0]:
|
||||
yield i, self._doBuild(makeObj, tHandle)
|
||||
else:
|
||||
yield i, False
|
||||
logger.error("Unsupported document format")
|
||||
return
|
||||
|
||||
self._error = None
|
||||
self._cache = makeObj
|
||||
|
||||
try:
|
||||
makeObj.saveMarkdown(path)
|
||||
makeObj.saveDocument(path)
|
||||
except Exception as exc:
|
||||
logException()
|
||||
self._error = formatException(exc)
|
||||
|
||||
return
|
||||
|
||||
def iterBuildNWD(self, path: Path | None, asJson: bool = False) -> Iterable[tuple[int, bool]]:
|
||||
"""Build a novelWriter Markdown file."""
|
||||
makeObj = ToMarkdown(self._project)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
|
||||
makeObj.setKeepMarkdown(True)
|
||||
|
||||
for i, tHandle in enumerate(self._queue):
|
||||
self._error = None
|
||||
if filtered.get(tHandle, (False, 0))[0]:
|
||||
yield i, self._doBuild(makeObj, tHandle, convert=False)
|
||||
else:
|
||||
yield i, False
|
||||
|
||||
if self._build.getBool("format.replaceTabs"):
|
||||
makeObj.replaceTabs(nSpaces=4, spaceChar=" ")
|
||||
|
||||
self._error = None
|
||||
self._cache = makeObj
|
||||
|
||||
if isinstance(path, Path):
|
||||
try:
|
||||
if asJson:
|
||||
makeObj.saveRawMarkdownJSON(path)
|
||||
else:
|
||||
makeObj.saveRawMarkdown(path)
|
||||
except Exception as exc:
|
||||
logException()
|
||||
self._error = formatException(exc)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _iterBuild(self, makeObj: Tokenizer, filtered: dict) -> Iterable[tuple[int, bool]]:
|
||||
"""Iterate over buildable documents."""
|
||||
self._count = True
|
||||
for i, tHandle in enumerate(self._queue):
|
||||
self._error = None
|
||||
if filtered.get(tHandle, (False, 0))[0]:
|
||||
yield i, self._doBuild(makeObj, tHandle)
|
||||
else:
|
||||
yield i, False
|
||||
return
|
||||
|
||||
def _setupBuild(self, bldObj: Tokenizer) -> dict:
|
||||
"""Configure the build object."""
|
||||
# Get Settings
|
||||
textFont = self._build.getStr("format.textFont")
|
||||
textSize = self._build.getInt("format.textSize")
|
||||
textFont = QFont(CONFIG.textFont)
|
||||
textFont.fromString(self._build.getStr("format.textFont"))
|
||||
|
||||
fontFamily = textFont or CONFIG.textFont
|
||||
bldFont = QFont(fontFamily, textSize)
|
||||
fontInfo = QFontInfo(bldFont)
|
||||
textFixed = fontInfo.fixedPitch()
|
||||
bldObj.setTextFont(textFont)
|
||||
bldObj.setLanguage(self._project.data.language)
|
||||
|
||||
bldObj.setTitleFormat(
|
||||
self._build.getStr("headings.fmtTitle"),
|
||||
self._build.getBool("headings.hideTitle")
|
||||
bldObj.setPartitionFormat(
|
||||
self._build.getStr("headings.fmtPart"),
|
||||
self._build.getBool("headings.hidePart")
|
||||
)
|
||||
bldObj.setChapterFormat(
|
||||
self._build.getStr("headings.fmtChapter"),
|
||||
@@ -317,6 +249,10 @@ class NWBuildDocument:
|
||||
self._build.getBool("headings.centerTitle"),
|
||||
self._build.getBool("headings.breakTitle")
|
||||
)
|
||||
bldObj.setPartitionStyle(
|
||||
self._build.getBool("headings.centerPart"),
|
||||
self._build.getBool("headings.breakPart")
|
||||
)
|
||||
bldObj.setChapterStyle(
|
||||
self._build.getBool("headings.centerChapter"),
|
||||
self._build.getBool("headings.breakChapter")
|
||||
@@ -326,9 +262,49 @@ class NWBuildDocument:
|
||||
self._build.getBool("headings.breakScene")
|
||||
)
|
||||
|
||||
bldObj.setFont(fontFamily, textSize, textFixed)
|
||||
bldObj.setJustify(self._build.getBool("format.justifyText"))
|
||||
bldObj.setLineHeight(self._build.getFloat("format.lineHeight"))
|
||||
bldObj.setKeepLineBreaks(self._build.getBool("format.keepBreaks"))
|
||||
bldObj.setDialogHighlight(self._build.getBool("format.showDialogue"))
|
||||
bldObj.setFirstLineIndent(
|
||||
self._build.getBool("format.firstLineIndent"),
|
||||
self._build.getFloat("format.firstIndentWidth"),
|
||||
self._build.getBool("format.indentFirstPar"),
|
||||
)
|
||||
bldObj.setHeadingStyles(
|
||||
self._build.getBool("doc.colorHeadings"),
|
||||
self._build.getBool("doc.scaleHeadings"),
|
||||
self._build.getBool("doc.boldHeadings"),
|
||||
)
|
||||
|
||||
bldObj.setTitleMargins(
|
||||
self._build.getFloat("format.titleMarginT"),
|
||||
self._build.getFloat("format.titleMarginB"),
|
||||
)
|
||||
bldObj.setHead1Margins(
|
||||
self._build.getFloat("format.h1MarginT"),
|
||||
self._build.getFloat("format.h1MarginB"),
|
||||
)
|
||||
bldObj.setHead2Margins(
|
||||
self._build.getFloat("format.h2MarginT"),
|
||||
self._build.getFloat("format.h2MarginB"),
|
||||
)
|
||||
bldObj.setHead3Margins(
|
||||
self._build.getFloat("format.h3MarginT"),
|
||||
self._build.getFloat("format.h3MarginB"),
|
||||
)
|
||||
bldObj.setHead4Margins(
|
||||
self._build.getFloat("format.h4MarginT"),
|
||||
self._build.getFloat("format.h4MarginB"),
|
||||
)
|
||||
bldObj.setTextMargins(
|
||||
self._build.getFloat("format.textMarginT"),
|
||||
self._build.getFloat("format.textMarginB"),
|
||||
)
|
||||
bldObj.setSeparatorMargins(
|
||||
self._build.getFloat("format.sepMarginT"),
|
||||
self._build.getFloat("format.sepMarginB"),
|
||||
)
|
||||
|
||||
bldObj.setBodyText(self._build.getBool("text.includeBodyText"))
|
||||
bldObj.setSynopsis(self._build.getBool("text.includeSynopsis"))
|
||||
@@ -340,14 +316,13 @@ class NWBuildDocument:
|
||||
bldObj.setStyles(self._build.getBool("html.addStyles"))
|
||||
bldObj.setReplaceUnicode(self._build.getBool("format.stripUnicode"))
|
||||
|
||||
if isinstance(bldObj, ToOdt):
|
||||
bldObj.setColourHeaders(self._build.getBool("odt.addColours"))
|
||||
bldObj.setLanguage(self._project.data.language)
|
||||
if isinstance(bldObj, (ToOdt, ToDocX)):
|
||||
bldObj.setHeaderFormat(
|
||||
self._build.getStr("odt.pageHeader"), self._build.getInt("odt.pageCountOffset")
|
||||
self._build.getStr("doc.pageHeader"),
|
||||
self._build.getInt("doc.pageCountOffset"),
|
||||
)
|
||||
bldObj.setFirstLineIndent(self._build.getBool("odt.firstLineIndent"))
|
||||
|
||||
if isinstance(bldObj, (ToOdt, ToDocX, ToQTextDocument)):
|
||||
scale = nwLabels.UNIT_SCALE.get(self._build.getStr("format.pageUnit"), 1.0)
|
||||
pW, pH = nwLabels.PAPER_SIZE.get(self._build.getStr("format.pageSize"), (-1.0, -1.0))
|
||||
bldObj.setPageLayout(
|
||||
@@ -370,14 +345,17 @@ class NWBuildDocument:
|
||||
tItem = self._project.tree[tHandle]
|
||||
if isinstance(tItem, NWItem):
|
||||
try:
|
||||
if tItem.isRootType() and not tItem.isNovelLike():
|
||||
bldObj.addRootHeading(tHandle)
|
||||
if convert:
|
||||
bldObj.doConvert()
|
||||
if self._count:
|
||||
bldObj.countStats()
|
||||
if self._outline:
|
||||
bldObj.buildOutline()
|
||||
if tItem.isRootType():
|
||||
if tItem.isNovelLike():
|
||||
bldObj.setBreakNext()
|
||||
else:
|
||||
bldObj.addRootHeading(tHandle)
|
||||
if convert:
|
||||
bldObj.doConvert()
|
||||
if self._count:
|
||||
bldObj.countStats()
|
||||
if self._outline:
|
||||
bldObj.buildOutline()
|
||||
elif tItem.isFileType():
|
||||
bldObj.setText(tHandle)
|
||||
bldObj.doPreProcessing()
|
||||
@@ -388,8 +366,6 @@ class NWBuildDocument:
|
||||
bldObj.buildOutline()
|
||||
if convert:
|
||||
bldObj.doConvert()
|
||||
else:
|
||||
logger.info(f"Build: Skipping '{tHandle}'")
|
||||
|
||||
except Exception:
|
||||
self._error = f"Build: Failed to build '{tHandle}'"
|
||||
@@ -397,5 +373,3 @@ class NWBuildDocument:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# END Class NWBuildDocument
|
||||
|
||||
@@ -26,14 +26,14 @@ from __future__ import annotations
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
|
||||
from novelwriter.enum import nwItemLayout, nwItemClass
|
||||
from novelwriter.error import formatException, logException
|
||||
from novelwriter.common import formatTimeStamp, isHandle
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout
|
||||
from novelwriter.error import formatException, logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.core.project import NWProject
|
||||
@@ -359,5 +359,3 @@ class NWDocument:
|
||||
logger.debug("Unknown meta data: '%s'", metaLine.strip())
|
||||
|
||||
return
|
||||
|
||||
# END Class NWDocument
|
||||
|
||||