Compare commits
512 Commits
ioprofiles
...
feature/cl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d34ce7f76 | ||
|
|
a0a16fc300 | ||
|
|
f99ccf97dc | ||
|
|
2d2749cb20 | ||
|
|
471ec29f5d | ||
|
|
56144f757d | ||
|
|
1c49b02763 | ||
|
|
60784c47d9 | ||
|
|
bd89df3564 | ||
|
|
b4e1077cb1 | ||
|
|
f518345430 | ||
|
|
f02c93c8c8 | ||
|
|
d10fe84c3a | ||
|
|
e9c818242e | ||
|
|
0bec01bfb4 | ||
|
|
9abe78ce5f | ||
|
|
f809041f85 | ||
|
|
f58710c76f | ||
|
|
267b39bc9d | ||
|
|
11ad932965 | ||
|
|
048cfcce81 | ||
|
|
33adf4106f | ||
|
|
a8ec5d6f16 | ||
|
|
384fb1da7c | ||
|
|
8e44e0f41a | ||
|
|
f851dd0a72 | ||
|
|
7038c02173 | ||
|
|
6747b8dd7c | ||
|
|
cf68aca735 | ||
|
|
265caf0df7 | ||
|
|
477621dd3e | ||
|
|
f77dad0c47 | ||
|
|
4faa6d522d | ||
|
|
ef11a4b7ef | ||
|
|
3bcf11264b | ||
|
|
68af947687 | ||
|
|
002c85e35f | ||
|
|
fed2bf21fe | ||
|
|
3f51308057 | ||
|
|
70d7d1b9ce | ||
|
|
c1082f2e3e | ||
|
|
7038b30381 | ||
|
|
1d73abda51 | ||
|
|
f157648d1e | ||
|
|
d4baaeccfc | ||
|
|
d412b66c6e | ||
|
|
74ae511f92 | ||
|
|
a3fbafe4ae | ||
|
|
8a45fbe9ed | ||
|
|
01c7929ee3 | ||
|
|
2261af17d7 | ||
|
|
41f34c3992 | ||
|
|
36b1cd2dde | ||
|
|
80374b3ec6 | ||
|
|
bc00d1e45f | ||
|
|
6ddb507247 | ||
|
|
b0f3b8f3d0 | ||
|
|
06e7191056 | ||
|
|
997131ba64 | ||
|
|
ef9f412e5f | ||
|
|
7b69d41c60 | ||
|
|
552947f507 | ||
|
|
f69f2df63c | ||
|
|
aa270067f6 | ||
|
|
28977313da | ||
|
|
cfe35d7795 | ||
|
|
4abbe332db | ||
|
|
3104abd4ad | ||
|
|
7714f7b503 | ||
|
|
9d06f10a9b | ||
|
|
8c27f7683b | ||
|
|
bf1a491789 | ||
|
|
701cb540e5 | ||
|
|
0f18a0349a | ||
|
|
205a152350 | ||
|
|
dae1a56691 | ||
|
|
39181f42cf | ||
|
|
3d706ad1a7 | ||
|
|
a31b77e5bc | ||
|
|
b417643415 | ||
|
|
dac2b4ff16 | ||
|
|
2d12b0c747 | ||
|
|
5fe26edaa6 | ||
|
|
a736cfd548 | ||
|
|
5af4214daa | ||
|
|
98ef7b329a | ||
|
|
b0e1962fa7 | ||
|
|
83684e8882 | ||
|
|
1ed7d077a9 | ||
|
|
ba4b36618f | ||
|
|
af647a4bad | ||
|
|
b719530ef0 | ||
|
|
530d61d67e | ||
|
|
3d76bcb48c | ||
|
|
70ce2f1f3c | ||
|
|
21a190a1aa | ||
|
|
a88d222709 | ||
|
|
b2defceae5 | ||
|
|
8d7565ffc4 | ||
|
|
9960b25dff | ||
|
|
411c116deb | ||
|
|
64e007f1fd | ||
|
|
c62fc365db | ||
|
|
e7e630bd5d | ||
|
|
7d77175fbb | ||
|
|
f033553972 | ||
|
|
ae1ed044ba | ||
|
|
35d601c7a7 | ||
|
|
f89aeec374 | ||
|
|
42c3b4b42e | ||
|
|
322fc31396 | ||
|
|
6e4d5cfddd | ||
|
|
d81485a8bf | ||
|
|
a9260d956c | ||
|
|
025bb560bc | ||
|
|
cdd1488e13 | ||
|
|
b8b2644969 | ||
|
|
09b5c0a5d0 | ||
|
|
1ed66f3aa2 | ||
|
|
3b4d5d1c3f | ||
|
|
f98fd5a7ad | ||
|
|
b961109623 | ||
|
|
8f0d1023a4 | ||
|
|
79773ba95c | ||
|
|
ff3f02fb8c | ||
|
|
0af2b20b3a | ||
|
|
b026fe357e | ||
|
|
ade36c013b | ||
|
|
54a6a7f590 | ||
|
|
20728e4a0f | ||
|
|
afa456f6b3 | ||
|
|
3fbfb77430 | ||
|
|
051bcb62c6 | ||
|
|
d2c57eed6d | ||
|
|
f2f38c0e0d | ||
|
|
4046bdbc6a | ||
|
|
c83cc206fd | ||
|
|
41ac14fbd3 | ||
|
|
e4c1cad1a7 | ||
|
|
863c1ac27a | ||
|
|
c85eba617c | ||
|
|
dcb7b7c309 | ||
|
|
3cee186663 | ||
|
|
06afe507f6 | ||
|
|
4268d4d770 | ||
|
|
d61dae5ab4 | ||
|
|
b5f39c1d53 | ||
|
|
767a61b86e | ||
|
|
0d3c0a2233 | ||
|
|
0431103a1d | ||
|
|
633e4e642c | ||
|
|
77dc82a381 | ||
|
|
44a63d4aaa | ||
|
|
5b3297f916 | ||
|
|
41413d4712 | ||
|
|
fd2e5ce71e | ||
|
|
e9ddd7d3b8 | ||
|
|
da6795f002 | ||
|
|
f497bb4b44 | ||
|
|
4aea85649f | ||
|
|
c56672dd04 | ||
|
|
c2dc1cd65f | ||
|
|
555783af4c | ||
|
|
b9ffae25e3 | ||
|
|
0f89936e01 | ||
|
|
6ecccb3fe1 | ||
|
|
2e003b56ea | ||
|
|
a705418b6f | ||
|
|
9767eb9d7f | ||
|
|
450b15944f | ||
|
|
1fa7cb2afa | ||
|
|
d2415ff5f9 | ||
|
|
cdbe8d73f6 | ||
|
|
38ae86f315 | ||
|
|
100201d23c | ||
|
|
db7a7f38f7 | ||
|
|
677ad5c54b | ||
|
|
b8e3cd5d64 | ||
|
|
dead1197bd | ||
|
|
a2455daa6c | ||
|
|
ddff1fc455 | ||
|
|
82f2bd6231 | ||
|
|
cc7c13e17f | ||
|
|
04a64e1312 | ||
|
|
bfecd9ebc6 | ||
|
|
6fb8ceb501 | ||
|
|
8124d101ad | ||
|
|
de8602847e | ||
|
|
9d1ca1986d | ||
|
|
a0312ff604 | ||
|
|
6f04513faa | ||
|
|
a747f55423 | ||
|
|
d27e6569a0 | ||
|
|
135ed0bf8b | ||
|
|
67ac27c054 | ||
|
|
4e123d747a | ||
|
|
9df470acfc | ||
|
|
af8edc72f4 | ||
|
|
2b2ae66b8d | ||
|
|
0a95c5dff3 | ||
|
|
56e1d80cf4 | ||
|
|
65432fd317 | ||
|
|
2ec21f5eba | ||
|
|
92e82c203f | ||
|
|
272bc5fe89 | ||
|
|
e8d5efd3b3 | ||
|
|
8b1a0a5b8e | ||
|
|
293b05fec6 | ||
|
|
37ba495354 | ||
|
|
a2e689a0dc | ||
|
|
2ea119fb31 | ||
|
|
162f59d220 | ||
|
|
880c5e722e | ||
|
|
82efa28703 | ||
|
|
c091a90cea | ||
|
|
e4c014c1a8 | ||
|
|
fe4704d0f6 | ||
|
|
9ea797b00b | ||
|
|
683f202191 | ||
|
|
1cf6e2743b | ||
|
|
2375aefebb | ||
|
|
1e04f66a11 | ||
|
|
f8bd483139 | ||
|
|
3548ce84c1 | ||
|
|
90b68f9987 | ||
|
|
44e895ee08 | ||
|
|
8032547fd0 | ||
|
|
a34dc35f0f | ||
|
|
68a5f0dd4b | ||
|
|
654f8d0761 | ||
|
|
942ff8bf4a | ||
|
|
e2c4392c6d | ||
|
|
7e771b1cfc | ||
|
|
dd799cf5c0 | ||
|
|
b8be28619a | ||
|
|
ca012a1c80 | ||
|
|
50de42ec9f | ||
|
|
38c9dd50ff | ||
|
|
27e4e3444a | ||
|
|
a8935da416 | ||
|
|
beb56c527b | ||
|
|
5e3caedaf6 | ||
|
|
0be17716f5 | ||
|
|
dda5fbc330 | ||
|
|
ffc16c6814 | ||
|
|
705371d7ee | ||
|
|
7c7810836e | ||
|
|
af9c039dcb | ||
|
|
7325835c3f | ||
|
|
e7aa72a7ab | ||
|
|
35c48de638 | ||
|
|
ae50ed980f | ||
|
|
1d6f0445f7 | ||
|
|
799ef63b81 | ||
|
|
6b22a0c03a | ||
|
|
2d54638f49 | ||
|
|
8adec835f6 | ||
|
|
a34654a9a9 | ||
|
|
b7c8108ad5 | ||
|
|
c34c3c3654 | ||
|
|
88988dd3e1 | ||
|
|
351b98189f | ||
|
|
e6a049c214 | ||
|
|
b9d027291e | ||
|
|
eb00915c39 | ||
|
|
828a22a939 | ||
|
|
875d02458e | ||
|
|
51d59cc90b | ||
|
|
a6d6ced1ad | ||
|
|
7e9855881b | ||
|
|
cf4e7ca279 | ||
|
|
0a9b2b0bac | ||
|
|
f6b0a63410 | ||
|
|
7563cd4a08 | ||
|
|
851f6d6624 | ||
|
|
cd97acfcc1 | ||
|
|
613a2c5583 | ||
|
|
4bff6efe97 | ||
|
|
c514dc7a24 | ||
|
|
32e95185ad | ||
|
|
24754edb6a | ||
|
|
79fbb76524 | ||
|
|
bbe61e4443 | ||
|
|
b85aede966 | ||
|
|
c66ca6e44f | ||
|
|
a192024fef | ||
|
|
918df9098a | ||
|
|
c9271bfa36 | ||
|
|
fa162c818b | ||
|
|
ff976e3ec2 | ||
|
|
17c5651305 | ||
|
|
7c7b049ba1 | ||
|
|
0823fe8b3d | ||
|
|
e787fd0fb5 | ||
|
|
650497bff4 | ||
|
|
2f25bd30b0 | ||
|
|
d58157a450 | ||
|
|
9d049bd041 | ||
|
|
988222b711 | ||
|
|
f42bd3036f | ||
|
|
297239fb5c | ||
|
|
dbd46d44aa | ||
|
|
254f4d6e92 | ||
|
|
e48719fa44 | ||
|
|
348e5a4e19 | ||
|
|
8d28972323 | ||
|
|
d74bd0a39b | ||
|
|
07307a6d8f | ||
|
|
151fb6e58d | ||
|
|
888ab49e44 | ||
|
|
24dad37da7 | ||
|
|
eb6a41556d | ||
|
|
5534cc4457 | ||
|
|
dde90fb5b7 | ||
|
|
efb2f749aa | ||
|
|
fbee977166 | ||
|
|
9f012b8ac8 | ||
|
|
9c3a157a84 | ||
|
|
b7f632077c | ||
|
|
bfab242344 | ||
|
|
6e54a96730 | ||
|
|
69d35a749f | ||
|
|
4745702909 | ||
|
|
e94801ee02 | ||
|
|
cc57fbdcd5 | ||
|
|
674097f672 | ||
|
|
472561c1b8 | ||
|
|
d345be2114 | ||
|
|
c505dfaa11 | ||
|
|
1574d5ab4c | ||
|
|
0a24f497cc | ||
|
|
9e629780ad | ||
|
|
98a842655a | ||
|
|
53943878c1 | ||
|
|
34360c1603 | ||
|
|
356448bb70 | ||
|
|
103cd641a7 | ||
|
|
d7fb0b3021 | ||
|
|
7bf79ec645 | ||
|
|
dd0e904432 | ||
|
|
561739ba8b | ||
|
|
b2596c0580 | ||
|
|
b1456b4fda | ||
|
|
923cf9b2bb | ||
|
|
273917060b | ||
|
|
7ba2046d14 | ||
|
|
be145c12a3 | ||
|
|
759e796fdd | ||
|
|
9121beaf8d | ||
|
|
89472dfc54 | ||
|
|
eb739195ea | ||
|
|
2da0bc9535 | ||
|
|
7255a162e9 | ||
|
|
a479506dcf | ||
|
|
cf62e85172 | ||
|
|
c0ea7acd28 | ||
|
|
7923db38c8 | ||
|
|
bf9937619e | ||
|
|
e5fe99eda9 | ||
|
|
eded375cf6 | ||
|
|
1b619a7a36 | ||
|
|
5d79e475d1 | ||
|
|
cb2b9dd3a2 | ||
|
|
04f819b331 | ||
|
|
5807ea001a | ||
|
|
28d92dc68b | ||
|
|
91a221529f | ||
|
|
844af0d93f | ||
|
|
6912d74d71 | ||
|
|
f1a6c0fcee | ||
|
|
edad3ab28c | ||
|
|
fb7e086770 | ||
|
|
6446f1d1bc | ||
|
|
01f391dea3 | ||
|
|
5b635abb38 | ||
|
|
54c52b230a | ||
|
|
40eb51e5eb | ||
|
|
546c4f36f0 | ||
|
|
2911960482 | ||
|
|
265e19def8 | ||
|
|
2bc88768b6 | ||
|
|
32f7923652 | ||
|
|
e379f05aca | ||
|
|
a7bab660e9 | ||
|
|
1bcb85968b | ||
|
|
4adf13539a | ||
|
|
8b47c5633a | ||
|
|
cb1e3f1b76 | ||
|
|
92ef89d5d2 | ||
|
|
b8fd9d6c45 | ||
|
|
0c17ca115e | ||
|
|
505a840574 | ||
|
|
56d742c1d2 | ||
|
|
28c66fa689 | ||
|
|
ceea1339d0 | ||
|
|
8aea50fd2b | ||
|
|
166e1f40fe | ||
|
|
415dcafee3 | ||
|
|
0399a6eb3c | ||
|
|
ac70da5b38 | ||
|
|
5ad20f6b4e | ||
|
|
283aa92579 | ||
|
|
a24cbbcc93 | ||
|
|
17b70b47ce | ||
|
|
295912fbb3 | ||
|
|
859adf966a | ||
|
|
cf404f980d | ||
|
|
6979abe96a | ||
|
|
c685cbd640 | ||
|
|
4934d78cea | ||
|
|
c6716e1b1a | ||
|
|
cc1d77ea32 | ||
|
|
3e7ac0d87d | ||
|
|
a6952251de | ||
|
|
d10bf29493 | ||
|
|
9364aa3536 | ||
|
|
a63135045e | ||
|
|
bc441116e2 | ||
|
|
025ef61de1 | ||
|
|
e4c7ffe201 | ||
|
|
0264fbebcd | ||
|
|
7dd61c89fc | ||
|
|
a62645f0b7 | ||
|
|
88079a3ee4 | ||
|
|
c7fbe591ba | ||
|
|
b1139a3911 | ||
|
|
f03fa29836 | ||
|
|
04a6365349 | ||
|
|
4d3c16fabc | ||
|
|
9d5896b62c | ||
|
|
23a1033787 | ||
|
|
c35cb6cf45 | ||
|
|
e0708e519c | ||
|
|
0935dda00b | ||
|
|
1119f774f9 | ||
|
|
7dcf98c395 | ||
|
|
e5174fdb08 | ||
|
|
0594668387 | ||
|
|
ebbb1f82fe | ||
|
|
dc8061a0a4 | ||
|
|
6c1c17445a | ||
|
|
56d366116a | ||
|
|
1ed4d271c7 | ||
|
|
bd1098f373 | ||
|
|
8ed9a33bcd | ||
|
|
17f37b48e7 | ||
|
|
5ea8bec0cf | ||
|
|
2f94fa4e2f | ||
|
|
6832b32741 | ||
|
|
c06b3db71e | ||
|
|
ebbaec762d | ||
|
|
ebc2246901 | ||
|
|
df76d83d4b | ||
|
|
7b15677426 | ||
|
|
297201a75f | ||
|
|
0c0cdfdee1 | ||
|
|
579194dd35 | ||
|
|
fa59bb06b1 | ||
|
|
38d4c5dd52 | ||
|
|
ce5658a205 | ||
|
|
f9e68a6854 | ||
|
|
f4bd4fe69b | ||
|
|
26d5c56cd0 | ||
|
|
9fc73468a2 | ||
|
|
37317136ed | ||
|
|
4ce7b0cadf | ||
|
|
29e8592582 | ||
|
|
a088c2455e | ||
|
|
dab16fb80a | ||
|
|
c9f918784c | ||
|
|
2876076cea | ||
|
|
08c53160a4 | ||
|
|
6cabacbcc0 | ||
|
|
d3d153b9c0 | ||
|
|
b9afcec3cf | ||
|
|
fd73afb66b | ||
|
|
64fb980ae4 | ||
|
|
c58f85c6ac | ||
|
|
94131a24ad | ||
|
|
30cc2a5e9c | ||
|
|
6eb3e814fe | ||
|
|
e029978937 | ||
|
|
85d637e62e | ||
|
|
dbdd7f3705 | ||
|
|
7b7eba1c7c | ||
|
|
0daf33c36f | ||
|
|
68a8d7d212 | ||
|
|
9f943aa2d0 | ||
|
|
6b9a2ed5d2 | ||
|
|
dcb332b06f | ||
|
|
b9f2cc4300 | ||
|
|
48716f1c0e | ||
|
|
33c8c28899 | ||
|
|
eb5968bdd2 | ||
|
|
16768cf10c | ||
|
|
789828e8b8 | ||
|
|
4b57ee4e64 | ||
|
|
b61c03630d | ||
|
|
b3a4b7158e | ||
|
|
28bb2e2adf | ||
|
|
c575385ba3 | ||
|
|
45ef5ee000 | ||
|
|
5552bea525 | ||
|
|
4f22704922 | ||
|
|
e0660a699b | ||
|
|
4b5827cb3e | ||
|
|
08ade0eb6f | ||
|
|
e4f89f0486 | ||
|
|
b2709aef6f | ||
|
|
3bf385b317 | ||
|
|
bebfdfa267 | ||
|
|
e3e7d12ff8 |
4
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
patreon: swordfish90
|
||||
custom: ['https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=flscogna%40gmail.com&item_name=Support+CRT¤cy_code=EUR&source=url']
|
||||
98
.github/workflows/appimage.yml
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
name: "ci"
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: "**"
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
appimage:
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo add-apt-repository -y ppa:beineri/opt-qt-5.15.2-bionic
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y \
|
||||
build-essential make wget libgl1-mesa-dev \
|
||||
qt515declarative qt515graphicaleffects \
|
||||
qt515quickcontrols qt515quickcontrols2
|
||||
|
||||
- name: Download QT appimage builder
|
||||
run: |
|
||||
wget -c -O linuxdeployqt.AppImage \
|
||||
https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage
|
||||
chmod a+x linuxdeployqt.AppImage
|
||||
|
||||
- name: Build project
|
||||
run: |
|
||||
source /opt/qt*/bin/qt*-env.sh && \
|
||||
qmake -v && \
|
||||
qmake CONFIG+=release PREFIX=/usr && \
|
||||
make -j$(nproc)
|
||||
|
||||
- name: Install to appdir
|
||||
run: |
|
||||
source /opt/qt*/bin/qt*-env.sh && \
|
||||
make INSTALL_ROOT=appdir -j$(nproc) install
|
||||
|
||||
- name: Extract version number
|
||||
run: |
|
||||
# Extract version for linuxdeployqt to name the file. Use the tag as
|
||||
# release name but remove prefix.
|
||||
echo "VERSION=$(echo '${{ github.ref }}' | sed 's;.*/;;')" >> $GITHUB_ENV
|
||||
|
||||
- name: Build appimage directory
|
||||
run: |
|
||||
mkdir -p \
|
||||
appdir/usr/bin \
|
||||
appdir/usr/lib \
|
||||
appdir/usr/share/applications \
|
||||
appdir/usr/share/metainfo \
|
||||
appdir/usr/share/icons/hicolor/128x128/apps
|
||||
|
||||
cp cool-retro-term appdir/usr/bin/
|
||||
cp cool-retro-term.desktop appdir/usr/share/applications/
|
||||
cp packaging/appdata/cool-retro-term.appdata.xml appdir/usr/share/metainfo/
|
||||
cp app/icons/128x128/cool-retro-term.png appdir/usr/share/icons/hicolor/128x128/apps/
|
||||
cp -r ./app/qml appdir/usr/
|
||||
# Workaround for https://github.com/probonopd/linuxdeployqt/issues/78
|
||||
cp -r ./qmltermwidget/QMLTermWidget appdir/usr/qml/
|
||||
|
||||
find appdir | sort
|
||||
|
||||
- name: Build appimage
|
||||
run: |
|
||||
source /opt/qt*/bin/qt*-env.sh && \
|
||||
./linuxdeployqt.AppImage appdir/usr/share/applications/cool-retro-term.desktop \
|
||||
-verbose=1 -appimage \
|
||||
-qmldir=./app/qml/ \
|
||||
-qmldir=./qmltermwidget/
|
||||
env:
|
||||
# Unset environment variables
|
||||
QTDIR:
|
||||
QT_PLUGIN_PATH:
|
||||
LD_LIBRARY_PATH:
|
||||
|
||||
- name: Upload release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
body: appimage release
|
||||
files: ./**/Cool_Retro_Term-*-x86_64.AppImage
|
||||
|
||||
- name: Clean up
|
||||
if: always()
|
||||
run: |
|
||||
find appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq
|
||||
make clean
|
||||
rm -rf appdir
|
||||
2
.gitignore
vendored
@@ -18,6 +18,7 @@
|
||||
*.pro.user.*
|
||||
*.moc
|
||||
moc_*.cpp
|
||||
moc_*.h
|
||||
qrc_*.cpp
|
||||
ui_*.h
|
||||
Makefile*
|
||||
@@ -42,6 +43,7 @@ Makefile*
|
||||
# Excludes compiled files
|
||||
imports
|
||||
cool-retro-term
|
||||
build
|
||||
|
||||
# Mac OSX
|
||||
|
||||
|
||||
7
.gitmodules
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
[submodule "qmltermwidget"]
|
||||
path = qmltermwidget
|
||||
url = https://github.com/Swordfish90/qmltermwidget
|
||||
branch = unstable
|
||||
[submodule "KDSingleApplication"]
|
||||
path = KDSingleApplication
|
||||
url = https://github.com/KDAB/KDSingleApplication.git
|
||||
37
.travis.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
language: c++
|
||||
|
||||
install:
|
||||
- sudo add-apt-repository -y ppa:beineri/opt-qt58-trusty
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get -y install build-essential qt58declarative qt58graphicaleffects qt58quickcontrols libgl1-mesa-dev
|
||||
- source /opt/qt*/bin/qt*-env.sh
|
||||
|
||||
script:
|
||||
- qmake CONFIG+=release PREFIX=/usr
|
||||
- make -j$(nproc)
|
||||
- mkdir -p appdir/usr/share/metainfo appdir/usr/bin
|
||||
- cp packaging/appdata/cool-retro-term.appdata.xml appdir/usr/share/metainfo/
|
||||
- cp cool-retro-term appdir/usr/bin/
|
||||
- cp ./cool-retro-term.desktop appdir/
|
||||
- cp ./app/icons/128x128/cool-retro-term.png appdir/
|
||||
- cp -r ./app/qml appdir/usr/
|
||||
- cp -r ./qmltermwidget/QMLTermWidget appdir/usr/qml/ # Workaround for https://github.com/probonopd/linuxdeployqt/issues/78
|
||||
- wget -c https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage
|
||||
- chmod a+x linuxdeployqt-*.AppImage
|
||||
- unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH
|
||||
- export VERSION=$(git rev-parse --short HEAD) # linuxdeployqt uses this for naming the file
|
||||
- ./linuxdeployqt-*.AppImage appdir/usr/bin/cool-retro-term -qmldir=./app/qml/ -qmldir=./qmltermwidget/ # -verbose=3 2>&1 | grep "path:" -C 3
|
||||
- ./linuxdeployqt-*.AppImage appdir/usr/bin/cool-retro-term -qmldir=./app/qml/ -qmldir=./qmltermwidget/ -verbose=2 -appimage
|
||||
|
||||
after_success:
|
||||
- find appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq
|
||||
- # curl --upload-file Cool*.AppImage https://transfer.sh/Cool_Retro_Term-git.$(git rev-parse --short HEAD)-x86_64.AppImage
|
||||
- wget -c https://github.com/probonopd/uploadtool/raw/master/upload.sh
|
||||
- bash upload.sh Cool*.AppImage*
|
||||
|
||||
branches:
|
||||
except:
|
||||
- # Do not build tags that we create when we upload to GitHub Releases
|
||||
- /^(?i:continuous)/
|
||||
1
KDSingleApplication
Submodule
115
README.md
@@ -1,109 +1,30 @@
|
||||
#cool-retro-term
|
||||
# cool-retro-term
|
||||
|
||||
##Description
|
||||
|> Default Amber|C:\ IBM DOS|$ Default Green|
|
||||
|---|---|---|
|
||||
||||
|
||||
|
||||
## Description
|
||||
cool-retro-term is a terminal emulator which mimics the look and feel of the old cathode tube screens.
|
||||
It has been designed to be eye-candy, customizable, and reasonably lightweight.
|
||||
|
||||
It uses the Konsole engine which is powerful and mature.
|
||||
It uses the QML port of qtermwidget (Konsole): https://github.com/Swordfish90/qmltermwidget.
|
||||
|
||||
This terminal emulator requires Qt 5.2 or higher to run.
|
||||
This terminal emulator works under Linux and macOS and requires Qt5. It's suggested that you stick to the latest LTS version.
|
||||
|
||||
##Screenshots
|
||||

|
||||

|
||||

|
||||
Settings such as colors, fonts, and effects can be accessed via context menu.
|
||||
|
||||
##Get cool-retro-term
|
||||
You can either build cool-retro-term yourself (see below) or walk the easy way and install one of these packages:
|
||||
## Screenshots
|
||||

|
||||

|
||||

|
||||
|
||||
Users of Fedora and openSUSE can grab a package from [Open Build Service](http://software.opensuse.org/package/cool-retro-term).
|
||||
## Install
|
||||
|
||||
Arch users can install this [package](https://aur.archlinux.org/packages/cool-retro-term-git/) directly via the [AUR](https://aur.archlinux.org):
|
||||
If you want to get a hold of the latest version, just go to the Releases page and grab the latest AppImage (Linux) or dmg (macOS).
|
||||
|
||||
yaourt -S aur/cool-retro-term-git
|
||||
Alternatively, most distributions such as Ubuntu, Fedora or Arch already package cool-retro-term in their official repositories.
|
||||
|
||||
##Build instructions (Linux)
|
||||
## Building
|
||||
|
||||
##Dependencies
|
||||
Make sure to install these first.
|
||||
|
||||
---
|
||||
|
||||
**Ubuntu 14.04**
|
||||
|
||||
sudo apt-get install build-essential qmlscene qt5-qmake qt5-default qtdeclarative5-dev qtdeclarative5-controls-plugin qtdeclarative5-qtquick2-plugin libqt5qml-graphicaleffects qtdeclarative5-dialogs-plugin qtdeclarative5-localstorage-plugin qtdeclarative5-window-plugin
|
||||
|
||||
---
|
||||
|
||||
**Debian Jessie**
|
||||
|
||||
sudo apt-get install build-essential qmlscene qt5-qmake qt5-default qtdeclarative5-dev qml-module-qtquick-controls qml-module-qtgraphicaleffects qml-module-qtquick-dialogs qml-module-qtquick-localstorage qml-module-qtquick-window2
|
||||
|
||||
---
|
||||
|
||||
**Fedora**
|
||||
This command should install the known fedora dependencies:
|
||||
|
||||
sudo yum -y install qt5-qtbase qt5-qtbase-devel qt5-qtdeclarative qt5-qtdeclarative-devel qt5-qtgraphicaleffects qt5-qtquickcontrols
|
||||
|
||||
or:
|
||||
|
||||
sudo dnf -y install qt5-qtbase qt5-qtbase-devel qt5-qtdeclarative qt5-qtdeclarative-devel qt5-qtgraphicaleffects qt5-qtquickcontrols
|
||||
|
||||
---
|
||||
|
||||
**Arch Linux**
|
||||
|
||||
sudo pacman -S qt5-base qt5-declarative qt5-quickcontrols qt5-graphicaleffects
|
||||
|
||||
---
|
||||
|
||||
**openSUSE**
|
||||
|
||||
Add repository with latest Qt 5 (this is only needed on openSUSE 13.1, Factory already has it):
|
||||
|
||||
sudo zypper ar http://download.opensuse.org/repositories/KDE:/Qt5/openSUSE_13.1/ KDE:Qt5
|
||||
|
||||
Install dependencies:
|
||||
|
||||
sudo zypper install libqt5-qtbase-devel libqt5-qtdeclarative-devel libqt5-qtquickcontrols libqt5-qtgraphicaleffects
|
||||
|
||||
---
|
||||
|
||||
**Anyone else**
|
||||
|
||||
Install Qt directly from here http://qt-project.org/downloads . Once done export them in you path (replace "_/opt/Qt5.3.1/5.3/gcc_64/bin_" with your correct folder):
|
||||
|
||||
export PATH=/opt/Qt5.3.1/5.3/gcc_64/bin/:$PATH
|
||||
---
|
||||
|
||||
###Compile
|
||||
Once you installed all dependencies (Qt is installed and in your path) you need to compile and run the application:
|
||||
|
||||
```bash
|
||||
# Get it from GitHub
|
||||
git clone https://github.com/Swordfish90/cool-retro-term.git
|
||||
|
||||
# Build it
|
||||
cd cool-retro-term
|
||||
|
||||
# Compile (Fedora and OpenSUSE user should use qmake-qt5 instead of qmake)
|
||||
qmake && make
|
||||
|
||||
# Have fun!
|
||||
./cool-retro-term
|
||||
```
|
||||
|
||||
##Build instructions (OSX)
|
||||
|
||||
brew install qt5
|
||||
git clone https://github.com/Swordfish90/cool-retro-term.git
|
||||
export CPPFLAGS="-I/usr/local/opt/qt5/include"
|
||||
export LDFLAGS="-L/usr/local/opt/qt5/lib"
|
||||
export PATH=/usr/local/opt/qt5/bin:$PATH
|
||||
cd cool-retro-term
|
||||
qmake && make
|
||||
open cool-retro-term.app
|
||||
|
||||
##Donations
|
||||
I made this project in my spare time because I love what I'm doing. If you are enjoying it and you want to buy me a beer click [here](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=flscogna%40gmail%2ecom&lc=IT&item_name=Filippo%20Scognamiglio¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted) .
|
||||
Check out the wiki and follow the instructions on how to build it on [Linux](https://github.com/Swordfish90/cool-retro-term/wiki/Build-Instructions-(Linux)) and [macOS](https://github.com/Swordfish90/cool-retro-term/wiki/Build-Instructions-(macOS)).
|
||||
|
||||
103
app/app.pro
@@ -1,13 +1,96 @@
|
||||
QT += qml quick widgets
|
||||
TARGET = cool-retro-term
|
||||
QT += qml quick widgets sql quickcontrols2
|
||||
TARGET = cool-retro-term
|
||||
|
||||
# TODO: When migrating to CMake, use KDSingleApplication's CMakeLists.txt instead of these manual sources.
|
||||
INCLUDEPATH += $$PWD/../KDSingleApplication/src
|
||||
HEADERS += \
|
||||
$$PWD/../KDSingleApplication/src/kdsingleapplication.h \
|
||||
$$PWD/../KDSingleApplication/src/kdsingleapplication_lib.h \
|
||||
$$PWD/../KDSingleApplication/src/kdsingleapplication_localsocket_p.h
|
||||
SOURCES += \
|
||||
$$PWD/../KDSingleApplication/src/kdsingleapplication.cpp \
|
||||
$$PWD/../KDSingleApplication/src/kdsingleapplication_localsocket.cpp
|
||||
DEFINES += KDSINGLEAPPLICATION_STATIC_BUILD
|
||||
|
||||
DESTDIR = $$OUT_PWD/../
|
||||
SOURCES = main.cpp
|
||||
|
||||
HEADERS += \
|
||||
fileio.h \
|
||||
fontmanager.h \
|
||||
fontlistmodel.h
|
||||
|
||||
SOURCES += main.cpp \
|
||||
fileio.cpp \
|
||||
fontmanager.cpp \
|
||||
fontlistmodel.cpp
|
||||
|
||||
macx:ICON = icons/crt.icns
|
||||
|
||||
RESOURCES += qml/resources.qrc
|
||||
|
||||
# Shader compilation (Qt Shader Baker)
|
||||
QSB_BIN = $$[QT_HOST_BINS]/qsb
|
||||
isEmpty(QSB_BIN): QSB_BIN = $$[QT_INSTALL_BINS]/qsb
|
||||
|
||||
SHADERS_DIR = $${_PRO_FILE_PWD_}/shaders
|
||||
SHADERS += $$files($$SHADERS_DIR/*.frag) $$files($$SHADERS_DIR/*.vert)
|
||||
SHADERS -= $$SHADERS_DIR/terminal_dynamic.frag
|
||||
SHADERS -= $$SHADERS_DIR/terminal_static.frag
|
||||
SHADERS -= $$SHADERS_DIR/passthrough.vert
|
||||
|
||||
qsb.input = SHADERS
|
||||
qsb.output = ../../app/shaders/${QMAKE_FILE_NAME}.qsb
|
||||
qsb.commands = $$QSB_BIN --glsl \"100 es,120,150\" --hlsl 50 --msl 12 --qt6 -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN}
|
||||
qsb.clean = $$qsb.output
|
||||
qsb.name = qsb ${QMAKE_FILE_IN}
|
||||
qsb.variable_out = QSB_FILES
|
||||
QMAKE_EXTRA_COMPILERS += qsb
|
||||
PRE_TARGETDEPS += $$QSB_FILES
|
||||
OTHER_FILES += $$SHADERS $$QSB_FILES
|
||||
|
||||
DYNAMIC_SHADER = $$SHADERS_DIR/terminal_dynamic.frag
|
||||
STATIC_SHADER = $$SHADERS_DIR/terminal_static.frag
|
||||
|
||||
RASTER_MODES = 0 1 2 3 4
|
||||
BINARY_FLAGS = 0 1
|
||||
VARIANT_SHADER_DIR = $$relative_path($$PWD/shaders, $$OUT_PWD)
|
||||
VARIANT_OUTPUTS =
|
||||
|
||||
for(raster_mode, RASTER_MODES) {
|
||||
for(burn_in, BINARY_FLAGS) {
|
||||
for(display_frame, BINARY_FLAGS) {
|
||||
for(chroma_on, BINARY_FLAGS) {
|
||||
dynamic_variant = terminal_dynamic_raster$${raster_mode}_burn$${burn_in}_frame$${display_frame}_chroma$${chroma_on}
|
||||
dynamic_output = $${VARIANT_SHADER_DIR}/$${dynamic_variant}.frag.qsb
|
||||
dynamic_target = shader_variant_$${dynamic_variant}
|
||||
$${dynamic_target}.target = $${dynamic_output}
|
||||
$${dynamic_target}.depends = $$DYNAMIC_SHADER
|
||||
$${dynamic_target}.commands = $$QSB_BIN --glsl \"100 es,120,150\" --hlsl 50 --msl 12 --qt6 -DCRT_RASTER_MODE=$${raster_mode} -DCRT_BURN_IN=$${burn_in} -DCRT_DISPLAY_FRAME=$${display_frame} -DCRT_CHROMA=$${chroma_on} -o $${dynamic_output} $$DYNAMIC_SHADER
|
||||
QMAKE_EXTRA_TARGETS += $${dynamic_target}
|
||||
VARIANT_OUTPUTS += $${dynamic_output}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(rgb_shift, BINARY_FLAGS) {
|
||||
for(bloom_on, BINARY_FLAGS) {
|
||||
for(curve_on, BINARY_FLAGS) {
|
||||
for(shine_on, BINARY_FLAGS) {
|
||||
static_variant = terminal_static_rgb$${rgb_shift}_bloom$${bloom_on}_curve$${curve_on}_shine$${shine_on}
|
||||
static_output = $${VARIANT_SHADER_DIR}/$${static_variant}.frag.qsb
|
||||
static_target = shader_variant_$${static_variant}
|
||||
$${static_target}.target = $${static_output}
|
||||
$${static_target}.depends = $$STATIC_SHADER
|
||||
$${static_target}.commands = $$QSB_BIN --glsl \"100 es,120,150\" --hlsl 50 --msl 12 --qt6 -DCRT_RGB_SHIFT=$${rgb_shift} -DCRT_BLOOM=$${bloom_on} -DCRT_CURVATURE=$${curve_on} -DCRT_FRAME_SHININESS=$${shine_on} -o $${static_output} $$STATIC_SHADER
|
||||
QMAKE_EXTRA_TARGETS += $${static_target}
|
||||
VARIANT_OUTPUTS += $${static_output}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PRE_TARGETDEPS += $${VARIANT_OUTPUTS}
|
||||
|
||||
#########################################
|
||||
## INTALLS
|
||||
#########################################
|
||||
@@ -15,3 +98,17 @@ RESOURCES += qml/resources.qrc
|
||||
target.path += /usr/bin/
|
||||
|
||||
INSTALLS += target
|
||||
|
||||
# Install icons
|
||||
unix {
|
||||
icon32.files = icons/32x32/cool-retro-term.png
|
||||
icon32.path = /usr/share/icons/hicolor/32x32/apps
|
||||
icon64.files = icons/64x64/cool-retro-term.png
|
||||
icon64.path = /usr/share/icons/hicolor/64x64/apps
|
||||
icon128.files = icons/128x128/cool-retro-term.png
|
||||
icon128.path = /usr/share/icons/hicolor/128x128/apps
|
||||
icon256.files = icons/256x256/cool-retro-term.png
|
||||
icon256.path = /usr/share/icons/hicolor/256x256/apps
|
||||
|
||||
INSTALLS += icon32 icon64 icon128 icon256
|
||||
}
|
||||
|
||||
37
app/fileio.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "fileio.h"
|
||||
|
||||
FileIO::FileIO()
|
||||
{
|
||||
}
|
||||
|
||||
bool FileIO::write(const QString& sourceUrl, const QString& data) {
|
||||
if (sourceUrl.isEmpty())
|
||||
return false;
|
||||
|
||||
QUrl url(sourceUrl);
|
||||
QFile file(url.toLocalFile());
|
||||
if (!file.open(QFile::WriteOnly | QFile::Truncate))
|
||||
return false;
|
||||
|
||||
QTextStream out(&file);
|
||||
out << data;
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
QString FileIO::read(const QString& sourceUrl) {
|
||||
if (sourceUrl.isEmpty())
|
||||
return "";
|
||||
|
||||
QUrl url(sourceUrl);
|
||||
QFile file(url.toLocalFile());
|
||||
if (!file.open(QFile::ReadOnly))
|
||||
return "";
|
||||
|
||||
QTextStream in(&file);
|
||||
QString result = in.readAll();
|
||||
|
||||
file.close();
|
||||
|
||||
return result;
|
||||
}
|
||||
21
app/fileio.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef FILEIO_H
|
||||
#define FILEIO_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QUrl>
|
||||
|
||||
class FileIO : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FileIO();
|
||||
|
||||
public slots:
|
||||
bool write(const QString& sourceUrl, const QString& data);
|
||||
QString read(const QString& sourceUrl);
|
||||
};
|
||||
|
||||
#endif // FILEIO_H
|
||||
94
app/fontlistmodel.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "fontlistmodel.h"
|
||||
|
||||
FontListModel::FontListModel(QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int FontListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return m_fonts.size();
|
||||
}
|
||||
|
||||
QVariant FontListModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() < 0 || index.row() >= m_fonts.size()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
const FontEntry &font = m_fonts.at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case NameRole:
|
||||
return font.name;
|
||||
case TextRole:
|
||||
return font.text;
|
||||
case SourceRole:
|
||||
return font.source;
|
||||
case BaseWidthRole:
|
||||
return font.baseWidth;
|
||||
case PixelSizeRole:
|
||||
return font.pixelSize;
|
||||
case LowResolutionRole:
|
||||
return font.lowResolutionFont;
|
||||
case IsSystemRole:
|
||||
return font.isSystemFont;
|
||||
case FamilyRole:
|
||||
return font.family;
|
||||
case FallbackNameRole:
|
||||
return font.fallbackName;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> FontListModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[NameRole] = "name";
|
||||
roles[TextRole] = "text";
|
||||
roles[SourceRole] = "source";
|
||||
roles[BaseWidthRole] = "baseWidth";
|
||||
roles[PixelSizeRole] = "pixelSize";
|
||||
roles[LowResolutionRole] = "lowResolutionFont";
|
||||
roles[IsSystemRole] = "isSystemFont";
|
||||
roles[FamilyRole] = "family";
|
||||
roles[FallbackNameRole] = "fallbackName";
|
||||
return roles;
|
||||
}
|
||||
|
||||
void FontListModel::setFonts(const QVector<FontEntry> &fonts)
|
||||
{
|
||||
beginResetModel();
|
||||
m_fonts = fonts;
|
||||
endResetModel();
|
||||
emit countChanged();
|
||||
}
|
||||
|
||||
const QVector<FontEntry> &FontListModel::fonts() const
|
||||
{
|
||||
return m_fonts;
|
||||
}
|
||||
|
||||
QVariantMap FontListModel::get(int index) const
|
||||
{
|
||||
QVariantMap map;
|
||||
if (index < 0 || index >= m_fonts.size()) {
|
||||
return map;
|
||||
}
|
||||
|
||||
const FontEntry &font = m_fonts.at(index);
|
||||
map.insert("name", font.name);
|
||||
map.insert("text", font.text);
|
||||
map.insert("source", font.source);
|
||||
map.insert("baseWidth", font.baseWidth);
|
||||
map.insert("pixelSize", font.pixelSize);
|
||||
map.insert("lowResolutionFont", font.lowResolutionFont);
|
||||
map.insert("isSystemFont", font.isSystemFont);
|
||||
map.insert("family", font.family);
|
||||
map.insert("fallbackName", font.fallbackName);
|
||||
return map;
|
||||
}
|
||||
59
app/fontlistmodel.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef FONTLISTMODEL_H
|
||||
#define FONTLISTMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QVector>
|
||||
#include <QVariant>
|
||||
#include <QVariantMap>
|
||||
#include <QString>
|
||||
|
||||
struct FontEntry
|
||||
{
|
||||
QString name;
|
||||
QString text;
|
||||
QString source;
|
||||
qreal baseWidth = 1.0;
|
||||
int pixelSize = 0;
|
||||
bool lowResolutionFont = false;
|
||||
bool isSystemFont = false;
|
||||
QString family;
|
||||
QString fallbackName;
|
||||
};
|
||||
|
||||
class FontListModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||
|
||||
public:
|
||||
explicit FontListModel(QObject *parent = nullptr);
|
||||
|
||||
enum Roles {
|
||||
NameRole = Qt::UserRole + 1,
|
||||
TextRole,
|
||||
SourceRole,
|
||||
BaseWidthRole,
|
||||
PixelSizeRole,
|
||||
LowResolutionRole,
|
||||
IsSystemRole,
|
||||
FamilyRole,
|
||||
FallbackNameRole
|
||||
};
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
void setFonts(const QVector<FontEntry> &fonts);
|
||||
const QVector<FontEntry> &fonts() const;
|
||||
|
||||
Q_INVOKABLE QVariantMap get(int index) const;
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
|
||||
private:
|
||||
QVector<FontEntry> m_fonts;
|
||||
};
|
||||
|
||||
#endif // FONTLISTMODEL_H
|
||||
584
app/fontmanager.cpp
Normal file
@@ -0,0 +1,584 @@
|
||||
#include "fontmanager.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QFontDatabase>
|
||||
#include <QFontMetricsF>
|
||||
#include <QtGlobal>
|
||||
#include <QtMath>
|
||||
|
||||
namespace {
|
||||
constexpr int kModernRasterization = 4;
|
||||
constexpr int kBaseFontPixelHeight = 32;
|
||||
constexpr int kSystemFontPixelSize = 32;
|
||||
}
|
||||
|
||||
FontManager::FontManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_fontListModel(this)
|
||||
, m_filteredFontListModel(this)
|
||||
{
|
||||
populateBundledFonts();
|
||||
populateSystemFonts();
|
||||
m_fontListModel.setFonts(m_allFonts);
|
||||
updateFilteredFonts();
|
||||
updateComputedFont();
|
||||
}
|
||||
|
||||
QStringList FontManager::retrieveMonospaceFonts()
|
||||
{
|
||||
QStringList result;
|
||||
|
||||
QFontDatabase fontDatabase;
|
||||
const QStringList fontFamilies = fontDatabase.families();
|
||||
|
||||
for (const QString &fontFamily : fontFamilies) {
|
||||
QFont font(fontFamily);
|
||||
if (fontDatabase.isFixedPitch(font.family())) {
|
||||
result.append(fontFamily);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void FontManager::refresh()
|
||||
{
|
||||
updateFilteredFonts();
|
||||
updateComputedFont();
|
||||
}
|
||||
|
||||
FontListModel *FontManager::fontList()
|
||||
{
|
||||
return &m_fontListModel;
|
||||
}
|
||||
|
||||
FontListModel *FontManager::filteredFontList()
|
||||
{
|
||||
return &m_filteredFontListModel;
|
||||
}
|
||||
|
||||
int FontManager::fontSource() const
|
||||
{
|
||||
return m_fontSource;
|
||||
}
|
||||
|
||||
void FontManager::setFontSource(int fontSource)
|
||||
{
|
||||
if (m_fontSource == fontSource) {
|
||||
return;
|
||||
}
|
||||
m_fontSource = fontSource;
|
||||
emit fontSourceChanged();
|
||||
updateFilteredFonts();
|
||||
updateComputedFont();
|
||||
}
|
||||
|
||||
int FontManager::rasterization() const
|
||||
{
|
||||
return m_rasterization;
|
||||
}
|
||||
|
||||
void FontManager::setRasterization(int rasterization)
|
||||
{
|
||||
if (m_rasterization == rasterization) {
|
||||
return;
|
||||
}
|
||||
m_rasterization = rasterization;
|
||||
emit rasterizationChanged();
|
||||
updateFilteredFonts();
|
||||
updateComputedFont();
|
||||
}
|
||||
|
||||
QString FontManager::fontName() const
|
||||
{
|
||||
return m_fontName;
|
||||
}
|
||||
|
||||
void FontManager::setFontName(const QString &fontName)
|
||||
{
|
||||
if (m_fontName == fontName) {
|
||||
return;
|
||||
}
|
||||
m_fontName = fontName;
|
||||
emit fontNameChanged();
|
||||
updateFilteredFonts();
|
||||
updateComputedFont();
|
||||
}
|
||||
|
||||
qreal FontManager::fontScaling() const
|
||||
{
|
||||
return m_fontScaling;
|
||||
}
|
||||
|
||||
void FontManager::setFontScaling(qreal fontScaling)
|
||||
{
|
||||
if (qFuzzyCompare(m_fontScaling, fontScaling)) {
|
||||
return;
|
||||
}
|
||||
m_fontScaling = fontScaling;
|
||||
emit fontScalingChanged();
|
||||
updateComputedFont();
|
||||
}
|
||||
|
||||
qreal FontManager::fontWidth() const
|
||||
{
|
||||
return m_fontWidth;
|
||||
}
|
||||
|
||||
void FontManager::setFontWidth(qreal fontWidth)
|
||||
{
|
||||
if (qFuzzyCompare(m_fontWidth, fontWidth)) {
|
||||
return;
|
||||
}
|
||||
m_fontWidth = fontWidth;
|
||||
emit fontWidthChanged();
|
||||
updateComputedFont();
|
||||
}
|
||||
|
||||
qreal FontManager::lineSpacing() const
|
||||
{
|
||||
return m_lineSpacing;
|
||||
}
|
||||
|
||||
void FontManager::setLineSpacing(qreal lineSpacing)
|
||||
{
|
||||
if (qFuzzyCompare(m_lineSpacing, lineSpacing)) {
|
||||
return;
|
||||
}
|
||||
m_lineSpacing = lineSpacing;
|
||||
emit lineSpacingChanged();
|
||||
updateComputedFont();
|
||||
}
|
||||
|
||||
qreal FontManager::baseFontScaling() const
|
||||
{
|
||||
return m_baseFontScaling;
|
||||
}
|
||||
|
||||
void FontManager::setBaseFontScaling(qreal baseFontScaling)
|
||||
{
|
||||
if (qFuzzyCompare(m_baseFontScaling, baseFontScaling)) {
|
||||
return;
|
||||
}
|
||||
m_baseFontScaling = baseFontScaling;
|
||||
emit baseFontScalingChanged();
|
||||
updateComputedFont();
|
||||
}
|
||||
|
||||
bool FontManager::lowResolutionFont() const
|
||||
{
|
||||
return m_lowResolutionFont;
|
||||
}
|
||||
|
||||
void FontManager::setFontSubstitutions(const QString &family, const QStringList &substitutes)
|
||||
{
|
||||
if (family.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFont::removeSubstitutions(family);
|
||||
|
||||
if (substitutes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFont::insertSubstitutions(family, substitutes);
|
||||
}
|
||||
|
||||
void FontManager::removeFontSubstitution(const QString &family)
|
||||
{
|
||||
if (family.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFont::removeSubstitutions(family);
|
||||
}
|
||||
|
||||
void FontManager::populateBundledFonts()
|
||||
{
|
||||
m_allFonts.clear();
|
||||
|
||||
addBundledFont(
|
||||
"TERMINESS_SCALED",
|
||||
"Terminess",
|
||||
":/fonts/terminus/TerminessNerdFontMono-Regular.ttf",
|
||||
1.0,
|
||||
12,
|
||||
true);
|
||||
addBundledFont(
|
||||
"BIGBLUE_TERMINAL_SCALED",
|
||||
"BigBlue Terminal",
|
||||
":/fonts/bigblue-terminal/BigBlueTerm437NerdFontMono-Regular.ttf",
|
||||
1.0,
|
||||
12,
|
||||
true);
|
||||
addBundledFont(
|
||||
"EXCELSIOR_SCALED",
|
||||
"Fixedsys Excelsior",
|
||||
":/fonts/fixedsys-excelsior/FSEX301-L2.ttf",
|
||||
1.0,
|
||||
16,
|
||||
true,
|
||||
"UNSCII_16_SCALED");
|
||||
addBundledFont(
|
||||
"GREYBEARD_SCALED",
|
||||
"Greybeard",
|
||||
":/fonts/greybeard/Greybeard-16px.ttf",
|
||||
1.0,
|
||||
16,
|
||||
true,
|
||||
"UNSCII_16_SCALED");
|
||||
addBundledFont(
|
||||
"COMMODORE_PET_SCALED",
|
||||
"Commodore PET",
|
||||
":/fonts/pet-me/PetMe.ttf",
|
||||
0.5,
|
||||
8,
|
||||
true,
|
||||
"UNSCII_8_SCALED");
|
||||
addBundledFont(
|
||||
"GOHU_11_SCALED",
|
||||
"Gohu 11",
|
||||
":/fonts/gohu/GohuFont11NerdFontMono-Regular.ttf",
|
||||
1.0,
|
||||
11,
|
||||
true);
|
||||
addBundledFont(
|
||||
"COZETTE_SCALED",
|
||||
"Cozette",
|
||||
":/fonts/cozette/CozetteVector.ttf",
|
||||
1.0,
|
||||
13,
|
||||
true);
|
||||
addBundledFont(
|
||||
"UNSCII_8_SCALED",
|
||||
"Unscii 8",
|
||||
":/fonts/unscii/unscii-8.ttf",
|
||||
0.5,
|
||||
8,
|
||||
true,
|
||||
"UNSCII_8_SCALED");
|
||||
addBundledFont(
|
||||
"UNSCII_8_THIN_SCALED",
|
||||
"Unscii 8 Thin",
|
||||
":/fonts/unscii/unscii-8-thin.ttf",
|
||||
0.5,
|
||||
8,
|
||||
true,
|
||||
"UNSCII_8_SCALED");
|
||||
addBundledFont(
|
||||
"UNSCII_16_SCALED",
|
||||
"Unscii 16",
|
||||
":/fonts/unscii/unscii-16-full.ttf",
|
||||
1.0,
|
||||
16,
|
||||
true,
|
||||
"UNSCII_16_SCALED");
|
||||
addBundledFont(
|
||||
"APPLE_II_SCALED",
|
||||
"Apple ][",
|
||||
":/fonts/apple2/PrintChar21.ttf",
|
||||
0.5,
|
||||
8,
|
||||
true,
|
||||
"UNSCII_8_SCALED");
|
||||
addBundledFont(
|
||||
"ATARI_400_SCALED",
|
||||
"Atari 400-800",
|
||||
":/fonts/atari-400-800/AtariClassic-Regular.ttf",
|
||||
0.5,
|
||||
8,
|
||||
true,
|
||||
"UNSCII_8_SCALED");
|
||||
addBundledFont(
|
||||
"COMMODORE_64_SCALED",
|
||||
"Commodore 64",
|
||||
":/fonts/pet-me/PetMe64.ttf",
|
||||
0.5,
|
||||
8,
|
||||
true,
|
||||
"UNSCII_8_SCALED");
|
||||
addBundledFont(
|
||||
"IBM_EGA_8x8",
|
||||
"IBM EGA 8x8",
|
||||
":/fonts/oldschool-pc-fonts/PxPlus_IBM_EGA_8x8.ttf",
|
||||
0.5,
|
||||
8,
|
||||
true,
|
||||
"UNSCII_8_SCALED");
|
||||
addBundledFont(
|
||||
"IBM_VGA_8x16",
|
||||
"IBM VGA 8x16",
|
||||
":/fonts/oldschool-pc-fonts/PxPlus_IBM_VGA_8x16.ttf",
|
||||
1.0,
|
||||
16,
|
||||
true,
|
||||
"UNSCII_16_SCALED");
|
||||
|
||||
addBundledFont(
|
||||
"TERMINESS",
|
||||
"Terminess",
|
||||
":/fonts/terminus/TerminessNerdFontMono-Regular.ttf",
|
||||
1.0,
|
||||
32,
|
||||
false);
|
||||
addBundledFont(
|
||||
"HACK",
|
||||
"Hack",
|
||||
":/fonts/hack/HackNerdFontMono-Regular.ttf",
|
||||
1.0,
|
||||
32,
|
||||
false);
|
||||
addBundledFont(
|
||||
"FIRA_CODE",
|
||||
"Fira Code",
|
||||
":/fonts/fira-code/FiraCodeNerdFontMono-Regular.ttf",
|
||||
1.0,
|
||||
32,
|
||||
false);
|
||||
addBundledFont(
|
||||
"IOSEVKA",
|
||||
"Iosevka",
|
||||
":/fonts/iosevka/IosevkaTermNerdFontMono-Regular.ttf",
|
||||
1.0,
|
||||
32,
|
||||
false);
|
||||
addBundledFont(
|
||||
"JETBRAINS_MONO",
|
||||
"JetBrains Mono",
|
||||
":/fonts/jetbrains-mono/JetBrainsMonoNerdFontMono-Regular.ttf",
|
||||
1.0,
|
||||
32,
|
||||
false);
|
||||
addBundledFont(
|
||||
"IBM_3278",
|
||||
"IBM 3278",
|
||||
":/fonts/ibm-3278/3270NerdFontMono-Regular.ttf",
|
||||
1.0,
|
||||
32,
|
||||
false);
|
||||
addBundledFont(
|
||||
"SOURCE_CODE_PRO",
|
||||
"Source Code Pro",
|
||||
":/fonts/source-code-pro/SauceCodeProNerdFontMono-Regular.ttf",
|
||||
1.0,
|
||||
32,
|
||||
false);
|
||||
addBundledFont(
|
||||
"DEPARTURE_MONO_SCALED",
|
||||
"Departure Mono",
|
||||
":/fonts/departure-mono/DepartureMonoNerdFontMono-Regular.otf",
|
||||
1.0,
|
||||
11,
|
||||
true);
|
||||
addBundledFont(
|
||||
"OPENDYSLEXIC",
|
||||
"OpenDyslexic",
|
||||
":/fonts/opendyslexic/OpenDyslexicMNerdFontMono-Regular.otf",
|
||||
1.0,
|
||||
32,
|
||||
false);
|
||||
}
|
||||
|
||||
void FontManager::addBundledFont(const QString &name,
|
||||
const QString &text,
|
||||
const QString &source,
|
||||
qreal baseWidth,
|
||||
int pixelSize,
|
||||
bool lowResolutionFont,
|
||||
const QString &fallbackName)
|
||||
{
|
||||
FontEntry entry;
|
||||
entry.name = name;
|
||||
entry.text = text;
|
||||
entry.source = source;
|
||||
entry.pixelSize = pixelSize;
|
||||
entry.lowResolutionFont = lowResolutionFont;
|
||||
entry.isSystemFont = false;
|
||||
entry.fallbackName = fallbackName;
|
||||
entry.family = resolveFontFamily(source);
|
||||
entry.baseWidth = lowResolutionFont
|
||||
? computeBaseWidth(entry.family, pixelSize, baseWidth)
|
||||
: baseWidth;
|
||||
m_allFonts.append(entry);
|
||||
}
|
||||
|
||||
void FontManager::populateSystemFonts()
|
||||
{
|
||||
const QStringList families = retrieveMonospaceFonts();
|
||||
for (const QString &family : families) {
|
||||
if (m_bundledFamilies.contains(family)) {
|
||||
continue;
|
||||
}
|
||||
FontEntry entry;
|
||||
entry.name = family;
|
||||
entry.text = family;
|
||||
entry.source = QString();
|
||||
entry.baseWidth = 1.0;
|
||||
entry.pixelSize = kSystemFontPixelSize;
|
||||
entry.lowResolutionFont = false;
|
||||
entry.isSystemFont = true;
|
||||
entry.family = family;
|
||||
m_allFonts.append(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void FontManager::updateFilteredFonts()
|
||||
{
|
||||
QVector<FontEntry> filtered;
|
||||
bool fontNameFound = false;
|
||||
const bool modernMode = (m_rasterization == kModernRasterization);
|
||||
|
||||
for (const FontEntry &font : m_allFonts) {
|
||||
const bool isBundled = !font.isSystemFont;
|
||||
const bool matchesSource = (m_fontSource == 0 && isBundled)
|
||||
|| (m_fontSource == 1 && font.isSystemFont);
|
||||
|
||||
if (!matchesSource) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool matchesRasterization = font.isSystemFont
|
||||
|| (modernMode == !font.lowResolutionFont);
|
||||
|
||||
if (!matchesRasterization) {
|
||||
continue;
|
||||
}
|
||||
|
||||
filtered.append(font);
|
||||
if (font.name == m_fontName) {
|
||||
fontNameFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fontNameFound && !filtered.isEmpty()) {
|
||||
if (m_fontName != filtered.first().name) {
|
||||
m_fontName = filtered.first().name;
|
||||
emit fontNameChanged();
|
||||
}
|
||||
}
|
||||
|
||||
m_filteredFontListModel.setFonts(filtered);
|
||||
emit filteredFontListChanged();
|
||||
}
|
||||
|
||||
void FontManager::updateComputedFont()
|
||||
{
|
||||
const FontEntry *font = findFontByName(m_fontName);
|
||||
if (!font) {
|
||||
const QVector<FontEntry> &filteredFonts = m_filteredFontListModel.fonts();
|
||||
if (!filteredFonts.isEmpty()) {
|
||||
font = &filteredFonts.first();
|
||||
}
|
||||
}
|
||||
|
||||
if (!font) {
|
||||
return;
|
||||
}
|
||||
|
||||
const qreal totalFontScaling = m_baseFontScaling * m_fontScaling;
|
||||
const qreal targetPixelHeight = kBaseFontPixelHeight * totalFontScaling;
|
||||
const qreal lineSpacingFactor = m_lineSpacing;
|
||||
|
||||
const int lineSpacing = qRound(targetPixelHeight * lineSpacingFactor);
|
||||
const int pixelSize = font->lowResolutionFont
|
||||
? font->pixelSize
|
||||
: static_cast<int>(targetPixelHeight);
|
||||
|
||||
const qreal nativeLineHeight = font->pixelSize + qRound(font->pixelSize * lineSpacingFactor);
|
||||
const qreal targetLineHeight = targetPixelHeight + lineSpacing;
|
||||
const qreal screenScaling = font->lowResolutionFont
|
||||
? (nativeLineHeight > 0 ? targetLineHeight / nativeLineHeight : 1.0)
|
||||
: 1.0;
|
||||
|
||||
const qreal fontWidth = font->baseWidth * m_fontWidth;
|
||||
|
||||
QString fontFamily = font->family.isEmpty() ? font->name : font->family;
|
||||
QString fallbackFontFamily;
|
||||
|
||||
if (!font->fallbackName.isEmpty() && font->fallbackName != font->name) {
|
||||
const FontEntry *fallback = findFontByName(font->fallbackName);
|
||||
if (fallback) {
|
||||
fallbackFontFamily = fallback->family.isEmpty() ? fallback->name : fallback->family;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList fallbackChain;
|
||||
if (!fallbackFontFamily.isEmpty()) {
|
||||
fallbackChain.append(fallbackFontFamily);
|
||||
}
|
||||
#if defined(Q_OS_MAC)
|
||||
fallbackChain.append(QStringLiteral("Menlo"));
|
||||
#else
|
||||
fallbackChain.append(QStringLiteral("Monospace"));
|
||||
#endif
|
||||
setFontSubstitutions(fontFamily, fallbackChain);
|
||||
|
||||
if (m_lowResolutionFont != font->lowResolutionFont) {
|
||||
m_lowResolutionFont = font->lowResolutionFont;
|
||||
emit lowResolutionFontChanged();
|
||||
}
|
||||
|
||||
emit terminalFontChanged(fontFamily,
|
||||
pixelSize,
|
||||
lineSpacing,
|
||||
screenScaling,
|
||||
fontWidth,
|
||||
fallbackFontFamily,
|
||||
font->lowResolutionFont);
|
||||
}
|
||||
|
||||
const FontEntry *FontManager::findFontByName(const QString &name) const
|
||||
{
|
||||
for (const FontEntry &font : m_allFonts) {
|
||||
if (font.name == name) {
|
||||
return &font;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString FontManager::resolveFontFamily(const QString &sourcePath)
|
||||
{
|
||||
const auto cached = m_loadedFamilies.constFind(sourcePath);
|
||||
if (cached != m_loadedFamilies.constEnd()) {
|
||||
return cached.value();
|
||||
}
|
||||
|
||||
const int fontId = QFontDatabase::addApplicationFont(sourcePath);
|
||||
QString family;
|
||||
if (fontId != -1) {
|
||||
const QStringList families = QFontDatabase::applicationFontFamilies(fontId);
|
||||
if (!families.isEmpty()) {
|
||||
family = families.first();
|
||||
}
|
||||
}
|
||||
|
||||
if (!family.isEmpty()) {
|
||||
m_bundledFamilies.insert(family);
|
||||
}
|
||||
|
||||
m_loadedFamilies.insert(sourcePath, family);
|
||||
return family;
|
||||
}
|
||||
|
||||
qreal FontManager::computeBaseWidth(const QString &family, int pixelSize, qreal fallbackWidth) const
|
||||
{
|
||||
if (family.isEmpty()) {
|
||||
return fallbackWidth;
|
||||
}
|
||||
|
||||
QFont font(family);
|
||||
font.setPixelSize(pixelSize);
|
||||
QFontMetricsF metrics(font);
|
||||
|
||||
const qreal glyphWidth = metrics.horizontalAdvance(QLatin1String("M"));
|
||||
const qreal glyphHeight = metrics.height();
|
||||
if (glyphWidth <= 0.0 || glyphHeight <= 0.0) {
|
||||
return fallbackWidth;
|
||||
}
|
||||
|
||||
const qreal targetRatio = 0.5;
|
||||
qreal computedWidth = (targetRatio * glyphHeight) / glyphWidth;
|
||||
return qBound(0.25, computedWidth, 2.0);
|
||||
}
|
||||
111
app/fontmanager.h
Normal file
@@ -0,0 +1,111 @@
|
||||
#ifndef FONTMANAGER_H
|
||||
#define FONTMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
|
||||
#include "fontlistmodel.h"
|
||||
|
||||
class FontManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(FontListModel *fontList READ fontList CONSTANT)
|
||||
Q_PROPERTY(FontListModel *filteredFontList READ filteredFontList NOTIFY filteredFontListChanged)
|
||||
Q_PROPERTY(int fontSource READ fontSource WRITE setFontSource NOTIFY fontSourceChanged)
|
||||
Q_PROPERTY(int rasterization READ rasterization WRITE setRasterization NOTIFY rasterizationChanged)
|
||||
Q_PROPERTY(QString fontName READ fontName WRITE setFontName NOTIFY fontNameChanged)
|
||||
Q_PROPERTY(qreal fontScaling READ fontScaling WRITE setFontScaling NOTIFY fontScalingChanged)
|
||||
Q_PROPERTY(qreal fontWidth READ fontWidth WRITE setFontWidth NOTIFY fontWidthChanged)
|
||||
Q_PROPERTY(qreal lineSpacing READ lineSpacing WRITE setLineSpacing NOTIFY lineSpacingChanged)
|
||||
Q_PROPERTY(qreal baseFontScaling READ baseFontScaling WRITE setBaseFontScaling NOTIFY baseFontScalingChanged)
|
||||
Q_PROPERTY(bool lowResolutionFont READ lowResolutionFont NOTIFY lowResolutionFontChanged)
|
||||
|
||||
public:
|
||||
explicit FontManager(QObject *parent = nullptr);
|
||||
|
||||
Q_INVOKABLE void refresh();
|
||||
|
||||
FontListModel *fontList();
|
||||
FontListModel *filteredFontList();
|
||||
|
||||
int fontSource() const;
|
||||
void setFontSource(int fontSource);
|
||||
|
||||
int rasterization() const;
|
||||
void setRasterization(int rasterization);
|
||||
|
||||
QString fontName() const;
|
||||
void setFontName(const QString &fontName);
|
||||
|
||||
qreal fontScaling() const;
|
||||
void setFontScaling(qreal fontScaling);
|
||||
|
||||
qreal fontWidth() const;
|
||||
void setFontWidth(qreal fontWidth);
|
||||
|
||||
qreal lineSpacing() const;
|
||||
void setLineSpacing(qreal lineSpacing);
|
||||
|
||||
qreal baseFontScaling() const;
|
||||
void setBaseFontScaling(qreal baseFontScaling);
|
||||
|
||||
bool lowResolutionFont() const;
|
||||
|
||||
signals:
|
||||
void fontSourceChanged();
|
||||
void rasterizationChanged();
|
||||
void fontNameChanged();
|
||||
void fontScalingChanged();
|
||||
void fontWidthChanged();
|
||||
void lineSpacingChanged();
|
||||
void baseFontScalingChanged();
|
||||
void lowResolutionFontChanged();
|
||||
void filteredFontListChanged();
|
||||
|
||||
void terminalFontChanged(QString fontFamily,
|
||||
int pixelSize,
|
||||
int lineSpacing,
|
||||
qreal screenScaling,
|
||||
qreal fontWidth,
|
||||
QString fallbackFontFamily,
|
||||
bool lowResolutionFont);
|
||||
|
||||
private:
|
||||
QStringList retrieveMonospaceFonts();
|
||||
void populateBundledFonts();
|
||||
void populateSystemFonts();
|
||||
void addBundledFont(const QString &name,
|
||||
const QString &text,
|
||||
const QString &source,
|
||||
qreal baseWidth,
|
||||
int pixelSize,
|
||||
bool lowResolutionFont,
|
||||
const QString &fallbackName = QString());
|
||||
void setFontSubstitutions(const QString &family, const QStringList &substitutes);
|
||||
void removeFontSubstitution(const QString &family);
|
||||
void updateFilteredFonts();
|
||||
void updateComputedFont();
|
||||
const FontEntry *findFontByName(const QString &name) const;
|
||||
QString resolveFontFamily(const QString &sourcePath);
|
||||
qreal computeBaseWidth(const QString &family, int pixelSize, qreal fallbackWidth) const;
|
||||
|
||||
FontListModel m_fontListModel;
|
||||
FontListModel m_filteredFontListModel;
|
||||
QVector<FontEntry> m_allFonts;
|
||||
|
||||
int m_fontSource = 0;
|
||||
int m_rasterization = 0;
|
||||
QString m_fontName = QStringLiteral("TERMINESS_SCALED");
|
||||
qreal m_fontScaling = 1.0;
|
||||
qreal m_fontWidth = 1.0;
|
||||
qreal m_lineSpacing = 0.1;
|
||||
qreal m_baseFontScaling = 0.75;
|
||||
bool m_lowResolutionFont = false;
|
||||
|
||||
QHash<QString, QString> m_loadedFamilies;
|
||||
QSet<QString> m_bundledFamilies;
|
||||
};
|
||||
|
||||
#endif // FONTMANAGER_H
|
||||
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
159
app/main.cpp
@@ -5,45 +5,164 @@
|
||||
#include <QStringList>
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QIcon>
|
||||
#include <QQuickStyle>
|
||||
#include <QtQml/qqml.h>
|
||||
|
||||
#include <kdsingleapplication.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <QLoggingCategory>
|
||||
|
||||
QString getNamedArgument(QStringList args, QString name) {
|
||||
#include <fileio.h>
|
||||
#include <fontlistmodel.h>
|
||||
#include <fontmanager.h>
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <QStyleFactory>
|
||||
#include <QMenu>
|
||||
#endif
|
||||
|
||||
QString getNamedArgument(QStringList args, QString name, QString defaultName)
|
||||
{
|
||||
int index = args.indexOf(name);
|
||||
return (index != -1) ? args[index + 1] : QString("");
|
||||
return (index != -1) ? args[index + 1] : QString(defaultName);
|
||||
}
|
||||
|
||||
QString getNamedArgument(QStringList args, QString name)
|
||||
{
|
||||
return getNamedArgument(args, name, "");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
setenv("QT_QPA_PLATFORMTHEME", "", 1);
|
||||
QApplication app(argc, argv);
|
||||
QQmlApplicationEngine engine;
|
||||
// Some environmental variable are necessary on certain platforms.
|
||||
// Disable Connections slot warnings
|
||||
QLoggingCategory::setFilterRules("qt.qml.connections.warning=false");
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Round);
|
||||
|
||||
// Manage command line arguments from the cpp side
|
||||
QStringList args = app.arguments();
|
||||
if (args.contains("-h") || args.contains("--help")) {
|
||||
qDebug() << "Usage: " + args.at(0) + " [--default-settings] [--workdir <dir>] [--program <prog>] [-p|--profile <prof>] [--fullscreen] [-h|--help]";
|
||||
qDebug() << " --default-settings Run cool-retro-term with the default settings";
|
||||
qDebug() << " --workdir <dir> Change working directory to 'dir'";
|
||||
qDebug() << " --program <prog> Run the 'prog' in the new terminal.";
|
||||
qDebug() << " --fullscreen Run cool-retro-term in fullscreen.";
|
||||
qDebug() << " -p|--profile <prof> Run cool-retro-term with the given profile.";
|
||||
qDebug() << " -h|--help Print this help.";
|
||||
// #if defined (Q_OS_LINUX)
|
||||
// setenv("QSG_RENDER_LOOP", "threaded", 0);
|
||||
// #endif
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
// This allows UTF-8 characters usage in OSX.
|
||||
setenv("LC_CTYPE", "UTF-8", 1);
|
||||
|
||||
// Ensure key repeat works for letter keys (disable macOS press-and-hold for this app).
|
||||
CFPreferencesSetAppValue(CFSTR("ApplePressAndHoldEnabled"), kCFBooleanFalse, kCFPreferencesCurrentApplication);
|
||||
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
|
||||
|
||||
// Qt6 macOS default look is still lacking, so let's force Fusion for now
|
||||
QQuickStyle::setStyle(QStringLiteral("Fusion"));
|
||||
#endif
|
||||
|
||||
if (argc>1 && (!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help"))) {
|
||||
QTextStream cout(stdout, QIODevice::WriteOnly);
|
||||
cout << "Usage: " << argv[0] << " [--default-settings] [--workdir <dir>] [--program <prog>] [-p|--profile <prof>] [--fullscreen] [-h|--help]" << Qt::endl;
|
||||
cout << " --default-settings Run cool-retro-term with the default settings" << Qt::endl;
|
||||
cout << " --workdir <dir> Change working directory to 'dir'" << Qt::endl;
|
||||
cout << " -e <cmd> Command to execute. This option will catch all following arguments, so use it as the last option." << Qt::endl;
|
||||
cout << " --fullscreen Run cool-retro-term in fullscreen." << Qt::endl;
|
||||
cout << " -p|--profile <prof> Run cool-retro-term with the given profile." << Qt::endl;
|
||||
cout << " -h|--help Print this help." << Qt::endl;
|
||||
cout << " --verbose Print additional information such as profiles and settings." << Qt::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
engine.rootContext()->setContextProperty("workdir", getNamedArgument(args, "--workdir"));
|
||||
engine.rootContext()->setContextProperty("shellProgram", getNamedArgument(args, "--program"));
|
||||
QString appVersion("1.2.0");
|
||||
|
||||
if (argc>1 && (!strcmp(argv[1],"-v") || !strcmp(argv[1],"--version"))) {
|
||||
QTextStream cout(stdout, QIODevice::WriteOnly);
|
||||
cout << "cool-retro-term " << appVersion << Qt::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
QApplication app(argc, argv);
|
||||
app.setAttribute(Qt::AA_MacDontSwapCtrlAndMeta, true);
|
||||
app.setApplicationName(QStringLiteral("cool-retro-term"));
|
||||
app.setOrganizationName(QStringLiteral("cool-retro-term"));
|
||||
app.setOrganizationDomain(QStringLiteral("cool-retro-term"));
|
||||
|
||||
KDSingleApplication singleApp(QStringLiteral("cool-retro-term"));
|
||||
|
||||
if (!singleApp.isPrimaryInstance()) {
|
||||
if (singleApp.sendMessage("new-window"))
|
||||
return 0;
|
||||
qWarning() << "KDSingleApplication: primary not reachable, continuing as independent instance.";
|
||||
}
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
FileIO fileIO;
|
||||
|
||||
qmlRegisterType<FontManager>("CoolRetroTerm", 1, 0, "FontManager");
|
||||
qmlRegisterUncreatableType<FontListModel>("CoolRetroTerm", 1, 0, "FontListModel", "FontListModel is created by FontManager");
|
||||
|
||||
#if !defined(Q_OS_MAC)
|
||||
app.setWindowIcon(QIcon::fromTheme("cool-retro-term", QIcon(":../icons/32x32/cool-retro-term.png")));
|
||||
#if defined(Q_OS_LINUX)
|
||||
QGuiApplication::setDesktopFileName(QStringLiteral("cool-retro-term"));
|
||||
#endif
|
||||
#else
|
||||
app.setWindowIcon(QIcon(":../icons/32x32/cool-retro-term.png"));
|
||||
#endif
|
||||
|
||||
// Manage command line arguments from the cpp side
|
||||
QStringList args = app.arguments();
|
||||
|
||||
// Manage default command
|
||||
QStringList cmdList;
|
||||
if (args.contains("-e")) {
|
||||
cmdList << args.mid(args.indexOf("-e") + 1);
|
||||
}
|
||||
QVariant command(cmdList.empty() ? QVariant() : cmdList[0]);
|
||||
QVariant commandArgs(cmdList.size() <= 1 ? QVariant() : QVariant(cmdList.mid(1)));
|
||||
engine.rootContext()->setContextProperty("appVersion", appVersion);
|
||||
engine.rootContext()->setContextProperty("defaultCmd", command);
|
||||
engine.rootContext()->setContextProperty("defaultCmdArgs", commandArgs);
|
||||
|
||||
engine.rootContext()->setContextProperty("workdir", getNamedArgument(args, "--workdir", "$HOME"));
|
||||
engine.rootContext()->setContextProperty("fileIO", &fileIO);
|
||||
|
||||
// Manage import paths for Linux and OSX.
|
||||
QStringList importPathList = engine.importPathList();
|
||||
importPathList.prepend(QCoreApplication::applicationDirPath() + "/imports/");
|
||||
importPathList.prepend(QCoreApplication::applicationDirPath() + "/../PlugIns");
|
||||
importPathList.append(QCoreApplication::applicationDirPath() + "/qmltermwidget");
|
||||
importPathList.append(QCoreApplication::applicationDirPath() + "/../PlugIns");
|
||||
importPathList.append(QCoreApplication::applicationDirPath() + "/../../../qmltermwidget");
|
||||
engine.setImportPathList(importPathList);
|
||||
|
||||
engine.load(QUrl("qrc:/main.qml"));
|
||||
engine.load(QUrl(QStringLiteral ("qrc:/main.qml")));
|
||||
|
||||
if (engine.rootObjects().isEmpty()) {
|
||||
qDebug() << "Cannot load QML interface";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Quit the application when the engine closes.
|
||||
QObject::connect((QObject*) &engine, SIGNAL(quit()), (QObject*) &app, SLOT(quit()));
|
||||
|
||||
auto requestNewWindow = [&engine]() {
|
||||
if (engine.rootObjects().isEmpty())
|
||||
return;
|
||||
|
||||
QObject *rootObject = engine.rootObjects().constFirst();
|
||||
QMetaObject::invokeMethod(rootObject, "createWindow", Qt::QueuedConnection);
|
||||
};
|
||||
|
||||
QObject::connect(&singleApp, &KDSingleApplication::messageReceived, &app,
|
||||
[&requestNewWindow](const QByteArray &message) {
|
||||
if (message.isEmpty() || message == QByteArray("new-window"))
|
||||
requestNewWindow();
|
||||
});
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
QMenu *dockMenu = new QMenu(nullptr);
|
||||
dockMenu->addAction(QObject::tr("New Window"), [&requestNewWindow]() { requestNewWindow(); });
|
||||
dockMenu->setAsDockMenu();
|
||||
#endif
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
@@ -1,24 +1,47 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.0
|
||||
|
||||
Window{
|
||||
ApplicationWindow {
|
||||
id: dialogwindow
|
||||
title: qsTr("About")
|
||||
width: 450
|
||||
height: 300
|
||||
width: 600
|
||||
height: 400
|
||||
|
||||
ColumnLayout{
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 15
|
||||
spacing: 15
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: "cool-retro-term"
|
||||
font {bold: true; pointSize: 18}
|
||||
color: palette.text
|
||||
font {
|
||||
bold: true
|
||||
pointSize: 18
|
||||
}
|
||||
}
|
||||
Loader{
|
||||
Loader {
|
||||
id: mainContent
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
@@ -39,71 +62,73 @@ Window{
|
||||
}
|
||||
}
|
||||
]
|
||||
Component.onCompleted: mainContent.state = "Default";
|
||||
Component.onCompleted: mainContent.state = "Default"
|
||||
}
|
||||
Item{
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
height: childrenRect.height
|
||||
Button{
|
||||
Button {
|
||||
anchors.left: parent.left
|
||||
text: qsTr("License")
|
||||
onClicked: {
|
||||
mainContent.state == "Default" ? mainContent.state = "License" : mainContent.state = "Default"
|
||||
mainContent.state == "Default" ? mainContent.state
|
||||
= "License" : mainContent.state = "Default"
|
||||
}
|
||||
}
|
||||
Button{
|
||||
Button {
|
||||
anchors.right: parent.right
|
||||
text: qsTr("Close")
|
||||
onClicked: dialogwindow.close();
|
||||
onClicked: dialogwindow.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
// MAIN COMPONENTS ////////////////////////////////////////////////////////
|
||||
Component{
|
||||
Component {
|
||||
id: defaultComponent
|
||||
ColumnLayout{
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
Item{
|
||||
Layout.fillHeight: true
|
||||
Image {
|
||||
Layout.fillWidth: true
|
||||
Image{
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "images/crt256.png"
|
||||
smooth: true
|
||||
}
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "images/crt256.png"
|
||||
smooth: true
|
||||
}
|
||||
Text{
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: shadersettings.version + "\n" +
|
||||
qsTr("Author: ") + "Filippo Scognamiglio\n" +
|
||||
qsTr("Email: ") + "flscogna@gmail.com\n" +
|
||||
qsTr("Source: ") + "https://github.com/Swordfish90/cool-retro-term\n"
|
||||
color: palette.text
|
||||
text: appSettings.version + "\n" + qsTr(
|
||||
"Author: ") + "Filippo Scognamiglio\n" + qsTr(
|
||||
"Email: ") + "flscogna@gmail.com\n" + qsTr(
|
||||
"Source: ") + "https://github.com/Swordfish90/cool-retro-term\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
Component{
|
||||
Component {
|
||||
id: licenseComponent
|
||||
TextArea{
|
||||
ScrollView {
|
||||
anchors.fill: parent
|
||||
readOnly: true
|
||||
text: "Copyright (c) 2013 Filippo Scognamiglio <flscogna@gmail.com>\n\n" +
|
||||
"https://github.com/Swordfish90/cool-retro-term\n\n" +
|
||||
|
||||
"cool-retro-term is free software: you can redistribute it and/or modify " +
|
||||
"it under the terms of the GNU General Public License as published by " +
|
||||
"the Free Software Foundation, either version 3 of the License, or " +
|
||||
"(at your option) any later version.\n\n" +
|
||||
|
||||
"This program is distributed in the hope that it will be useful, " +
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of " +
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the " +
|
||||
"GNU General Public License for more details.\n\n" +
|
||||
|
||||
"You should have received a copy of the GNU General Public License " +
|
||||
"along with this program. If not, see <http://www.gnu.org/licenses/>."
|
||||
clip: true
|
||||
TextArea {
|
||||
readOnly: true
|
||||
wrapMode: TextEdit.Wrap
|
||||
color: palette.text
|
||||
text: "Copyright (c) 2013-2025 Filippo Scognamiglio <flscogna@gmail.com>\n\n"
|
||||
+ "https://github.com/Swordfish90/cool-retro-term\n\n" +
|
||||
"cool-retro-term is free software: you can redistribute it and/or modify "
|
||||
+ "it under the terms of the GNU General Public License as published by "
|
||||
+ "the Free Software Foundation, either version 3 of the License, or "
|
||||
+ "(at your option) any later version.\n\n" +
|
||||
"This program is distributed in the hope that it will be useful, "
|
||||
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of "
|
||||
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
|
||||
+ "GNU General Public License for more details.\n\n" +
|
||||
"You should have received a copy of the GNU General Public License "
|
||||
+ "along with this program. If not, see <http://www.gnu.org/licenses/>."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
129
app/qml/BurnInEffect.qml
Normal file
@@ -0,0 +1,129 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
import QtQuick 2.0
|
||||
|
||||
import "utils.js" as Utils
|
||||
|
||||
Loader {
|
||||
id: burnInEffect
|
||||
|
||||
property ShaderEffectSource effectSource: item ? item.source : null
|
||||
|
||||
property real lastUpdate: 0
|
||||
property real prevLastUpdate: 0
|
||||
|
||||
property real burnIn: appSettings.burnIn
|
||||
property real burnInFadeTime: 1 / Utils.lint(_minBurnInFadeTime, _maxBurnInFadeTime, burnIn)
|
||||
property real _minBurnInFadeTime: appSettings.minBurnInFadeTime
|
||||
property real _maxBurnInFadeTime: appSettings.maxBurnInFadeTime
|
||||
|
||||
active: appSettings.burnIn !== 0
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
function completelyUpdate() {
|
||||
let newTime = timeManager.time
|
||||
if (newTime > lastUpdate) {
|
||||
prevLastUpdate = lastUpdate
|
||||
lastUpdate = newTime
|
||||
}
|
||||
|
||||
item.source.scheduleUpdate()
|
||||
}
|
||||
|
||||
function restartBlurSource() {
|
||||
prevLastUpdate = timeManager.time
|
||||
lastUpdate = prevLastUpdate
|
||||
completelyUpdate()
|
||||
}
|
||||
|
||||
sourceComponent: Item {
|
||||
property alias source: burnInEffectSource
|
||||
|
||||
ShaderEffectSource {
|
||||
id: burnInEffectSource
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
sourceItem: burnInShaderEffect
|
||||
live: false
|
||||
recursive: true
|
||||
hideSource: true
|
||||
wrapMode: ShaderEffectSource.ClampToEdge
|
||||
|
||||
format: ShaderEffectSource.RGBA
|
||||
smooth: true
|
||||
|
||||
visible: false
|
||||
|
||||
Connections {
|
||||
target: kterminal
|
||||
|
||||
onImagePainted: {
|
||||
completelyUpdate()
|
||||
}
|
||||
}
|
||||
// Restart blurred source settings change.
|
||||
Connections {
|
||||
target: appSettings.fontManager
|
||||
|
||||
onTerminalFontChanged: {
|
||||
burnInEffect.restartBlurSource()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: appSettings
|
||||
|
||||
onBurnInChanged: {
|
||||
burnInEffect.restartBlurSource()
|
||||
}
|
||||
|
||||
onRasterizationChanged: {
|
||||
burnInEffect.restartBlurSource()
|
||||
}
|
||||
|
||||
onBurnInQualityChanged: {
|
||||
burnInEffect.restartBlurSource()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShaderEffect {
|
||||
id: burnInShaderEffect
|
||||
|
||||
property real time: timeManager.time
|
||||
|
||||
property variant txt_source: kterminalSource
|
||||
property variant burnInSource: burnInEffectSource
|
||||
property real burnInTime: burnInFadeTime
|
||||
property real burnInLastUpdate: burnInEffect.lastUpdate
|
||||
property real prevLastUpdate: burnInEffect.prevLastUpdate
|
||||
|
||||
anchors.fill: parent
|
||||
blending: false
|
||||
|
||||
fragmentShader: "qrc:/shaders/burn_in.frag.qsb"
|
||||
vertexShader: "qrc:/shaders/burn_in.vert.qsb"
|
||||
|
||||
onStatusChanged: if (log) console.log(log) //Print warning messages
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
|
||||
MenuBar {
|
||||
id: defaultMenuBar
|
||||
property bool visible: true
|
||||
Menu {
|
||||
title: qsTr("File")
|
||||
visible: defaultMenuBar.visible
|
||||
MenuItem {action: quitAction}
|
||||
}
|
||||
Menu {
|
||||
title: qsTr("Edit")
|
||||
visible: defaultMenuBar.visible
|
||||
MenuItem {action: copyAction}
|
||||
MenuItem {action: pasteAction}
|
||||
MenuSeparator{visible: Qt.platform.os !== "osx"}
|
||||
MenuItem {action: showsettingsAction}
|
||||
}
|
||||
Menu{
|
||||
title: qsTr("View")
|
||||
visible: defaultMenuBar.visible
|
||||
MenuItem {action: fullscreenAction; visible: fullscreenAction.enabled}
|
||||
MenuItem {action: showMenubarAction; visible: showMenubarAction.enabled}
|
||||
MenuSeparator{visible: showMenubarAction.enabled}
|
||||
MenuItem {action: zoomIn}
|
||||
MenuItem {action: zoomOut}
|
||||
}
|
||||
Menu{
|
||||
id: profilesMenu
|
||||
title: qsTr("Profiles")
|
||||
visible: defaultMenuBar.visible
|
||||
Instantiator{
|
||||
model: shadersettings.profiles_list
|
||||
delegate: MenuItem {
|
||||
text: model.text
|
||||
onTriggered: {
|
||||
shadersettings.loadProfileString(obj_string);
|
||||
shadersettings.handleFontChanged();
|
||||
}
|
||||
}
|
||||
onObjectAdded: profilesMenu.insertItem(index, object)
|
||||
onObjectRemoved: profilesMenu.removeItem(object)
|
||||
}
|
||||
}
|
||||
Menu{
|
||||
title: qsTr("Help")
|
||||
visible: defaultMenuBar.visible
|
||||
MenuItem {action: showAboutAction}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -17,65 +17,56 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import "Components"
|
||||
|
||||
RowLayout {
|
||||
property alias name: check.text
|
||||
|
||||
property double value
|
||||
property alias min_value: slider.minimumValue
|
||||
property alias max_value: slider.maximumValue
|
||||
property alias min_value: slider.from
|
||||
property alias max_value: slider.to
|
||||
property alias stepSize: slider.stepSize
|
||||
|
||||
signal newValue(real newValue);
|
||||
signal newValue(real newValue)
|
||||
|
||||
id: setting_component
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 25
|
||||
Layout.fillWidth: true
|
||||
|
||||
onValueChanged: {
|
||||
check.checked = !(value == 0);
|
||||
if(check.checked)
|
||||
slider.value = value;
|
||||
check.checked = !(value == 0)
|
||||
if (check.checked)
|
||||
slider.value = value
|
||||
}
|
||||
|
||||
CheckBox{
|
||||
CheckBox {
|
||||
id: check
|
||||
implicitWidth: 150
|
||||
implicitWidth: 160
|
||||
onClicked: {
|
||||
if(!checked){
|
||||
checked = false;
|
||||
slider.enabled = false;
|
||||
newValue(0);
|
||||
if (!checked) {
|
||||
checked = false
|
||||
slider.enabled = false
|
||||
newValue(0)
|
||||
} else {
|
||||
checked = true;
|
||||
newValue(slider.value);
|
||||
slider.enabled = true;
|
||||
checked = true
|
||||
newValue(slider.value)
|
||||
slider.enabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
Slider{
|
||||
Slider {
|
||||
id: slider
|
||||
stepSize: parent.stepSize
|
||||
Layout.fillWidth: true
|
||||
onValueChanged: {
|
||||
newValue(value);
|
||||
newValue(value)
|
||||
}
|
||||
}
|
||||
Text{
|
||||
id: textfield
|
||||
property string unformattedText: Math.round(((value - min_value) / (max_value - min_value)) * 100)
|
||||
text: formatNumber(unformattedText)
|
||||
}
|
||||
function formatNumber(num) {
|
||||
var n = "" + num;
|
||||
while (n.length < 3) {
|
||||
n = " " + n;
|
||||
}
|
||||
return n + "%";
|
||||
SizedLabel {
|
||||
text: Math.round(
|
||||
((value - min_value) / (max_value - min_value)) * 100) + "%"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -17,31 +17,33 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Dialogs 1.1
|
||||
import QtQuick.Dialogs
|
||||
|
||||
Item {
|
||||
signal colorSelected (color color)
|
||||
property color button_color
|
||||
id: rootItem
|
||||
|
||||
signal colorSelected(color color)
|
||||
property color color
|
||||
property string name
|
||||
|
||||
ColorDialog {
|
||||
id: colorDialog
|
||||
title: qsTr("Choose a color")
|
||||
modality: Qt.ApplicationModal
|
||||
visible: false
|
||||
selectedColor: rootItem.color
|
||||
|
||||
//This is a workaround to a Qt 5.2 bug.
|
||||
onCurrentColorChanged: colorDialog.color = colorDialog.currentColor;
|
||||
onAccepted: colorSelected(color)
|
||||
onSelectedColorChanged: {
|
||||
if (!appSettings.isMacOS && visible)
|
||||
colorSelected(selectedColor)
|
||||
}
|
||||
onAccepted: colorSelected(selectedColor)
|
||||
}
|
||||
Rectangle{
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 10
|
||||
color: button_color
|
||||
border.color: "black"
|
||||
Glossy {}
|
||||
color: rootItem.color
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: parent.height * 0.25
|
||||
@@ -49,14 +51,14 @@ Item {
|
||||
color: "white"
|
||||
opacity: 0.5
|
||||
}
|
||||
Text{
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
z: parent.z + 1
|
||||
text: name + ": " + button_color
|
||||
text: name + ": " + rootItem.color
|
||||
}
|
||||
}
|
||||
MouseArea{
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: colorDialog.visible = true;
|
||||
onClicked: colorDialog.open()
|
||||
}
|
||||
}
|
||||
|
||||
32
app/qml/Components/SizedLabel.qml
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.0
|
||||
|
||||
// This component is simply a label with a predefined size.
|
||||
// Used to improve alignment.
|
||||
Label {
|
||||
id: textfield
|
||||
Layout.minimumWidth: appSettings.labelWidth
|
||||
width: appSettings.labelWidth
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
|
||||
Item{
|
||||
property int selectedFontIndex
|
||||
property real scaling
|
||||
property alias fontlist: fontlist
|
||||
property var _font: fontlist.get(selectedFontIndex)
|
||||
property var source: _font.source
|
||||
property int pixelSize: _font.pixelSize
|
||||
property int lineSpacing: _font.lineSpacing
|
||||
property real screenScaling: scaling * _font.baseScaling
|
||||
|
||||
ListModel{
|
||||
id: fontlist
|
||||
ListElement{
|
||||
text: "Commodore PET (1977)"
|
||||
source: "fonts/1977-commodore-pet/COMMODORE_PET.ttf"
|
||||
lineSpacing: 2
|
||||
pixelSize: 8
|
||||
baseScaling: 4.0
|
||||
}
|
||||
ListElement{
|
||||
text: "Apple ][ (1977)"
|
||||
source: "fonts/1977-apple2/PrintChar21.ttf"
|
||||
lineSpacing: 2
|
||||
pixelSize: 8
|
||||
baseScaling: 4.0
|
||||
}
|
||||
ListElement{
|
||||
text: "Atari 400-800 (1979)"
|
||||
source: "fonts/1979-atari-400-800/ATARI400800_original.TTF"
|
||||
lineSpacing: 3
|
||||
pixelSize: 8
|
||||
baseScaling: 4.0
|
||||
}
|
||||
ListElement{
|
||||
text: "Commodore 64 (1982)"
|
||||
source: "fonts/1982-commodore64/C64_User_Mono_v1.0-STYLE.ttf"
|
||||
lineSpacing: 3
|
||||
pixelSize: 8
|
||||
baseScaling: 4.0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
|
||||
Item{
|
||||
property int selectedFontIndex
|
||||
property real scaling
|
||||
property alias fontlist: fontlist
|
||||
property var _font: fontlist.get(selectedFontIndex)
|
||||
property var source: _font.source
|
||||
property int pixelSize: _font.pixelSize
|
||||
property int lineSpacing: _font.lineSpacing
|
||||
property real screenScaling: scaling * _font.baseScaling
|
||||
|
||||
ListModel{
|
||||
id: fontlist
|
||||
ListElement{
|
||||
text: "Commodore PET (1977)"
|
||||
source: "fonts/1977-commodore-pet/COMMODORE_PET.ttf"
|
||||
lineSpacing: 2
|
||||
pixelSize: 8
|
||||
baseScaling: 4.0
|
||||
}
|
||||
ListElement{
|
||||
text: "Apple ][ (1977)"
|
||||
source: "fonts/1977-apple2/PrintChar21.ttf"
|
||||
lineSpacing: 2
|
||||
pixelSize: 8
|
||||
baseScaling: 4.0
|
||||
}
|
||||
ListElement{
|
||||
text: "Atari 400-800 (1979)"
|
||||
source: "fonts/1979-atari-400-800/ATARI400800_original.TTF"
|
||||
lineSpacing: 3
|
||||
pixelSize: 8
|
||||
baseScaling: 4.0
|
||||
}
|
||||
ListElement{
|
||||
text: "Commodore 64 (1982)"
|
||||
source: "fonts/1982-commodore64/C64_User_Mono_v1.0-STYLE.ttf"
|
||||
lineSpacing: 3
|
||||
pixelSize: 8
|
||||
baseScaling: 4.0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
|
||||
Item{
|
||||
property int selectedFontIndex
|
||||
property real scaling
|
||||
property alias fontlist: fontlist
|
||||
property var source: fontlist.get(selectedFontIndex).source
|
||||
property var _font: fontlist.get(selectedFontIndex)
|
||||
property int pixelSize: _font.pixelSize * scaling
|
||||
property int lineSpacing: pixelSize * _font.lineSpacing
|
||||
property real screenScaling: 1.0
|
||||
|
||||
//In this configuration lineSpacing is proportional to pixelSize.
|
||||
|
||||
ListModel{
|
||||
id: fontlist
|
||||
ListElement{
|
||||
text: "Terminus (Modern)"
|
||||
source: "fonts/modern-terminus/TerminusTTF-Bold-4.38.2.ttf"
|
||||
lineSpacing: 0.2
|
||||
pixelSize: 35
|
||||
}
|
||||
ListElement{
|
||||
text: "Commodore PET (1977)"
|
||||
source: "fonts/1977-commodore-pet/COMMODORE_PET.ttf"
|
||||
lineSpacing: 0.2
|
||||
pixelSize: 24
|
||||
}
|
||||
ListElement{
|
||||
text: "Commodore PET 2Y (1977)"
|
||||
source: "fonts/1977-commodore-pet/COMMODORE_PET_2y.ttf"
|
||||
lineSpacing: 0.2
|
||||
pixelSize: 32
|
||||
}
|
||||
ListElement{
|
||||
text: "Apple ][ (1977)"
|
||||
source: "fonts/1977-apple2/PrintChar21.ttf"
|
||||
lineSpacing: 0.2
|
||||
pixelSize: 24
|
||||
}
|
||||
ListElement{
|
||||
text: "Atari 400-800 (1979)"
|
||||
source: "fonts/1979-atari-400-800/ATARI400800_original.TTF"
|
||||
lineSpacing: 0.3
|
||||
pixelSize: 24
|
||||
}
|
||||
ListElement{
|
||||
text: "Commodore 64 (1982)"
|
||||
source: "fonts/1982-commodore64/C64_User_Mono_v1.0-STYLE.ttf"
|
||||
lineSpacing: 0.3
|
||||
pixelSize: 24
|
||||
}
|
||||
ListElement{
|
||||
text: "Atari ST (1985)"
|
||||
source: "fonts/1985-atari-st/AtariST8x16SystemFont.ttf"
|
||||
lineSpacing: 0.2
|
||||
pixelSize: 32
|
||||
}
|
||||
ListElement{
|
||||
text: "IBM DOS (1985)"
|
||||
source: "fonts/1985-ibm-pc-vga/Perfect DOS VGA 437.ttf"
|
||||
lineSpacing: 0.2
|
||||
pixelSize: 32
|
||||
}
|
||||
ListElement{
|
||||
text: "IBM 3278 (1971)"
|
||||
source: "fonts/1971-ibm-3278/3270Medium.ttf"
|
||||
lineSpacing: 0.2
|
||||
pixelSize: 32
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import QtQuick 2.2
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - parent.border.width
|
||||
height: parent.height - parent.border.width
|
||||
radius:parent.radius - parent.border.width/2
|
||||
smooth: true
|
||||
|
||||
border.width: parent.border.width/2
|
||||
border.color: "#22FFFFFF"
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0; color: "#88FFFFFF" }
|
||||
GradientStop { position: .1; color: "#55FFFFFF" }
|
||||
GradientStop { position: .5; color: "#33FFFFFF" }
|
||||
GradientStop { position: .501; color: "#11000000" }
|
||||
GradientStop { position: .8; color: "#11FFFFFF" }
|
||||
GradientStop { position: 1; color: "#55FFFFFF" }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -17,20 +17,20 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Window 2.0
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.1
|
||||
import QtQuick.Dialogs
|
||||
|
||||
Window{
|
||||
Window {
|
||||
id: insertnamedialog
|
||||
width: 400
|
||||
height: 100
|
||||
modality: Qt.ApplicationModal
|
||||
title: qsTr("Save new profile")
|
||||
|
||||
property alias profileName: namefield.text
|
||||
signal nameSelected(string name)
|
||||
|
||||
MessageDialog {
|
||||
@@ -38,60 +38,53 @@ Window{
|
||||
title: qsTr("Error")
|
||||
visible: false
|
||||
|
||||
function showError(message){
|
||||
text = message;
|
||||
open();
|
||||
function showError(message) {
|
||||
text = message
|
||||
open()
|
||||
}
|
||||
}
|
||||
|
||||
function validateName(name){
|
||||
var profile_list = shadersettings.profiles_list;
|
||||
function validateName(name) {
|
||||
var profile_list = appSettings.profilesList
|
||||
if (name === "")
|
||||
return 1;
|
||||
|
||||
for (var i = 0; i < profile_list.count; i++){
|
||||
if(profile_list.get(i).text === name)
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
ColumnLayout{
|
||||
ColumnLayout {
|
||||
anchors.margins: 10
|
||||
anchors.fill: parent
|
||||
RowLayout{
|
||||
Label{text: qsTr("Name")}
|
||||
TextField{
|
||||
RowLayout {
|
||||
Label {
|
||||
text: qsTr("Name")
|
||||
}
|
||||
TextField {
|
||||
id: namefield
|
||||
Layout.fillWidth: true
|
||||
Component.onCompleted: forceActiveFocus()
|
||||
onAccepted: okbutton.clickAction()
|
||||
}
|
||||
}
|
||||
RowLayout{
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
Button{
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
|
||||
Button {
|
||||
id: okbutton
|
||||
text: qsTr("OK")
|
||||
onClicked: clickAction()
|
||||
function clickAction(){
|
||||
var name = namefield.text;
|
||||
switch(validateName(name)){
|
||||
function clickAction() {
|
||||
var name = namefield.text
|
||||
switch (validateName(name)) {
|
||||
case 1:
|
||||
errorDialog.showError(qsTr("The name you inserted is empty. Please choose a different one."));
|
||||
break;
|
||||
case 2:
|
||||
errorDialog.showError(qsTr("The name you inserted already exists. Please choose a different one."));
|
||||
break;
|
||||
errorDialog.showError(
|
||||
qsTr("The name you inserted is empty. Please choose a different one."))
|
||||
break
|
||||
default:
|
||||
nameSelected(name);
|
||||
close();
|
||||
nameSelected(name)
|
||||
close()
|
||||
}
|
||||
}
|
||||
}
|
||||
Button{
|
||||
Button {
|
||||
text: qsTr("Cancel")
|
||||
onClicked: close()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -19,426 +19,269 @@
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls 2.0
|
||||
|
||||
import org.crt.konsole 0.1
|
||||
import QMLTermWidget 1.0
|
||||
|
||||
import "menus"
|
||||
import "utils.js" as Utils
|
||||
|
||||
Item{
|
||||
id: terminalContainer
|
||||
signal sessionFinished()
|
||||
|
||||
//Frame displacement properties. This makes the terminal the same size of the texture.
|
||||
property real dtop: frame.item.displacementTop
|
||||
property real dleft:frame.item.displacementLeft
|
||||
property real dright: frame.item.displacementRight
|
||||
property real dbottom: frame.item.displacementBottom
|
||||
|
||||
anchors.leftMargin: dleft
|
||||
anchors.rightMargin: dright
|
||||
anchors.topMargin: dtop
|
||||
anchors.bottomMargin: dbottom
|
||||
|
||||
property variant theSource: mBlur !== 0 ? blurredSourceLoader.item : kterminalSource
|
||||
property variant bloomSource: bloomSourceLoader.item
|
||||
property variant rasterizationSource: rasterizationEffectSource
|
||||
property variant staticNoiseSource: staticNoiseSource
|
||||
property size virtualResolution: Qt.size(kterminal.totalWidth, kterminal.totalHeight)
|
||||
property alias mainTerminal: kterminal
|
||||
|
||||
property ShaderEffectSource mainSource: kterminalSource
|
||||
property BurnInEffect burnInEffect: burnInEffect
|
||||
property real fontWidth: 1.0
|
||||
property real screenScaling: 1.0
|
||||
property real scaleTexture: 1.0
|
||||
property alias title: ksession.title
|
||||
property alias kterminal: kterminal
|
||||
|
||||
signal sizeChanged
|
||||
onWidthChanged: sizeChanged()
|
||||
onHeightChanged: sizeChanged()
|
||||
|
||||
//The blur effect has to take into account the framerate
|
||||
property int fps: shadersettings.fps !== 0 ? shadersettings.fps : 60
|
||||
property real fpsAttenuation: Math.sqrt(60 / fps)
|
||||
property real mBlur: shadersettings.motion_blur
|
||||
property real motionBlurCoefficient: (_maxBlurCoefficient * mBlur + _minBlurCoefficient * (1 - mBlur))
|
||||
property real _minBlurCoefficient: 0.70
|
||||
property real _maxBlurCoefficient: 0.90
|
||||
|
||||
property real mBloom: shadersettings.bloom_strength
|
||||
property int mScanlines: shadersettings.rasterization
|
||||
onMScanlinesChanged: restartBlurredSource()
|
||||
|
||||
property size terminalSize: kterminal.terminalSize
|
||||
property size paintedTextSize
|
||||
property size fontMetrics: kterminal.fontMetrics
|
||||
|
||||
onMBlurChanged: restartBlurredSource()
|
||||
// Manage copy and paste
|
||||
Connections {
|
||||
target: copyAction
|
||||
|
||||
function restartBlurredSource(){
|
||||
if(!blurredSourceLoader.item) return;
|
||||
blurredSourceLoader.item.restartBlurSource();
|
||||
onTriggered: {
|
||||
kterminal.copyClipboard()
|
||||
}
|
||||
}
|
||||
function pasteClipboard(){
|
||||
kterminal.pasteClipboard();
|
||||
}
|
||||
function copyClipboard(){
|
||||
kterminal.copyClipboard();
|
||||
Connections {
|
||||
target: pasteAction
|
||||
|
||||
onTriggered: {
|
||||
kterminal.pasteClipboard()
|
||||
}
|
||||
}
|
||||
|
||||
//When settings are updated sources need to be redrawn.
|
||||
Connections{
|
||||
target: shadersettings
|
||||
onFontScalingChanged: terminalContainer.updateSources();
|
||||
onFontWidthChanged: terminalContainer.updateSources();
|
||||
Connections {
|
||||
target: appSettings
|
||||
|
||||
onFontScalingChanged: {
|
||||
terminalContainer.updateSources()
|
||||
}
|
||||
|
||||
onFontWidthChanged: {
|
||||
terminalContainer.updateSources()
|
||||
}
|
||||
}
|
||||
Connections{
|
||||
Connections {
|
||||
target: terminalContainer
|
||||
onWidthChanged: terminalContainer.updateSources();
|
||||
onHeightChanged: terminalContainer.updateSources();
|
||||
|
||||
onWidthChanged: {
|
||||
terminalContainer.updateSources()
|
||||
}
|
||||
|
||||
onHeightChanged: {
|
||||
terminalContainer.updateSources()
|
||||
}
|
||||
}
|
||||
|
||||
function updateSources() {
|
||||
kterminal.update();
|
||||
kterminal.updateImage();
|
||||
kterminal.update()
|
||||
}
|
||||
|
||||
|
||||
KTerminal {
|
||||
QMLTermWidget {
|
||||
id: kterminal
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
property int textureResolutionScale: appSettings.lowResolutionFont ? Screen.devicePixelRatio : 1
|
||||
property int margin: appSettings.margin / screenScaling
|
||||
property int totalWidth: Math.floor(parent.width / (screenScaling * fontWidth))
|
||||
property int totalHeight: Math.floor(parent.height / screenScaling)
|
||||
|
||||
property int rawWidth: totalWidth - 2 * margin
|
||||
property int rawHeight: totalHeight - 2 * margin
|
||||
|
||||
textureSize: Qt.size(width / textureResolutionScale, height / textureResolutionScale)
|
||||
|
||||
width: ensureMultiple(rawWidth, Screen.devicePixelRatio)
|
||||
height: ensureMultiple(rawHeight, Screen.devicePixelRatio)
|
||||
|
||||
/** Ensure size is a multiple of factor. This is needed for pixel perfect scaling on highdpi screens. */
|
||||
function ensureMultiple(size, factor) {
|
||||
return Math.round(size / factor) * factor;
|
||||
}
|
||||
|
||||
fullCursorHeight: true
|
||||
blinkingCursor: appSettings.blinkingCursor
|
||||
|
||||
colorScheme: "cool-retro-term"
|
||||
|
||||
smooth: false
|
||||
|
||||
session: KSession {
|
||||
session: QMLTermSession {
|
||||
id: ksession
|
||||
kbScheme: "xterm"
|
||||
|
||||
onFinished: {
|
||||
Qt.quit()
|
||||
terminalContainer.sessionFinished()
|
||||
}
|
||||
}
|
||||
|
||||
FontLoader{ id: fontLoader }
|
||||
Text{id: fontMetrics; text: "B"; visible: false}
|
||||
QMLTermScrollbar {
|
||||
id: kterminalScrollbar
|
||||
terminal: kterminal
|
||||
anchors.margins: width * 0.5
|
||||
width: terminal.fontMetrics.width * 0.75
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 1
|
||||
anchors.bottomMargin: 1
|
||||
color: "white"
|
||||
opacity: 0.7
|
||||
}
|
||||
}
|
||||
|
||||
function handleFontChange(fontSource, pixelSize, lineSpacing, screenScaling){
|
||||
fontLoader.source = fontSource;
|
||||
font.pixelSize = pixelSize;
|
||||
font.family = fontLoader.name;
|
||||
function handleFontChanged(fontFamily, pixelSize, lineSpacing, screenScaling, fontWidth, fallbackFontFamily, lowResolutionFont) {
|
||||
kterminal.lineSpacing = lineSpacing;
|
||||
kterminal.antialiasText = !lowResolutionFont;
|
||||
kterminal.smooth = !lowResolutionFont;
|
||||
kterminal.enableBold = !lowResolutionFont;
|
||||
|
||||
var fontWidth = 1.0 / shadersettings.fontWidth;
|
||||
|
||||
width = Qt.binding(function() {return Math.floor(fontWidth * terminalContainer.width / screenScaling);});
|
||||
height = Qt.binding(function() {return Math.floor(terminalContainer.height / screenScaling);});
|
||||
|
||||
var scaleTexture = Math.max(Math.round(screenScaling / shadersettings.scanline_quality), 1.0);
|
||||
|
||||
kterminalSource.textureSize = Qt.binding(function () {
|
||||
return Qt.size(kterminal.width * scaleTexture, kterminal.height * scaleTexture);
|
||||
kterminal.font = Qt.font({
|
||||
family: fontFamily,
|
||||
pixelSize: pixelSize
|
||||
});
|
||||
|
||||
setLineSpacing(lineSpacing);
|
||||
update();
|
||||
restartBlurredSource();
|
||||
terminalContainer.fontWidth = fontWidth;
|
||||
terminalContainer.screenScaling = screenScaling;
|
||||
scaleTexture = Math.max(1.0, Math.floor(screenScaling * appSettings.windowScaling));
|
||||
}
|
||||
Component.onCompleted: {
|
||||
shadersettings.terminalFontChanged.connect(handleFontChange);
|
||||
|
||||
Connections {
|
||||
target: appSettings
|
||||
|
||||
onWindowScalingChanged: {
|
||||
scaleTexture = Math.max(1.0, Math.floor(terminalContainer.screenScaling * appSettings.windowScaling));
|
||||
}
|
||||
}
|
||||
|
||||
function startSession() {
|
||||
// Retrieve the variable set in main.cpp if arguments are passed.
|
||||
if (shellProgram)
|
||||
ksession.setShellProgram(shellProgram);
|
||||
if (defaultCmd) {
|
||||
ksession.setShellProgram(defaultCmd);
|
||||
ksession.setArgs(defaultCmdArgs);
|
||||
} else if (appSettings.useCustomCommand) {
|
||||
var args = Utils.tokenizeCommandLine(appSettings.customCommand);
|
||||
ksession.setShellProgram(args[0]);
|
||||
ksession.setArgs(args.slice(1));
|
||||
} else if (!defaultCmd && appSettings.isMacOS) {
|
||||
// OSX Requires the following default parameters for auto login.
|
||||
ksession.setArgs(["-i", "-l"]);
|
||||
}
|
||||
|
||||
if (workdir)
|
||||
ksession.initialWorkingDirectory = workdir;
|
||||
|
||||
ksession.startShellProgram();
|
||||
forceActiveFocus();
|
||||
}
|
||||
Component.onCompleted: {
|
||||
appSettings.fontManager.terminalFontChanged.connect(handleFontChanged);
|
||||
appSettings.fontManager.refresh()
|
||||
startSession();
|
||||
}
|
||||
}
|
||||
Menu{
|
||||
id: contextmenu
|
||||
MenuItem{action: copyAction}
|
||||
MenuItem{action: pasteAction}
|
||||
MenuSeparator{visible: Qt.platform.os !== "osx"}
|
||||
MenuItem{action: fullscreenAction; visible: Qt.platform.os !== "osx"}
|
||||
MenuItem{action: showMenubarAction; visible: Qt.platform.os !== "osx"}
|
||||
MenuSeparator{visible: !shadersettings.showMenubar}
|
||||
CRTMainMenuBar{visible: !shadersettings.showMenubar}
|
||||
|
||||
Component {
|
||||
id: shortContextMenu
|
||||
ShortContextMenu { }
|
||||
}
|
||||
MouseArea{
|
||||
|
||||
Component {
|
||||
id: fullContextMenu
|
||||
FullContextMenu { }
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: menuLoader
|
||||
sourceComponent: (appSettings.isMacOS || appSettings.showMenubar ? shortContextMenu : fullContextMenu)
|
||||
}
|
||||
property alias contextmenu: menuLoader.item
|
||||
|
||||
MouseArea {
|
||||
property real margin: appSettings.margin
|
||||
property real frameSize: appSettings.frameSize * terminalWindow.normalizedWindowScale
|
||||
|
||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
||||
// This is incredibly ugly. All this file should be reorganized.
|
||||
width: (parent.width + dleft + dright) / shadersettings.window_scaling - dleft -dright
|
||||
height: (parent.height + dtop + dbottom) / shadersettings.window_scaling - dtop - dbottom
|
||||
onWheel:{
|
||||
if(wheel.modifiers & Qt.ControlModifier){
|
||||
anchors.fill: parent
|
||||
cursorShape: kterminal.terminalUsesMouse ? Qt.ArrowCursor : Qt.IBeamCursor
|
||||
onWheel: function(wheel) {
|
||||
if (wheel.modifiers & Qt.ControlModifier) {
|
||||
wheel.angleDelta.y > 0 ? zoomIn.trigger() : zoomOut.trigger();
|
||||
} else {
|
||||
var coord = correctDistortion(wheel.x, wheel.y);
|
||||
var lines = wheel.angleDelta.y > 0 ? -1 : 1;
|
||||
kterminal.scrollWheelEvent(coord, lines);
|
||||
kterminal.simulateWheel(coord.x, coord.y, wheel.buttons, wheel.modifiers, wheel.angleDelta);
|
||||
}
|
||||
}
|
||||
onDoubleClicked: {
|
||||
onDoubleClicked: function(mouse) {
|
||||
var coord = correctDistortion(mouse.x, mouse.y);
|
||||
kterminal.mouseDoubleClickEvent(coord, mouse.button, mouse.modifiers);
|
||||
kterminal.simulateMouseDoubleClick(coord.x, coord.y, mouse.button, mouse.buttons, mouse.modifiers);
|
||||
}
|
||||
onPressed: {
|
||||
if((!kterminal.usesMouse || mouse.modifiers & Qt.ShiftModifier) && mouse.button == Qt.RightButton) {
|
||||
onPressed: function(mouse) {
|
||||
kterminal.forceActiveFocus()
|
||||
if ((!kterminal.terminalUsesMouse || mouse.modifiers & Qt.ShiftModifier) && mouse.button == Qt.RightButton) {
|
||||
contextmenu.popup();
|
||||
} else {
|
||||
var coord = correctDistortion(mouse.x, mouse.y);
|
||||
kterminal.mousePressEvent(coord, mouse.button, mouse.modifiers)
|
||||
kterminal.simulateMousePress(coord.x, coord.y, mouse.button, mouse.buttons, mouse.modifiers)
|
||||
}
|
||||
}
|
||||
onReleased: {
|
||||
onReleased: function(mouse) {
|
||||
var coord = correctDistortion(mouse.x, mouse.y);
|
||||
kterminal.mouseReleaseEvent(coord, mouse.button, mouse.modifiers);
|
||||
kterminal.simulateMouseRelease(coord.x, coord.y, mouse.button, mouse.buttons, mouse.modifiers);
|
||||
}
|
||||
onPositionChanged: {
|
||||
onPositionChanged: function(mouse) {
|
||||
var coord = correctDistortion(mouse.x, mouse.y);
|
||||
kterminal.mouseMoveEvent(coord, mouse.button, mouse.buttons, mouse.modifiers);
|
||||
kterminal.simulateMouseMove(coord.x, coord.y, mouse.button, mouse.buttons, mouse.modifiers);
|
||||
}
|
||||
|
||||
function correctDistortion(x, y){
|
||||
x = x / width;
|
||||
y = y / height;
|
||||
function correctDistortion(x, y) {
|
||||
x = (x - margin) / width;
|
||||
y = (y - margin) / height;
|
||||
|
||||
x = x * (1 + frameSize * 2) - frameSize;
|
||||
y = y * (1 + frameSize * 2) - frameSize;
|
||||
|
||||
var cc = Qt.size(0.5 - x, 0.5 - y);
|
||||
var distortion = (cc.height * cc.height + cc.width * cc.width) * shadersettings.screen_distortion;
|
||||
var distortion = (cc.height * cc.height + cc.width * cc.width)
|
||||
* appSettings.screenCurvature * appSettings.screenCurvatureSize
|
||||
* terminalWindow.normalizedWindowScale;
|
||||
|
||||
return Qt.point((x - cc.width * (1+distortion) * distortion) * kterminal.width,
|
||||
(y - cc.height * (1+distortion) * distortion) * kterminal.height)
|
||||
return Qt.point((x - cc.width * (1+distortion) * distortion) * (kterminal.totalWidth),
|
||||
(y - cc.height * (1+distortion) * distortion) * (kterminal.totalHeight))
|
||||
}
|
||||
}
|
||||
ShaderEffectSource{
|
||||
id: kterminalSource
|
||||
sourceItem: kterminal
|
||||
hideSource: true
|
||||
wrapMode: ShaderEffectSource.ClampToEdge
|
||||
live: false
|
||||
|
||||
signal sourceUpdate
|
||||
|
||||
Connections{
|
||||
target: kterminal
|
||||
onUpdatedImage:{
|
||||
kterminalSource.scheduleUpdate();
|
||||
kterminalSource.sourceUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loader{
|
||||
id: blurredSourceLoader
|
||||
asynchronous: true
|
||||
active: mBlur !== 0
|
||||
|
||||
sourceComponent: ShaderEffectSource{
|
||||
id: _blurredSourceEffect
|
||||
sourceItem: blurredTerminalLoader.item
|
||||
recursive: true
|
||||
live: false
|
||||
hideSource: true
|
||||
wrapMode: kterminalSource.wrapMode
|
||||
|
||||
function restartBlurSource(){
|
||||
livetimer.restart();
|
||||
}
|
||||
|
||||
Timer{
|
||||
id: livetimer
|
||||
running: true
|
||||
onRunningChanged: {
|
||||
running ?
|
||||
timeBinding.target = timeManager :
|
||||
timeBinding.target = null
|
||||
}
|
||||
}
|
||||
Connections{
|
||||
id: timeBinding
|
||||
target: timeManager
|
||||
onTimeChanged: {
|
||||
_blurredSourceEffect.scheduleUpdate();
|
||||
}
|
||||
}
|
||||
Connections{
|
||||
target: kterminalSource
|
||||
onSourceUpdate:{
|
||||
livetimer.restart();
|
||||
}
|
||||
}
|
||||
Connections{
|
||||
target: shadersettings
|
||||
onScanline_qualityChanged: restartBlurredSource();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader{
|
||||
id: blurredTerminalLoader
|
||||
width: kterminalSource.textureSize.width
|
||||
height: kterminalSource.textureSize.height
|
||||
active: mBlur !== 0
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: ShaderEffect {
|
||||
property variant txt_source: kterminalSource
|
||||
property variant blurredSource: blurredSourceLoader.item
|
||||
property real blurCoefficient: (1.0 - motionBlurCoefficient) * fpsAttenuation
|
||||
|
||||
blending: false
|
||||
|
||||
fragmentShader:
|
||||
"uniform lowp float qt_Opacity;" +
|
||||
"uniform lowp sampler2D txt_source;" +
|
||||
|
||||
"varying highp vec2 qt_TexCoord0;
|
||||
|
||||
uniform lowp sampler2D blurredSource;
|
||||
uniform highp float blurCoefficient;" +
|
||||
|
||||
"float rgb2grey(vec3 v){
|
||||
return dot(v, vec3(0.21, 0.72, 0.04));
|
||||
}" +
|
||||
|
||||
"void main() {" +
|
||||
"vec2 coords = qt_TexCoord0;" +
|
||||
"vec3 color = texture2D(txt_source, coords).rgb * 256.0;" +
|
||||
|
||||
"vec3 blur_color = texture2D(blurredSource, coords).rgb * 256.0;" +
|
||||
"blur_color = blur_color - blur_color * blurCoefficient;" +
|
||||
"color = step(vec3(1.0), color) * color + step(color, vec3(1.0)) * blur_color;" +
|
||||
|
||||
"gl_FragColor = vec4(floor(color) / 256.0, 1.0);" +
|
||||
"}"
|
||||
|
||||
onStatusChanged: if (log) console.log(log) //Print warning messages
|
||||
}
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// EFFECTS //////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// BLOOM ////////////////////////////////////////////////////////////////
|
||||
|
||||
Loader{
|
||||
property real scaling: shadersettings.bloom_quality * shadersettings.window_scaling
|
||||
id: bloomEffectLoader
|
||||
active: mBloom != 0
|
||||
asynchronous: true
|
||||
width: parent.width * scaling
|
||||
height: parent.height * scaling
|
||||
sourceComponent: FastBlur{
|
||||
radius: 48 * scaling
|
||||
source: kterminal
|
||||
transparentBorder: true
|
||||
}
|
||||
}
|
||||
Loader{
|
||||
id: bloomSourceLoader
|
||||
active: mBloom != 0
|
||||
asynchronous: true
|
||||
sourceComponent: ShaderEffectSource{
|
||||
id: _bloomEffectSource
|
||||
sourceItem: bloomEffectLoader.item
|
||||
hideSource: true
|
||||
live: false
|
||||
smooth: true
|
||||
Connections{
|
||||
target: kterminalSource
|
||||
onSourceUpdate: _bloomEffectSource.scheduleUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOISE ////////////////////////////////////////////////////////////////
|
||||
|
||||
ShaderEffect {
|
||||
id: staticNoiseEffect
|
||||
anchors.fill: parent
|
||||
property real element_size: shadersettings.rasterization == shadersettings.no_rasterization ? 2 : 1
|
||||
property size virtual_resolution: Qt.size(kterminal.width / element_size, kterminal.height / element_size)
|
||||
|
||||
blending: false
|
||||
|
||||
fragmentShader:
|
||||
"uniform lowp float qt_Opacity;
|
||||
varying highp vec2 qt_TexCoord0;
|
||||
uniform highp vec2 virtual_resolution;" +
|
||||
|
||||
"highp float noise(vec2 co)
|
||||
{
|
||||
highp float a = 12.9898;
|
||||
highp float b = 78.233;
|
||||
highp float c = 43758.5453;
|
||||
highp float dt= dot(co.xy ,vec2(a,b));
|
||||
highp float sn= mod(dt,3.14);
|
||||
return fract(sin(sn) * c);
|
||||
}
|
||||
|
||||
vec2 sw(vec2 p) {return vec2( floor(p.x) , floor(p.y) );}
|
||||
vec2 se(vec2 p) {return vec2( ceil(p.x) , floor(p.y) );}
|
||||
vec2 nw(vec2 p) {return vec2( floor(p.x) , ceil(p.y) );}
|
||||
vec2 ne(vec2 p) {return vec2( ceil(p.x) , ceil(p.y) );}
|
||||
|
||||
float smoothNoise(vec2 p) {
|
||||
vec2 inter = smoothstep(0., 1., fract(p));
|
||||
float s = mix(noise(sw(p)), noise(se(p)), inter.x);
|
||||
float n = mix(noise(nw(p)), noise(ne(p)), inter.x);
|
||||
return mix(s, n, inter.y);
|
||||
}" +
|
||||
|
||||
"void main() {" +
|
||||
"gl_FragColor.a = smoothNoise(qt_TexCoord0 * virtual_resolution);" +
|
||||
"}"
|
||||
|
||||
onStatusChanged: if (log) console.log(log) //Print warning messages
|
||||
}
|
||||
ShaderEffectSource{
|
||||
id: staticNoiseSource
|
||||
sourceItem: staticNoiseEffect
|
||||
textureSize: Qt.size(parent.width, parent.height)
|
||||
wrapMode: ShaderEffectSource.Repeat
|
||||
smooth: true
|
||||
hideSource: true
|
||||
visible: false
|
||||
textureSize: Qt.size(kterminal.totalWidth * scaleTexture, kterminal.totalHeight * scaleTexture)
|
||||
sourceRect: Qt.rect(-kterminal.margin, -kterminal.margin, kterminal.totalWidth, kterminal.totalHeight)
|
||||
}
|
||||
|
||||
// RASTERIZATION //////////////////////////////////////////////////////////
|
||||
Item {
|
||||
id: burnInContainer
|
||||
|
||||
ShaderEffect {
|
||||
id: rasterizationEffect
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
property size virtual_resolution: Qt.size(kterminal.width, kterminal.height)
|
||||
property int burnInScaling: scaleTexture * appSettings.burnInQuality
|
||||
|
||||
blending: false
|
||||
width: Math.round(appSettings.lowResolutionFont
|
||||
? kterminal.totalWidth * Math.max(1, burnInScaling)
|
||||
: kterminal.totalWidth * scaleTexture * appSettings.burnInQuality)
|
||||
|
||||
fragmentShader:
|
||||
"uniform lowp float qt_Opacity;" +
|
||||
height: Math.round(appSettings.lowResolutionFont
|
||||
? kterminal.totalHeight * Math.max(1, burnInScaling)
|
||||
: kterminal.totalHeight * scaleTexture * appSettings.burnInQuality)
|
||||
|
||||
"varying highp vec2 qt_TexCoord0;
|
||||
uniform highp vec2 virtual_resolution;
|
||||
|
||||
highp float getScanlineIntensity(vec2 coords) {
|
||||
highp float result = 1.0;" +
|
||||
|
||||
(mScanlines != shadersettings.no_rasterization ?
|
||||
"result *= abs(sin(coords.y * virtual_resolution.y * "+Math.PI+"));" : "") +
|
||||
(mScanlines == shadersettings.pixel_rasterization ?
|
||||
"result *= abs(sin(coords.x * virtual_resolution.x * "+Math.PI+"));" : "") + "
|
||||
|
||||
return result;
|
||||
}" +
|
||||
|
||||
"void main() {" +
|
||||
"highp float color = getScanlineIntensity(qt_TexCoord0);" +
|
||||
|
||||
"float distance = length(vec2(0.5) - qt_TexCoord0);" +
|
||||
"color = mix(color, 0.0, 1.2 * distance * distance);" +
|
||||
|
||||
"gl_FragColor.a = color;" +
|
||||
"}"
|
||||
|
||||
onStatusChanged: if (log) console.log(log) //Print warning messages
|
||||
}
|
||||
ShaderEffectSource{
|
||||
id: rasterizationEffectSource
|
||||
sourceItem: rasterizationEffect
|
||||
hideSource: true
|
||||
smooth: true
|
||||
wrapMode: ShaderEffectSource.Repeat
|
||||
BurnInEffect {
|
||||
id: burnInEffect
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
165
app/qml/SettingsAdvancedTab.qml
Normal file
@@ -0,0 +1,165 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQml 2.0
|
||||
|
||||
import "Components"
|
||||
|
||||
ColumnLayout {
|
||||
GroupBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
title: qsTr("Command")
|
||||
padding: appSettings.defaultMargin
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
CheckBox {
|
||||
id: useCustomCommand
|
||||
text: qsTr("Use custom command instead of shell at startup")
|
||||
checked: appSettings.useCustomCommand
|
||||
onCheckedChanged: appSettings.useCustomCommand = checked
|
||||
}
|
||||
// Workaround for QTBUG-31627 for pre 5.3.0
|
||||
Binding {
|
||||
target: useCustomCommand
|
||||
property: "checked"
|
||||
value: appSettings.useCustomCommand
|
||||
}
|
||||
TextField {
|
||||
id: customCommand
|
||||
Layout.fillWidth: true
|
||||
text: appSettings.customCommand
|
||||
enabled: useCustomCommand.checked
|
||||
onEditingFinished: appSettings.customCommand = text
|
||||
|
||||
// Save text even if user forgets to press enter or unfocus
|
||||
function saveSetting() {
|
||||
appSettings.customCommand = text
|
||||
}
|
||||
Component.onCompleted: settings_window.closing.connect(
|
||||
saveSetting)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GroupBox {
|
||||
title: qsTr("Cursor")
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
padding: appSettings.defaultMargin
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
CheckBox {
|
||||
id: blinkingCursor
|
||||
text: qsTr("Blinking Cursor")
|
||||
checked: appSettings.blinkingCursor
|
||||
onCheckedChanged: appSettings.blinkingCursor = checked
|
||||
}
|
||||
Binding {
|
||||
target: blinkingCursor
|
||||
property: "checked"
|
||||
value: appSettings.blinkingCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GroupBox {
|
||||
title: qsTr("Performance")
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
padding: appSettings.defaultMargin
|
||||
GridLayout {
|
||||
anchors.fill: parent
|
||||
columns: 4
|
||||
|
||||
Label {
|
||||
text: qsTr("Effects FPS")
|
||||
}
|
||||
Slider {
|
||||
Layout.fillWidth: true
|
||||
Layout.columnSpan: 2
|
||||
id: effectsFpsSlider
|
||||
onValueChanged: appSettings.effectsFrameSkip = Math.round(value)
|
||||
stepSize: 1
|
||||
enabled: true
|
||||
from: 5
|
||||
to: 1
|
||||
value: appSettings.effectsFrameSkip
|
||||
}
|
||||
|
||||
SizedLabel {
|
||||
text: Math.round(100 / Math.max(1, Math.round(effectsFpsSlider.value))) + "%"
|
||||
}
|
||||
Label {
|
||||
text: qsTr("Texture Quality")
|
||||
}
|
||||
Slider {
|
||||
id: txtslider
|
||||
Layout.fillWidth: true
|
||||
Layout.columnSpan: 2
|
||||
onValueChanged: appSettings.windowScaling = value
|
||||
stepSize: 0.05
|
||||
enabled: true
|
||||
from: 0.25
|
||||
value: appSettings.windowScaling
|
||||
}
|
||||
SizedLabel {
|
||||
text: Math.round(txtslider.value * 100) + "%"
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Bloom Quality")
|
||||
}
|
||||
Slider {
|
||||
Layout.fillWidth: true
|
||||
Layout.columnSpan: 2
|
||||
id: bloomSlider
|
||||
onValueChanged: appSettings.bloomQuality = value
|
||||
stepSize: 0.05
|
||||
enabled: true
|
||||
from: 0.25
|
||||
value: appSettings.bloomQuality
|
||||
}
|
||||
SizedLabel {
|
||||
text: Math.round(bloomSlider.value * 100) + "%"
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("BurnIn Quality")
|
||||
}
|
||||
Slider {
|
||||
Layout.fillWidth: true
|
||||
id: burnInSlider
|
||||
Layout.columnSpan: 2
|
||||
onValueChanged: appSettings.burnInQuality = value
|
||||
stepSize: 0.05
|
||||
enabled: true
|
||||
from: 0.25
|
||||
value: appSettings.burnInQuality
|
||||
}
|
||||
SizedLabel {
|
||||
text: Math.round(burnInSlider.value * 100) + "%"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -17,68 +17,79 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
Tab{
|
||||
GroupBox{
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
spacing: 2
|
||||
|
||||
GroupBox {
|
||||
title: qsTr("Effects")
|
||||
anchors.fill: parent
|
||||
ColumnLayout{
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
padding: appSettings.defaultMargin
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
CheckableSlider{
|
||||
|
||||
CheckableSlider {
|
||||
name: qsTr("Bloom")
|
||||
onNewValue: shadersettings.bloom_strength = newValue
|
||||
value: shadersettings.bloom_strength
|
||||
onNewValue: function(newValue) { appSettings.bloom = newValue }
|
||||
value: appSettings.bloom
|
||||
}
|
||||
CheckableSlider{
|
||||
name: qsTr("Motion Blur")
|
||||
onNewValue: shadersettings.motion_blur = newValue
|
||||
value: shadersettings.motion_blur
|
||||
CheckableSlider {
|
||||
name: qsTr("BurnIn")
|
||||
onNewValue: function(newValue) { appSettings.burnIn = newValue }
|
||||
value: appSettings.burnIn
|
||||
}
|
||||
CheckableSlider{
|
||||
name: qsTr("Noise")
|
||||
onNewValue: shadersettings.noise_strength = newValue
|
||||
value: shadersettings.noise_strength
|
||||
CheckableSlider {
|
||||
name: qsTr("Static Noise")
|
||||
onNewValue: function(newValue) { appSettings.staticNoise = newValue }
|
||||
value: appSettings.staticNoise
|
||||
}
|
||||
CheckableSlider{
|
||||
CheckableSlider {
|
||||
name: qsTr("Jitter")
|
||||
onNewValue: shadersettings.jitter = newValue
|
||||
value: shadersettings.jitter
|
||||
onNewValue: function(newValue) { appSettings.jitter = newValue }
|
||||
value: appSettings.jitter
|
||||
}
|
||||
CheckableSlider{
|
||||
name: qsTr("Glow")
|
||||
onNewValue: shadersettings.glowing_line_strength = newValue;
|
||||
value: shadersettings.glowing_line_strength
|
||||
CheckableSlider {
|
||||
name: qsTr("Glow Line")
|
||||
onNewValue: function(newValue) { appSettings.glowingLine = newValue }
|
||||
value: appSettings.glowingLine
|
||||
}
|
||||
CheckableSlider{
|
||||
name: qsTr("Screen distortion")
|
||||
onNewValue: shadersettings.screen_distortion = newValue;
|
||||
value: shadersettings.screen_distortion;
|
||||
CheckableSlider {
|
||||
name: qsTr("Screen Curvature")
|
||||
onNewValue: function(newValue) { appSettings.screenCurvature = newValue }
|
||||
value: appSettings.screenCurvature
|
||||
}
|
||||
CheckableSlider{
|
||||
name: qsTr("Ambient light")
|
||||
onNewValue: shadersettings.ambient_light = newValue;
|
||||
value: shadersettings.ambient_light
|
||||
enabled: shadersettings.frames_index !== 0
|
||||
CheckableSlider {
|
||||
name: qsTr("Ambient Light")
|
||||
onNewValue: function(newValue) { appSettings.ambientLight = newValue }
|
||||
value: appSettings.ambientLight
|
||||
enabled: appSettings.framesIndex !== 0
|
||||
}
|
||||
CheckableSlider{
|
||||
name: qsTr("Brightness flickering")
|
||||
onNewValue: shadersettings.brightness_flickering = newValue;
|
||||
value: shadersettings.brightness_flickering;
|
||||
CheckableSlider {
|
||||
name: qsTr("Flickering")
|
||||
onNewValue: function(newValue) { appSettings.flickering = newValue }
|
||||
value: appSettings.flickering
|
||||
}
|
||||
CheckableSlider{
|
||||
name: qsTr("Horizontal flickering")
|
||||
onNewValue: shadersettings.horizontal_sincronization = newValue;
|
||||
value: shadersettings.horizontal_sincronization;
|
||||
CheckableSlider {
|
||||
name: qsTr("Horizontal Sync")
|
||||
onNewValue: function(newValue) { appSettings.horizontalSync = newValue }
|
||||
value: appSettings.horizontalSync
|
||||
}
|
||||
CheckableSlider{
|
||||
name: qsTr("RGB shift")
|
||||
onNewValue: shadersettings.rgb_shift = newValue;
|
||||
value: shadersettings.rgb_shift;
|
||||
enabled: shadersettings.chroma_color !== 0
|
||||
CheckableSlider {
|
||||
name: qsTr("RGB Shift")
|
||||
onNewValue: function(newValue) { appSettings.rbgShift = newValue }
|
||||
value: appSettings.rbgShift
|
||||
}
|
||||
CheckableSlider {
|
||||
name: qsTr("Frame Shininess")
|
||||
onNewValue: function(newValue) { appSettings._frameShininess = newValue }
|
||||
value: appSettings._frameShininess
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -17,93 +17,262 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs
|
||||
|
||||
Tab{
|
||||
ColumnLayout{
|
||||
anchors.fill: parent
|
||||
GroupBox{
|
||||
Layout.fillWidth: true
|
||||
title: qsTr("Profile")
|
||||
ColumnLayout{
|
||||
anchors.fill: parent
|
||||
ComboBox{
|
||||
id: profilesbox
|
||||
Layout.fillWidth: true
|
||||
model: shadersettings.profiles_list
|
||||
currentIndex: shadersettings.profiles_index
|
||||
}
|
||||
RowLayout{
|
||||
Layout.fillWidth: true
|
||||
Button{
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Load")
|
||||
onClicked: {
|
||||
shadersettings.profiles_index = profilesbox.currentIndex
|
||||
shadersettings.loadCurrentProfile();
|
||||
shadersettings.handleFontChanged();
|
||||
}
|
||||
}
|
||||
Button{
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Save New Profile")
|
||||
onClicked: insertname.show()
|
||||
}
|
||||
Button{
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Remove Selected")
|
||||
enabled: !shadersettings.profiles_list.get(profilesbox.currentIndex).builtin
|
||||
onClicked: {
|
||||
shadersettings.profiles_list.remove(profilesbox.currentIndex)
|
||||
profilesbox.currentIndex = profilesbox.currentIndex - 1
|
||||
ColumnLayout {
|
||||
GroupBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
title: qsTr("Profile")
|
||||
padding: appSettings.defaultMargin
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
ListView {
|
||||
id: profilesView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
model: appSettings.profilesList
|
||||
clip: true
|
||||
delegate: Rectangle {
|
||||
width: label.width
|
||||
height: label.height
|
||||
color: (index == profilesView.currentIndex) ? palette.highlight : palette.base
|
||||
Label {
|
||||
id: label
|
||||
text: appSettings.profilesList.get(index).text
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: profilesView.currentIndex = index
|
||||
onDoubleClicked: appSettings.loadProfile(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
InsertNameDialog{
|
||||
id: insertname
|
||||
onNameSelected: shadersettings.addNewCustomProfile(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
GroupBox{
|
||||
title: qsTr("Lights")
|
||||
Layout.fillWidth: true
|
||||
GridLayout{
|
||||
anchors.fill: parent
|
||||
columns: 2
|
||||
Text{ text: qsTr("Brightness") }
|
||||
SimpleSlider{
|
||||
onValueChanged: shadersettings.brightness = value
|
||||
value: shadersettings.brightness
|
||||
}
|
||||
Text{ text: qsTr("Contrast") }
|
||||
SimpleSlider{
|
||||
onValueChanged: shadersettings.contrast = value
|
||||
value: shadersettings.contrast
|
||||
}
|
||||
Text{ text: qsTr("Opacity") }
|
||||
SimpleSlider{
|
||||
onValueChanged: shadersettings.windowOpacity = value
|
||||
value: shadersettings.windowOpacity
|
||||
}
|
||||
}
|
||||
}
|
||||
GroupBox{
|
||||
title: qsTr("Frame")
|
||||
Layout.fillWidth: true
|
||||
RowLayout{
|
||||
anchors.fill: parent
|
||||
ComboBox{
|
||||
id: framescombobox
|
||||
ColumnLayout {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: false
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
model: shadersettings.frames_list
|
||||
currentIndex: shadersettings.frames_index
|
||||
onCurrentIndexChanged: shadersettings.frames_index = currentIndex
|
||||
text: qsTr("Save")
|
||||
onClicked: {
|
||||
insertname.profileName = ""
|
||||
insertname.show()
|
||||
}
|
||||
}
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
property alias currentIndex: profilesView.currentIndex
|
||||
enabled: currentIndex >= 0
|
||||
text: qsTr("Load")
|
||||
onClicked: {
|
||||
var index = currentIndex
|
||||
if (index >= 0)
|
||||
appSettings.loadProfile(index)
|
||||
}
|
||||
}
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Remove")
|
||||
property alias currentIndex: profilesView.currentIndex
|
||||
|
||||
enabled: currentIndex >= 0 && !appSettings.profilesList.get(
|
||||
currentIndex).builtin
|
||||
onClicked: {
|
||||
appSettings.profilesList.remove(currentIndex)
|
||||
profilesView.selection.clear()
|
||||
|
||||
// TODO This is a very ugly workaround. The view didn't update on Qt 5.3.2.
|
||||
profilesView.model = 0
|
||||
profilesView.model = appSettings.profilesList
|
||||
}
|
||||
}
|
||||
Item {
|
||||
// Spacing
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Import")
|
||||
onClicked: {
|
||||
fileDialog.selectExisting = true
|
||||
fileDialog.callBack = function (url) {
|
||||
loadFile(url)
|
||||
}
|
||||
fileDialog.open()
|
||||
}
|
||||
function loadFile(url) {
|
||||
try {
|
||||
if (appSettings.verbose)
|
||||
console.log("Loading file: " + url)
|
||||
|
||||
var profileObject = JSON.parse(fileIO.read(url))
|
||||
var name = profileObject.name
|
||||
|
||||
if (!name)
|
||||
throw "Profile doesn't have a name"
|
||||
|
||||
var version = profileObject.version
|
||||
!== undefined ? profileObject.version : 1
|
||||
if (version !== appSettings.profileVersion)
|
||||
throw "This profile is not supported on this version of CRT."
|
||||
|
||||
delete profileObject.name
|
||||
|
||||
appSettings.appendCustomProfile(name,
|
||||
JSON.stringify(
|
||||
profileObject))
|
||||
} catch (err) {
|
||||
messageDialog.text = qsTr(err)
|
||||
messageDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
Button {
|
||||
property alias currentIndex: profilesView.currentIndex
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: qsTr("Export")
|
||||
enabled: currentIndex >= 0 && !appSettings.profilesList.get(
|
||||
currentIndex).builtin
|
||||
onClicked: {
|
||||
fileDialog.selectExisting = false
|
||||
fileDialog.callBack = function (url) {
|
||||
storeFile(url)
|
||||
}
|
||||
fileDialog.open()
|
||||
}
|
||||
function storeFile(url) {
|
||||
try {
|
||||
var urlString = url.toString()
|
||||
|
||||
// Fix the extension if it's missing.
|
||||
var extension = urlString.substring(
|
||||
urlString.length - 5, urlString.length)
|
||||
var urlTail = (extension === ".json" ? "" : ".json")
|
||||
url += urlTail
|
||||
|
||||
if (true)
|
||||
console.log("Storing file: " + url)
|
||||
|
||||
var profileObject = appSettings.profilesList.get(
|
||||
currentIndex)
|
||||
var profileSettings = JSON.parse(
|
||||
profileObject.obj_string)
|
||||
profileSettings["name"] = profileObject.text
|
||||
profileSettings["version"] = appSettings.profileVersion
|
||||
|
||||
var result = fileIO.write(url, JSON.stringify(
|
||||
profileSettings,
|
||||
undefined, 2))
|
||||
if (!result)
|
||||
throw "The file could not be written."
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
messageDialog.text = qsTr(
|
||||
"There has been an error storing the file.")
|
||||
messageDialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GroupBox {
|
||||
title: qsTr("Screen")
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
padding: appSettings.defaultMargin
|
||||
GridLayout {
|
||||
anchors.fill: parent
|
||||
columns: 2
|
||||
Label {
|
||||
text: qsTr("Brightness")
|
||||
}
|
||||
SimpleSlider {
|
||||
onValueChanged: appSettings.brightness = value
|
||||
value: appSettings.brightness
|
||||
}
|
||||
Label {
|
||||
text: qsTr("Contrast")
|
||||
}
|
||||
SimpleSlider {
|
||||
onValueChanged: appSettings.contrast = value
|
||||
value: appSettings.contrast
|
||||
}
|
||||
Label {
|
||||
text: qsTr("Margin")
|
||||
}
|
||||
SimpleSlider {
|
||||
onValueChanged: appSettings._margin = value
|
||||
value: appSettings._margin
|
||||
}
|
||||
Label {
|
||||
text: qsTr("Radius")
|
||||
}
|
||||
SimpleSlider {
|
||||
onValueChanged: appSettings._screenRadius = value
|
||||
value: appSettings._screenRadius
|
||||
}
|
||||
Label {
|
||||
text: qsTr("Frame size")
|
||||
}
|
||||
SimpleSlider {
|
||||
onValueChanged: appSettings._frameSize = value
|
||||
value: appSettings._frameSize
|
||||
}
|
||||
Label {
|
||||
text: qsTr("Opacity")
|
||||
visible: !appSettings.isMacOS
|
||||
}
|
||||
SimpleSlider {
|
||||
onValueChanged: appSettings.windowOpacity = value
|
||||
value: appSettings.windowOpacity
|
||||
visible: !appSettings.isMacOS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DIALOGS ////////////////////////////////////////////////////////////////
|
||||
InsertNameDialog {
|
||||
id: insertname
|
||||
onNameSelected: {
|
||||
appSettings.appendCustomProfile(name,
|
||||
appSettings.composeProfileString())
|
||||
}
|
||||
}
|
||||
MessageDialog {
|
||||
id: messageDialog
|
||||
title: qsTr("File Error")
|
||||
buttons: MessageDialog.Ok
|
||||
onAccepted: {
|
||||
messageDialog.close()
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
property var callBack
|
||||
property bool selectExisting: false
|
||||
id: fileDialog
|
||||
|
||||
sourceComponent: FileDialog {
|
||||
nameFilters: ["Json files (*.json)"]
|
||||
fileMode: fileDialog.selectExisting ? FileDialog.OpenFile : FileDialog.SaveFile
|
||||
onAccepted: callBack(selectedFile)
|
||||
}
|
||||
|
||||
onSelectExistingChanged: reload()
|
||||
|
||||
function open() {
|
||||
item.open()
|
||||
}
|
||||
|
||||
function reload() {
|
||||
active = false
|
||||
active = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
Tab{
|
||||
ColumnLayout{
|
||||
anchors.fill: parent
|
||||
GroupBox{
|
||||
title: qsTr("General")
|
||||
Layout.fillWidth: true
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
GridLayout{
|
||||
anchors.fill: parent
|
||||
rows: 2
|
||||
columns: 3
|
||||
CheckBox{
|
||||
property int fps: checked ? slider.value : 0
|
||||
onFpsChanged: shadersettings.fps = fps
|
||||
checked: shadersettings.fps !== 0
|
||||
text: qsTr("Limit FPS")
|
||||
}
|
||||
Slider{
|
||||
id: slider
|
||||
Layout.fillWidth: true
|
||||
stepSize: 1
|
||||
maximumValue: 60
|
||||
minimumValue: 1
|
||||
enabled: shadersettings.fps !== 0
|
||||
value: shadersettings.fps !== 0 ? shadersettings.fps : 60
|
||||
}
|
||||
Text{text: slider.value}
|
||||
Text{text: qsTr("Texture Quality")}
|
||||
Slider{
|
||||
Layout.fillWidth: true
|
||||
id: txtslider
|
||||
onValueChanged: shadersettings.window_scaling = value;
|
||||
value: shadersettings.window_scaling
|
||||
stepSize: 0.10
|
||||
Component.onCompleted: minimumValue = 0.3 //Without this value gets set to 0.5
|
||||
}
|
||||
Text{text: Math.round(txtslider.value * 100) + "%"}
|
||||
}
|
||||
}
|
||||
GroupBox{
|
||||
title: qsTr("Rasterization")
|
||||
Layout.fillWidth: true
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
GridLayout{
|
||||
id: scanlineQualityContainer
|
||||
anchors.fill: parent
|
||||
columns: 3
|
||||
property alias valsIndex: scanlineQualitySlider.value
|
||||
property var vals: [4,3,2]
|
||||
property var valsStrings: [
|
||||
qsTr("Low"),
|
||||
qsTr("Medium"),
|
||||
qsTr("High")
|
||||
]
|
||||
|
||||
onValsIndexChanged: shadersettings.scanline_quality = vals[valsIndex];
|
||||
|
||||
Text{text: qsTr("Scanlines Quality")}
|
||||
Slider{
|
||||
id: scanlineQualitySlider
|
||||
Layout.fillWidth: true
|
||||
onValueChanged: parent.valsIndex = value;
|
||||
stepSize: 1
|
||||
Component.onCompleted: {
|
||||
minimumValue = 0;
|
||||
maximumValue = 2;
|
||||
value = parent.vals.indexOf(shadersettings.scanline_quality);
|
||||
}
|
||||
Connections{
|
||||
target: shadersettings
|
||||
onScanline_qualityChanged:
|
||||
scanlineQualityContainer.valsIndex = scanlineQualityContainer.vals.indexOf(shadersettings.scanline_quality);
|
||||
}
|
||||
}
|
||||
Text{
|
||||
text: parent.valsStrings[parent.valsIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
GroupBox{
|
||||
title: qsTr("Bloom")
|
||||
Layout.fillWidth: true
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
GridLayout{
|
||||
id: bloomQualityContainer
|
||||
anchors.fill: parent
|
||||
columns: 3
|
||||
property alias valsIndex: bloomQualitySlider.value
|
||||
property var vals: [0.25, 0.50, 1.00]
|
||||
property var valsStrings: [
|
||||
qsTr("Low"),
|
||||
qsTr("Medium"),
|
||||
qsTr("High")
|
||||
]
|
||||
|
||||
onValsIndexChanged: shadersettings.bloom_quality = vals[valsIndex];
|
||||
|
||||
Text{text: qsTr("Bloom Quality")}
|
||||
Slider{
|
||||
id: bloomQualitySlider
|
||||
Layout.fillWidth: true
|
||||
onValueChanged: parent.valsIndex = value;
|
||||
stepSize: 1
|
||||
Component.onCompleted: {
|
||||
minimumValue = 0;
|
||||
maximumValue = 2;
|
||||
value = parent.vals.indexOf(shadersettings.bloom_quality);
|
||||
}
|
||||
Connections{
|
||||
target: shadersettings
|
||||
onBloom_qualityChanged:
|
||||
bloomQualityContainer.valsIndex = bloomQualityContainer.vals.indexOf(shadersettings.bloom_quality);
|
||||
}
|
||||
}
|
||||
Text{
|
||||
text: parent.valsStrings[parent.valsIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
GroupBox{
|
||||
title: qsTr("Frame")
|
||||
Layout.fillWidth: true
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
CheckBox{
|
||||
checked: shadersettings._frameReflections
|
||||
text: qsTr("Frame Reflections")
|
||||
onCheckedChanged: shadersettings._frameReflections = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -17,125 +17,204 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls 2.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQml 2.0
|
||||
|
||||
Tab{
|
||||
ColumnLayout{
|
||||
anchors.fill: parent
|
||||
GroupBox{
|
||||
title: qsTr("Rasterization Mode")
|
||||
Layout.fillWidth: true
|
||||
import "Components"
|
||||
|
||||
ColumnLayout {
|
||||
GroupBox {
|
||||
title: qsTr("Font")
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
padding: appSettings.defaultMargin
|
||||
GridLayout {
|
||||
anchors.fill: parent
|
||||
columns: 2
|
||||
Label {
|
||||
text: qsTr("Source")
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
RadioButton {
|
||||
text: qsTr("Bundled")
|
||||
checked: appSettings.fontSource === appSettings.bundled_fonts
|
||||
onClicked: {
|
||||
appSettings.fontSource = appSettings.bundled_fonts
|
||||
}
|
||||
}
|
||||
RadioButton {
|
||||
text: qsTr("System")
|
||||
checked: appSettings.fontSource === appSettings.system_fonts
|
||||
onClicked: {
|
||||
appSettings.fontSource = appSettings.system_fonts
|
||||
}
|
||||
}
|
||||
}
|
||||
Label {
|
||||
text: qsTr("Rendering")
|
||||
enabled: appSettings.fontSource === appSettings.bundled_fonts
|
||||
}
|
||||
ComboBox {
|
||||
id: rasterizationBox
|
||||
id: renderingBox
|
||||
|
||||
property string selectedElement: model[currentIndex]
|
||||
anchors.fill: parent
|
||||
model: [qsTr("Default"), qsTr("Scanlines"), qsTr("Pixels")]
|
||||
currentIndex: shadersettings.rasterization
|
||||
|
||||
Layout.fillWidth: true
|
||||
model: [qsTr("Default"), qsTr("Scanlines"), qsTr("Pixels"), qsTr("Sub-Pixels"), qsTr("Modern")]
|
||||
currentIndex: appSettings.rasterization
|
||||
onCurrentIndexChanged: {
|
||||
shadersettings.rasterization = currentIndex
|
||||
fontChanger.updateIndex();
|
||||
appSettings.rasterization = currentIndex
|
||||
}
|
||||
enabled: appSettings.fontSource === appSettings.bundled_fonts
|
||||
}
|
||||
Label {
|
||||
text: qsTr("Name")
|
||||
}
|
||||
ComboBox {
|
||||
id: fontChanger
|
||||
Layout.fillWidth: true
|
||||
model: appSettings.filteredFontList
|
||||
textRole: "text"
|
||||
onActivated: {
|
||||
var font = appSettings.filteredFontList.get(currentIndex)
|
||||
|
||||
// If selecting a high-res font while not in Modern mode,
|
||||
// switch to Modern to render at full resolution.
|
||||
if (!font.lowResolutionFont && appSettings.rasterization !== appSettings.modern_rasterization) {
|
||||
appSettings.rasterization = appSettings.modern_rasterization
|
||||
}
|
||||
// If selecting a low-res font while in Modern mode, switch back to default.
|
||||
if (font.lowResolutionFont && appSettings.rasterization === appSettings.modern_rasterization) {
|
||||
appSettings.rasterization = appSettings.no_rasterization
|
||||
}
|
||||
|
||||
appSettings.fontName = font.name
|
||||
}
|
||||
function updateIndex() {
|
||||
for (var i = 0; i < appSettings.filteredFontList.count; i++) {
|
||||
var font = appSettings.filteredFontList.get(i)
|
||||
if (font.name === appSettings.fontName) {
|
||||
currentIndex = i
|
||||
return
|
||||
}
|
||||
}
|
||||
currentIndex = 0
|
||||
}
|
||||
Connections {
|
||||
target: appSettings.fontManager
|
||||
|
||||
onTerminalFontChanged: {
|
||||
fontChanger.updateIndex()
|
||||
}
|
||||
|
||||
onFilteredFontListChanged: {
|
||||
fontChanger.updateIndex()
|
||||
}
|
||||
}
|
||||
Component.onCompleted: updateIndex()
|
||||
}
|
||||
Label {
|
||||
text: qsTr("Scaling")
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Slider {
|
||||
Layout.fillWidth: true
|
||||
id: fontScalingChanger
|
||||
onValueChanged: appSettings.fontScaling = value
|
||||
value: appSettings.fontScaling
|
||||
stepSize: 0.05
|
||||
from: appSettings.minimumFontScaling
|
||||
to: appSettings.maximumFontScaling
|
||||
}
|
||||
SizedLabel {
|
||||
text: Math.round(fontScalingChanger.value * 100) + "%"
|
||||
}
|
||||
}
|
||||
Label {
|
||||
text: qsTr("Font Width")
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Slider {
|
||||
Layout.fillWidth: true
|
||||
id: widthChanger
|
||||
onValueChanged: appSettings.fontWidth = value
|
||||
value: appSettings.fontWidth
|
||||
stepSize: 0.05
|
||||
from: 0.5
|
||||
to: 1.5
|
||||
}
|
||||
SizedLabel {
|
||||
text: Math.round(widthChanger.value * 100) + "%"
|
||||
}
|
||||
}
|
||||
Label {
|
||||
text: qsTr("Line Spacing")
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Slider {
|
||||
Layout.fillWidth: true
|
||||
id: lineSpacingChanger
|
||||
onValueChanged: appSettings.lineSpacing = value
|
||||
value: appSettings.lineSpacing
|
||||
stepSize: 0.01
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
}
|
||||
SizedLabel {
|
||||
text: Math.round(lineSpacingChanger.value * 100) + "%"
|
||||
}
|
||||
}
|
||||
}
|
||||
GroupBox{
|
||||
title: qsTr("Font") + " (" + rasterizationBox.selectedElement + ")"
|
||||
Layout.fillWidth: true
|
||||
GridLayout{
|
||||
anchors.fill: parent
|
||||
columns: 2
|
||||
Text{ text: qsTr("Name") }
|
||||
ComboBox{
|
||||
id: fontChanger
|
||||
Layout.fillWidth: true
|
||||
model: shadersettings.fontlist
|
||||
currentIndex: updateIndex()
|
||||
onActivated: {
|
||||
shadersettings.fontIndexes[shadersettings.rasterization] = index;
|
||||
shadersettings.handleFontChanged();
|
||||
}
|
||||
function updateIndex(){
|
||||
currentIndex = shadersettings.fontIndexes[shadersettings.rasterization];
|
||||
}
|
||||
}
|
||||
GroupBox {
|
||||
title: qsTr("Colors")
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
padding: appSettings.defaultMargin
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
CheckableSlider {
|
||||
name: qsTr("Chroma Color")
|
||||
onNewValue: function(newValue) { appSettings.chromaColor = newValue }
|
||||
value: appSettings.chromaColor
|
||||
}
|
||||
Text{ text: qsTr("Scaling") }
|
||||
RowLayout{
|
||||
Layout.fillWidth: true
|
||||
Slider{
|
||||
Layout.fillWidth: true
|
||||
id: fontScalingChanger
|
||||
onValueChanged: if(enabled) shadersettings.fontScaling = value
|
||||
stepSize: 0.05
|
||||
enabled: false // Another trick to fix initial bad behavior.
|
||||
Component.onCompleted: {
|
||||
minimumValue = 0.5;
|
||||
maximumValue = 2.5;
|
||||
value = shadersettings.fontScaling;
|
||||
enabled = true;
|
||||
}
|
||||
Connections{
|
||||
target: shadersettings
|
||||
onFontScalingChanged: fontScalingChanger.value = shadersettings.fontScaling;
|
||||
}
|
||||
}
|
||||
Text{
|
||||
text: Math.round(fontScalingChanger.value * 100) + "%"
|
||||
}
|
||||
}
|
||||
Text{ text: qsTr("Font Width") }
|
||||
RowLayout{
|
||||
Layout.fillWidth: true
|
||||
Slider{
|
||||
Layout.fillWidth: true
|
||||
id: widthChanger
|
||||
onValueChanged: shadersettings.fontWidth = value;
|
||||
value: shadersettings.fontWidth
|
||||
stepSize: 0.05
|
||||
Component.onCompleted: minimumValue = 0.5 //Without this value gets set to 0.5
|
||||
}
|
||||
Text{
|
||||
text: Math.round(widthChanger.value * 100) + "%"
|
||||
}
|
||||
CheckableSlider {
|
||||
name: qsTr("Saturation Color")
|
||||
onNewValue: function(newValue) { appSettings.saturationColor = newValue }
|
||||
value: appSettings.saturationColor
|
||||
enabled: appSettings.chromaColor !== 0
|
||||
}
|
||||
}
|
||||
}
|
||||
GroupBox{
|
||||
title: qsTr("Colors")
|
||||
Layout.fillWidth: true
|
||||
ColumnLayout{
|
||||
anchors.fill: parent
|
||||
RowLayout{
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
ColorButton {
|
||||
name: qsTr("Font")
|
||||
height: 50
|
||||
Layout.fillWidth: true
|
||||
ColorButton{
|
||||
name: qsTr("Font")
|
||||
height: 50
|
||||
Layout.fillWidth: true
|
||||
onColorSelected: shadersettings._font_color = color;
|
||||
button_color: shadersettings._font_color
|
||||
}
|
||||
ColorButton{
|
||||
name: qsTr("Background")
|
||||
height: 50
|
||||
Layout.fillWidth: true
|
||||
onColorSelected: shadersettings._background_color = color;
|
||||
button_color: shadersettings._background_color
|
||||
}
|
||||
onColorSelected: appSettings._fontColor = color
|
||||
color: appSettings._fontColor
|
||||
}
|
||||
ColumnLayout{
|
||||
ColorButton {
|
||||
name: qsTr("Background")
|
||||
height: 50
|
||||
Layout.fillWidth: true
|
||||
CheckableSlider{
|
||||
name: qsTr("Chroma Color")
|
||||
onNewValue: shadersettings.chroma_color = newValue
|
||||
value: shadersettings.chroma_color
|
||||
}
|
||||
CheckableSlider{
|
||||
name: qsTr("Saturation Color")
|
||||
onNewValue: shadersettings.saturation_color = newValue
|
||||
value: shadersettings.saturation_color
|
||||
enabled: shadersettings.chroma_color !== 0
|
||||
}
|
||||
onColorSelected: appSettings._backgroundColor = color
|
||||
color: appSettings._backgroundColor
|
||||
}
|
||||
ColorButton {
|
||||
name: qsTr("Frame")
|
||||
height: 50
|
||||
Layout.fillWidth: true
|
||||
onColorSelected: appSettings._frameColor = color
|
||||
color: appSettings._frameColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -19,46 +19,58 @@
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls 2.1
|
||||
import QtQuick.Window 2.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.1
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Dialogs
|
||||
|
||||
ApplicationWindow {
|
||||
readonly property real tabButtonPadding: 10
|
||||
|
||||
Window {
|
||||
id: settings_window
|
||||
title: qsTr("Settings")
|
||||
width: 640
|
||||
height: 440
|
||||
height: 520
|
||||
|
||||
property int tabmargins: 15
|
||||
Item {
|
||||
anchors { fill: parent; }
|
||||
|
||||
TabView{
|
||||
id: tabView
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
SettingsGeneralTab{
|
||||
id: generalTab
|
||||
title: qsTr("General")
|
||||
anchors.fill: parent
|
||||
anchors.margins: tabmargins
|
||||
TabBar {
|
||||
id: bar
|
||||
anchors { left: parent.left; right: parent.right; top: parent.top; }
|
||||
TabButton {
|
||||
padding: tabButtonPadding
|
||||
text: qsTr("General")
|
||||
}
|
||||
TabButton {
|
||||
padding: tabButtonPadding
|
||||
text: qsTr("Terminal")
|
||||
}
|
||||
TabButton {
|
||||
padding: tabButtonPadding
|
||||
text: qsTr("Effects")
|
||||
}
|
||||
TabButton {
|
||||
padding: tabButtonPadding
|
||||
text: qsTr("Advanced")
|
||||
}
|
||||
}
|
||||
SettingsTerminalTab{
|
||||
id: terminalTab
|
||||
title: qsTr("Terminal")
|
||||
anchors.fill: parent
|
||||
anchors.margins: tabmargins
|
||||
}
|
||||
SettingsEffectsTab{
|
||||
id: effectsTab
|
||||
title: qsTr("Effects")
|
||||
anchors.fill: parent
|
||||
anchors.margins: tabmargins
|
||||
}
|
||||
SettingsPerformanceTab{
|
||||
id: performanceTab
|
||||
title: qsTr("Performance")
|
||||
anchors.fill: parent
|
||||
anchors.margins: tabmargins
|
||||
|
||||
StackLayout {
|
||||
anchors {
|
||||
top: bar.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
margins: 16
|
||||
}
|
||||
|
||||
currentIndex: bar.currentIndex
|
||||
|
||||
SettingsGeneralTab { }
|
||||
SettingsTerminalTab { }
|
||||
SettingsEffectsTab { }
|
||||
SettingsAdvancedTab { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -19,259 +19,182 @@
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import "utils.js" as Utils
|
||||
|
||||
ShaderEffect {
|
||||
property color font_color: shadersettings.font_color
|
||||
property color background_color: shadersettings.background_color
|
||||
property variant source: terminal.theSource
|
||||
property variant bloomSource: terminal.bloomSource
|
||||
property variant rasterizationSource: terminal.rasterizationSource
|
||||
property variant noiseSource: terminal.staticNoiseSource
|
||||
property real bloom_strength: shadersettings.bloom_strength * 2.5
|
||||
|
||||
property real jitter: shadersettings.jitter * 0.007
|
||||
|
||||
property real noise_strength: shadersettings.noise_strength
|
||||
property real screen_distorsion: shadersettings.screen_distortion
|
||||
property real glowing_line_strength: shadersettings.glowing_line_strength
|
||||
|
||||
property real chroma_color: shadersettings.chroma_color;
|
||||
|
||||
property real rgb_shift: shadersettings.rgb_shift * 0.2
|
||||
|
||||
property real brightness_flickering: shadersettings.brightness_flickering
|
||||
property real horizontal_sincronization: shadersettings.horizontal_sincronization
|
||||
|
||||
property bool frameReflections: shadersettings.frameReflections
|
||||
|
||||
property real disp_top: (frame.item.displacementTop * shadersettings.window_scaling) / height
|
||||
property real disp_bottom: (frame.item.displacementBottom * shadersettings.window_scaling) / height
|
||||
property real disp_left: (frame.item.displacementLeft * shadersettings.window_scaling) / width
|
||||
property real disp_right: (frame.item.displacementRight * shadersettings.window_scaling) / width
|
||||
|
||||
property real screen_brightness: shadersettings.brightness * 1.5 + 0.5
|
||||
|
||||
property real time: timeManager.time
|
||||
property variant randomFunctionSource: randfuncsource
|
||||
|
||||
// If something goes wrong activate the fallback version of the shader.
|
||||
property bool fallBack: false
|
||||
|
||||
blending: false
|
||||
|
||||
//Smooth random texture used for flickering effect.
|
||||
Image{
|
||||
id: randtexture
|
||||
source: "frames/images/randfunction.png"
|
||||
width: 512
|
||||
height: 512
|
||||
sourceSize.width: 512
|
||||
sourceSize.height: 256
|
||||
fillMode: Image.TileVertically
|
||||
Item {
|
||||
function dynamicFragmentPath() {
|
||||
var rasterMode = appSettings.rasterization;
|
||||
var burnInOn = appSettings.burnIn > 0 ? 1 : 0;
|
||||
var frameOn = appSettings.frameEnabled ? 1 : 0;
|
||||
var chromaOn = appSettings.chromaColor > 0 ? 1 : 0;
|
||||
return "qrc:/shaders/terminal_dynamic_raster" + rasterMode +
|
||||
"_burn" + burnInOn +
|
||||
"_frame" + frameOn +
|
||||
"_chroma" + chromaOn +
|
||||
".frag.qsb";
|
||||
}
|
||||
ShaderEffectSource{
|
||||
id: randfuncsource
|
||||
sourceItem: randtexture
|
||||
live: false
|
||||
|
||||
function staticFragmentPath() {
|
||||
var rgbShiftOn = appSettings.rbgShift > 0 ? 1 : 0;
|
||||
var bloomOn = appSettings.bloom > 0 ? 1 : 0;
|
||||
var curvatureOn = (appSettings.screenCurvature > 0 || appSettings.frameSize > 0) ? 1 : 0;
|
||||
var shineOn = appSettings.frameShininess > 0 ? 1 : 0;
|
||||
return "qrc:/shaders/terminal_static_rgb" + rgbShiftOn +
|
||||
"_bloom" + bloomOn +
|
||||
"_curve" + curvatureOn +
|
||||
"_shine" + shineOn +
|
||||
".frag.qsb";
|
||||
}
|
||||
|
||||
property ShaderEffectSource source
|
||||
property BurnInEffect burnInEffect
|
||||
property ShaderEffectSource bloomSource
|
||||
|
||||
property color fontColor: appSettings.fontColor
|
||||
property color backgroundColor: appSettings.backgroundColor
|
||||
|
||||
property real screenCurvature: appSettings.screenCurvature * appSettings.screenCurvatureSize * terminalWindow.normalizedWindowScale
|
||||
property real frameSize: appSettings.frameSize * terminalWindow.normalizedWindowScale
|
||||
|
||||
property real chromaColor: appSettings.chromaColor
|
||||
|
||||
property real ambientLight: appSettings.ambientLight * 0.2
|
||||
|
||||
property size virtualResolution
|
||||
property size screenResolution
|
||||
|
||||
property real _screenDensity: Math.min(
|
||||
screenResolution.width / virtualResolution.width,
|
||||
screenResolution.height / virtualResolution.height
|
||||
)
|
||||
|
||||
ShaderEffect {
|
||||
id: dynamicShader
|
||||
|
||||
property ShaderEffectSource screenBuffer: frameBuffer
|
||||
property ShaderEffectSource burnInSource: burnInEffect.effectSource
|
||||
property ShaderEffectSource frameSource: terminalFrameLoader.item
|
||||
|
||||
property color fontColor: parent.fontColor
|
||||
property color backgroundColor: parent.backgroundColor
|
||||
property real screenCurvature: parent.screenCurvature
|
||||
property real chromaColor: parent.chromaColor
|
||||
property real ambientLight: parent.ambientLight
|
||||
|
||||
property real flickering: appSettings.flickering
|
||||
property real horizontalSync: appSettings.horizontalSync
|
||||
property real horizontalSyncStrength: Utils.lint(0.05, 0.35, horizontalSync)
|
||||
property real glowingLine: appSettings.glowingLine * 0.2
|
||||
|
||||
// Fast burnin properties
|
||||
property real burnIn: appSettings.burnIn
|
||||
property real burnInLastUpdate: burnInEffect.lastUpdate
|
||||
property real burnInTime: burnInEffect.burnInFadeTime
|
||||
|
||||
property real jitter: appSettings.jitter
|
||||
property size jitterDisplacement: Qt.size(0.007 * jitter, 0.002 * jitter)
|
||||
property real staticNoise: appSettings.staticNoise
|
||||
property size scaleNoiseSize: Qt.size((width * 0.75) / (noiseTexture.width * appSettings.windowScaling * appSettings.totalFontScaling),
|
||||
(height * 0.75) / (noiseTexture.height * appSettings.windowScaling * appSettings.totalFontScaling))
|
||||
|
||||
property size virtualResolution: parent.virtualResolution
|
||||
|
||||
// Rasterization might display oversamping issues if virtual resolution is close to physical display resolution.
|
||||
// We progressively disable rasterization from 4x up to 2x resolution.
|
||||
property real rasterizationIntensity: Utils.smoothstep(2.0, 4.0, _screenDensity)
|
||||
|
||||
property real time: timeManager ? timeManager.time : 0
|
||||
property ShaderEffectSource noiseSource: noiseShaderSource
|
||||
|
||||
property real frameSize: parent.frameSize
|
||||
property real frameShininess: appSettings.frameShininess
|
||||
property real bloom: parent.bloomSource ? appSettings.bloom * 2.5 : 0
|
||||
|
||||
anchors.fill: parent
|
||||
blending: false
|
||||
|
||||
Image {
|
||||
id: noiseTexture
|
||||
source: "images/allNoise512.png"
|
||||
width: 512
|
||||
height: 512
|
||||
fillMode: Image.Tile
|
||||
visible: false
|
||||
}
|
||||
ShaderEffectSource {
|
||||
id: noiseShaderSource
|
||||
sourceItem: noiseTexture
|
||||
wrapMode: ShaderEffectSource.Repeat
|
||||
visible: false
|
||||
smooth: true
|
||||
}
|
||||
|
||||
vertexShader: "qrc:/shaders/terminal_dynamic.vert.qsb"
|
||||
fragmentShader: dynamicFragmentPath()
|
||||
|
||||
onStatusChanged: if (log) console.log(log)
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: terminalFrameLoader
|
||||
|
||||
active: appSettings.frameEnabled
|
||||
|
||||
width: staticShader.width
|
||||
height: staticShader.height
|
||||
|
||||
sourceComponent: ShaderEffectSource {
|
||||
|
||||
sourceItem: terminalFrame
|
||||
hideSource: true
|
||||
visible: false
|
||||
format: ShaderEffectSource.RGBA
|
||||
|
||||
TerminalFrame {
|
||||
id: terminalFrame
|
||||
blending: false
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShaderEffect {
|
||||
id: staticShader
|
||||
|
||||
width: parent.width * appSettings.windowScaling
|
||||
height: parent.height * appSettings.windowScaling
|
||||
|
||||
property ShaderEffectSource source: parent.source
|
||||
property ShaderEffectSource bloomSource: parent.bloomSource
|
||||
|
||||
property color fontColor: parent.fontColor
|
||||
property color backgroundColor: parent.backgroundColor
|
||||
property real bloom: bloomSource ? appSettings.bloom * 2.5 : 0
|
||||
|
||||
property real screenCurvature: parent.screenCurvature
|
||||
|
||||
property real chromaColor: appSettings.chromaColor;
|
||||
|
||||
property real rbgShift: (appSettings.rbgShift / width) * appSettings.totalFontScaling
|
||||
|
||||
property real screen_brightness: Utils.lint(0.5, 1.5, appSettings.brightness)
|
||||
property real frameShininess: appSettings.frameShininess
|
||||
property real frameSize: parent.frameSize
|
||||
|
||||
blending: false
|
||||
visible: false
|
||||
|
||||
vertexShader: "qrc:/shaders/terminal_static.vert.qsb"
|
||||
fragmentShader: staticFragmentPath()
|
||||
|
||||
onStatusChanged: if (log) console.log(log)
|
||||
}
|
||||
|
||||
ShaderEffectSource {
|
||||
id: frameBuffer
|
||||
visible: false
|
||||
sourceItem: staticShader
|
||||
hideSource: true
|
||||
wrapMode: ShaderEffectSource.Repeat
|
||||
}
|
||||
|
||||
//Print the number with a reasonable precision for the shader.
|
||||
function str(num){
|
||||
return num.toFixed(8);
|
||||
}
|
||||
|
||||
vertexShader: "
|
||||
uniform highp mat4 qt_Matrix;
|
||||
uniform highp float time;
|
||||
|
||||
uniform highp float disp_left;
|
||||
uniform highp float disp_right;
|
||||
uniform highp float disp_top;
|
||||
uniform highp float disp_bottom;
|
||||
|
||||
attribute highp vec4 qt_Vertex;
|
||||
attribute highp vec2 qt_MultiTexCoord0;
|
||||
|
||||
varying highp vec2 qt_TexCoord0;" +
|
||||
|
||||
(!fallBack ? "
|
||||
uniform sampler2D randomFunctionSource;" : "") +
|
||||
|
||||
(!fallBack && brightness_flickering !== 0.0 ?"
|
||||
varying lowp float brightness;
|
||||
uniform lowp float brightness_flickering;" : "") +
|
||||
(!fallBack && horizontal_sincronization !== 0.0 ?"
|
||||
varying lowp float horizontal_distortion;
|
||||
uniform lowp float horizontal_sincronization;" : "") +
|
||||
"
|
||||
void main() {
|
||||
qt_TexCoord0.x = (qt_MultiTexCoord0.x - disp_left) / (1.0 - disp_left - disp_right);
|
||||
qt_TexCoord0.y = (qt_MultiTexCoord0.y - disp_top) / (1.0 - disp_top - disp_bottom);
|
||||
vec2 coords = vec2(fract(time/(1024.0*2.0)), fract(time/(1024.0*1024.0)));" +
|
||||
(!fallBack && brightness_flickering !== 0.0 ? "
|
||||
brightness = 1.0 + (texture2D(randomFunctionSource, coords).g - 0.5) * brightness_flickering;"
|
||||
: "") +
|
||||
|
||||
(!fallBack && horizontal_sincronization !== 0.0 ? "
|
||||
float randval = 1.5 * texture2D(randomFunctionSource,(vec2(1.0) -coords) * 0.5).g;
|
||||
float negsinc = 1.0 - 0.6 * horizontal_sincronization;" + "
|
||||
horizontal_distortion = step(negsinc, randval) * (randval - negsinc) * 0.3*horizontal_sincronization;"
|
||||
: "") +
|
||||
|
||||
"gl_Position = qt_Matrix * qt_Vertex;
|
||||
}"
|
||||
|
||||
fragmentShader: "
|
||||
uniform sampler2D source;
|
||||
uniform highp float qt_Opacity;
|
||||
uniform highp float time;
|
||||
varying highp vec2 qt_TexCoord0;
|
||||
|
||||
uniform highp vec4 font_color;
|
||||
uniform highp vec4 background_color;
|
||||
uniform highp sampler2D rasterizationSource;
|
||||
uniform lowp float screen_brightness;" +
|
||||
|
||||
(bloom_strength !== 0 ? "
|
||||
uniform highp sampler2D bloomSource;
|
||||
uniform lowp float bloom_strength;" : "") +
|
||||
(noise_strength !== 0 ? "
|
||||
uniform highp float noise_strength;" : "") +
|
||||
(noise_strength !== 0 || jitter !== 0 || rgb_shift ? "
|
||||
uniform lowp sampler2D noiseSource;" : "") +
|
||||
(screen_distorsion !== 0 ? "
|
||||
uniform highp float screen_distorsion;" : "") +
|
||||
(glowing_line_strength !== 0 ? "
|
||||
uniform highp float glowing_line_strength;" : "") +
|
||||
(chroma_color !== 0 ? "
|
||||
uniform lowp float chroma_color;" : "") +
|
||||
(jitter !== 0 ? "
|
||||
uniform lowp float jitter;" : "") +
|
||||
(rgb_shift !== 0 ? "
|
||||
uniform lowp float rgb_shift;" : "") +
|
||||
|
||||
(fallBack && (brightness_flickering || horizontal_sincronization) ? "
|
||||
uniform lowp sampler2D randomFunctionSource;" : "") +
|
||||
(fallBack && horizontal_sincronization !== 0 ? "
|
||||
uniform lowp float horizontal_sincronization;" : "") +
|
||||
(fallBack && brightness_flickering !== 0.0 ?"
|
||||
uniform lowp float brightness_flickering;" : "") +
|
||||
(!fallBack && brightness_flickering !== 0 ? "
|
||||
varying lowp float brightness;" : "") +
|
||||
(!fallBack && horizontal_sincronization !== 0 ? "
|
||||
varying lowp float horizontal_distortion;" : "") +
|
||||
|
||||
(glowing_line_strength !== 0 ? "
|
||||
float randomPass(vec2 coords){
|
||||
return fract(smoothstep(-0.2, 0.0, coords.y - 3.0 * fract(time * 0.0001))) * glowing_line_strength;
|
||||
}" : "") +
|
||||
|
||||
"float rgb2grey(vec3 v){
|
||||
return dot(v, vec3(0.21, 0.72, 0.04));
|
||||
}" +
|
||||
|
||||
"void main() {" +
|
||||
"vec2 cc = vec2(0.5) - qt_TexCoord0;" +
|
||||
"float distance = length(cc);" +
|
||||
|
||||
//FallBack if there are problem
|
||||
(fallBack && (brightness_flickering || horizontal_sincronization) ? "
|
||||
vec2 randCoords = vec2(fract(time/(1024.0*2.0)), fract(time/(1024.0*1024.0)));" : "") +
|
||||
|
||||
(fallBack && brightness_flickering !== 0.0 ? "
|
||||
float brightness = 1.0 + (texture2D(randomFunctionSource, randCoords).g - 0.5) * brightness_flickering;"
|
||||
: "") +
|
||||
|
||||
(fallBack && horizontal_sincronization !== 0.0 ? "
|
||||
float randval = 1.5 * texture2D(randomFunctionSource,(vec2(1.0) - randCoords) * 0.5).g;
|
||||
float negsinc = 1.0 - 0.6 * horizontal_sincronization;" + "
|
||||
float horizontal_distortion = step(negsinc, randval) * (randval - negsinc) * 0.3*horizontal_sincronization;"
|
||||
: "") +
|
||||
|
||||
(noise_strength ? "
|
||||
float noise = noise_strength;" : "") +
|
||||
|
||||
(screen_distorsion !== 0 ? "
|
||||
float distortion = dot(cc, cc) * screen_distorsion;
|
||||
vec2 coords = (qt_TexCoord0 - cc * (1.0 + distortion) * distortion);"
|
||||
:"
|
||||
vec2 coords = qt_TexCoord0;") +
|
||||
|
||||
(horizontal_sincronization !== 0 ? "
|
||||
float h_distortion = 0.5 * sin(time*0.001 + coords.y*10.0*fract(time/10.0));
|
||||
h_distortion += 0.5 * cos(time*0.04 + 0.03 + coords.y*50.0*fract(time/10.0 + 0.4));
|
||||
coords.x = coords.x + h_distortion * horizontal_distortion;" +
|
||||
(noise_strength ? "
|
||||
noise += horizontal_distortion;" : "")
|
||||
: "") +
|
||||
|
||||
(jitter !== 0 ? "
|
||||
vec2 offset = vec2(texture2D(noiseSource, coords + fract(time / 57.0)).a,
|
||||
texture2D(noiseSource, coords + fract(time / 251.0)).a) - 0.5;
|
||||
vec2 txt_coords = coords + offset * jitter;"
|
||||
: "vec2 txt_coords = coords;") +
|
||||
|
||||
"float color = 0.0;" +
|
||||
|
||||
(noise_strength !== 0 ? "
|
||||
float noiseVal = texture2D(noiseSource, qt_TexCoord0 + vec2(fract(time / 51.0), fract(time / 237.0))).a;
|
||||
color += noiseVal * noise * (1.0 - distance * 1.3);" : "") +
|
||||
|
||||
(glowing_line_strength !== 0 ? "
|
||||
color += randomPass(coords) * glowing_line_strength;" : "") +
|
||||
|
||||
|
||||
"vec3 txt_color = texture2D(source, txt_coords).rgb;
|
||||
float greyscale_color = rgb2grey(txt_color) + color;" +
|
||||
|
||||
(chroma_color !== 0 ?
|
||||
(rgb_shift !== 0 ? "
|
||||
float rgb_noise = abs(texture2D(noiseSource, vec2(fract(time/(1024.0 * 256.0)), fract(time/(1024.0*1024.0)))).a - 0.5);
|
||||
float rcolor = texture2D(source, txt_coords + vec2(0.1, 0.0) * rgb_shift * rgb_noise).r;
|
||||
float bcolor = texture2D(source, txt_coords - vec2(0.1, 0.0) * rgb_shift * rgb_noise).b;
|
||||
txt_color.r = rcolor;
|
||||
txt_color.b = bcolor;
|
||||
greyscale_color = 0.33 * (rcolor + bcolor);" : "") +
|
||||
|
||||
"vec3 mixedColor = mix(font_color.rgb, txt_color * font_color.rgb, chroma_color);
|
||||
vec3 finalBackColor = mix(background_color.rgb, mixedColor, greyscale_color);
|
||||
vec3 finalColor = mix(finalBackColor, font_color.rgb, color).rgb;"
|
||||
:
|
||||
"vec3 finalColor = mix(background_color.rgb, font_color.rgb, greyscale_color);") +
|
||||
|
||||
"finalColor *= texture2D(rasterizationSource, coords).a;" +
|
||||
|
||||
(bloom_strength !== 0 ?
|
||||
"vec4 bloomFullColor = texture2D(bloomSource, coords);
|
||||
vec3 bloomColor = bloomFullColor.rgb;
|
||||
vec2 minBound = step(vec2(0.0), coords);
|
||||
vec2 maxBound = step(coords, vec2(1.0));
|
||||
float bloomAlpha = bloomFullColor.a * minBound.x * minBound.y * maxBound.x * maxBound.y;" +
|
||||
(chroma_color !== 0 ?
|
||||
"bloomColor = font_color.rgb * mix(vec3(rgb2grey(bloomColor)), bloomColor, chroma_color);"
|
||||
:
|
||||
"bloomColor = font_color.rgb * rgb2grey(bloomColor);") +
|
||||
"finalColor += bloomColor * bloom_strength * bloomAlpha;"
|
||||
: "") +
|
||||
|
||||
(brightness_flickering !== 0 ? "
|
||||
finalColor *= brightness;" : "") +
|
||||
|
||||
"gl_FragColor = vec4(finalColor * screen_brightness, qt_Opacity);" +
|
||||
"}"
|
||||
|
||||
onStatusChanged: {
|
||||
// Print warning messages
|
||||
if (log)
|
||||
console.log(log);
|
||||
|
||||
// Activate fallback mode
|
||||
if (status == ShaderEffect.Error) {
|
||||
fallBack = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -17,34 +17,27 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import "Components"
|
||||
|
||||
RowLayout {
|
||||
property alias value: slider.value
|
||||
property alias stepSize: slider.stepSize
|
||||
property alias minimumValue: slider.minimumValue
|
||||
property alias maximumValue: slider.maximumValue
|
||||
property alias minimumValue: slider.from
|
||||
property alias maximumValue: slider.to
|
||||
property real maxMultiplier: 100
|
||||
|
||||
id: setting_component
|
||||
spacing: 10
|
||||
Slider{
|
||||
Slider {
|
||||
id: slider
|
||||
stepSize: parent.stepSize
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Text{
|
||||
id: textfield
|
||||
text: formatNumber(Math.round(value * maxMultiplier))
|
||||
}
|
||||
function formatNumber(num) {
|
||||
var n = "" + num;
|
||||
while (n.length < 3) {
|
||||
n = " " + n;
|
||||
}
|
||||
return n + "%";
|
||||
SizedLabel {
|
||||
text: Math.round(value * maxMultiplier) + "%"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -17,12 +17,12 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
|
||||
import QtQuick 2.2
|
||||
|
||||
Rectangle{
|
||||
Rectangle {
|
||||
property size terminalSize
|
||||
property real topOpacity: 0.6
|
||||
|
||||
width: textSize.width * 2
|
||||
height: textSize.height * 2
|
||||
radius: 5
|
||||
@@ -31,17 +31,21 @@ Rectangle{
|
||||
color: "black"
|
||||
opacity: sizetimer.running ? 0.6 : 0.0
|
||||
|
||||
Behavior on opacity{NumberAnimation{duration: 200}}
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
|
||||
onTerminalSizeChanged: sizetimer.restart()
|
||||
|
||||
Text{
|
||||
Text {
|
||||
id: textSize
|
||||
anchors.centerIn: parent
|
||||
color: "white"
|
||||
text: terminalSize.width + "x" + terminalSize.height
|
||||
}
|
||||
Timer{
|
||||
Timer {
|
||||
id: sizetimer
|
||||
interval: 1000
|
||||
running: false
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -21,11 +21,13 @@
|
||||
import QtQuick 2.2
|
||||
import QtQuick.LocalStorage 2.0
|
||||
|
||||
Item {
|
||||
QtObject {
|
||||
readonly property string dbMajorVersion: "2"
|
||||
readonly property string dbMinorVersion: "1.0"
|
||||
property bool initialized: false
|
||||
|
||||
function getDatabase() {
|
||||
return LocalStorage.openDatabaseSync("coololdterm", "1.0", "StorageDatabase", 100000);
|
||||
return LocalStorage.openDatabaseSync("coolretroterm" + dbMajorVersion, dbMinorVersion, "StorageDatabase", 100000)
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
@@ -33,43 +35,47 @@ Item {
|
||||
db.transaction(
|
||||
function(tx) {
|
||||
tx.executeSql('CREATE TABLE IF NOT EXISTS settings(setting TEXT UNIQUE, value TEXT)');
|
||||
});
|
||||
}
|
||||
)
|
||||
|
||||
initialized = true;
|
||||
initialized = true
|
||||
}
|
||||
|
||||
function setSetting(setting, value) {
|
||||
if(!initialized) initialize();
|
||||
if(!initialized) initialize();
|
||||
|
||||
var db = getDatabase();
|
||||
var res = "";
|
||||
db.transaction(function(tx) {
|
||||
var rs = tx.executeSql('INSERT OR REPLACE INTO settings VALUES (?,?);', [setting,value]);
|
||||
//console.log(rs.rowsAffected)
|
||||
if (rs.rowsAffected > 0) {
|
||||
var db = getDatabase();
|
||||
var res = "";
|
||||
db.transaction(
|
||||
function(tx) {
|
||||
var rs = tx.executeSql('INSERT OR REPLACE INTO settings VALUES (?,?);', [setting,value]);
|
||||
//console.log(rs.rowsAffected)
|
||||
if (rs.rowsAffected > 0) {
|
||||
res = "OK";
|
||||
} else {
|
||||
} else {
|
||||
res = "Error";
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
)
|
||||
// The function returns “OK” if it was successful, or “Error” if it wasn't
|
||||
return res;
|
||||
return res
|
||||
}
|
||||
|
||||
function getSetting(setting) {
|
||||
if(!initialized) initialize();
|
||||
var db = getDatabase();
|
||||
var res="";
|
||||
db.transaction(function(tx) {
|
||||
var rs = tx.executeSql('SELECT value FROM settings WHERE setting=?;', [setting]);
|
||||
if (rs.rows.length > 0) {
|
||||
res = rs.rows.item(0).value;
|
||||
} else {
|
||||
res = undefined;
|
||||
}
|
||||
})
|
||||
return res
|
||||
if(!initialized) initialize();
|
||||
var db = getDatabase();
|
||||
var res = "";
|
||||
db.transaction(
|
||||
function(tx) {
|
||||
var rs = tx.executeSql('SELECT value FROM settings WHERE setting=?;', [setting]);
|
||||
if (rs.rows.length > 0) {
|
||||
res = rs.rows.item(0).value;
|
||||
} else {
|
||||
res = undefined;
|
||||
}
|
||||
}
|
||||
)
|
||||
return res
|
||||
}
|
||||
|
||||
function dropSettings(){
|
||||
@@ -77,6 +83,7 @@ Item {
|
||||
db.transaction(
|
||||
function(tx) {
|
||||
tx.executeSql('DROP TABLE settings');
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,81 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
import QtQuick 2.2
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
Item{
|
||||
Item{
|
||||
id: scalableContent
|
||||
width: parent.width * shadersettings.window_scaling
|
||||
height: parent.height * shadersettings.window_scaling
|
||||
import "utils.js" as Utils
|
||||
|
||||
Loader{
|
||||
id: frame
|
||||
anchors.fill: parent
|
||||
z: 2.1
|
||||
source: shadersettings.frame_source
|
||||
}
|
||||
PreprocessedTerminal{
|
||||
id: terminal
|
||||
anchors.fill: parent
|
||||
}
|
||||
ShaderTerminal{
|
||||
id: shadercontainer
|
||||
anchors.fill: parent
|
||||
opacity: shadersettings.windowOpacity * 0.3 + 0.7
|
||||
z: 1.9
|
||||
}
|
||||
ShaderTerminal {
|
||||
property alias title: terminal.title
|
||||
property alias terminalSize: terminal.terminalSize
|
||||
signal sessionFinished()
|
||||
|
||||
property bool loadBloomEffect: appSettings.bloom > 0 || appSettings._frameShininess > 0
|
||||
|
||||
id: mainShader
|
||||
opacity: appSettings.windowOpacity * 0.3 + 0.7
|
||||
|
||||
source: terminal.mainSource
|
||||
burnInEffect: terminal.burnInEffect
|
||||
virtualResolution: terminal.virtualResolution
|
||||
screenResolution: Qt.size(
|
||||
terminalWindow.width * Screen.devicePixelRatio * appSettings.windowScaling,
|
||||
terminalWindow.height * Screen.devicePixelRatio * appSettings.windowScaling
|
||||
)
|
||||
bloomSource: bloomSourceLoader.item
|
||||
|
||||
PreprocessedTerminal {
|
||||
id: terminal
|
||||
anchors.fill: parent
|
||||
onSessionFinished: mainShader.sessionFinished()
|
||||
}
|
||||
|
||||
// This is used to render the texture to a lower resolution then scale it up.
|
||||
Loader{
|
||||
id: scalableContentSource
|
||||
active: shadersettings.window_scaling < 1
|
||||
sourceComponent: ShaderEffectSource{
|
||||
sourceItem: scalableContent
|
||||
function activate() {
|
||||
terminal.mainTerminal.forceActiveFocus()
|
||||
}
|
||||
|
||||
// EFFECTS ////////////////////////////////////////////////////////////////
|
||||
Loader {
|
||||
id: bloomEffectLoader
|
||||
active: loadBloomEffect
|
||||
asynchronous: true
|
||||
width: parent.width * appSettings.bloomQuality
|
||||
height: parent.height * appSettings.bloomQuality
|
||||
|
||||
sourceComponent: FastBlur {
|
||||
radius: Utils.lint(16, 64, appSettings.bloomQuality)
|
||||
source: terminal.mainSource
|
||||
transparentBorder: true
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: bloomSourceLoader
|
||||
active: loadBloomEffect
|
||||
asynchronous: true
|
||||
sourceComponent: ShaderEffectSource {
|
||||
id: _bloomEffectSource
|
||||
sourceItem: bloomEffectLoader.item
|
||||
wrapMode: ShaderEffectSource.Repeat
|
||||
hideSource: true
|
||||
smooth: true
|
||||
}
|
||||
}
|
||||
Loader{
|
||||
active: shadersettings.window_scaling < 1
|
||||
anchors.fill: parent
|
||||
sourceComponent: ShaderEffect{
|
||||
property var source: scalableContentSource.item
|
||||
}
|
||||
}
|
||||
|
||||
// Terminal size overlay. Shown when terminal size changes.
|
||||
Loader{
|
||||
id: sizeoverlayloader
|
||||
z: 3
|
||||
anchors.centerIn: parent
|
||||
active: shadersettings.show_terminal_size
|
||||
sourceComponent: SizeOverlay{
|
||||
terminalSize: terminal.terminalSize
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
52
app/qml/TerminalFrame.qml
Normal file
@@ -0,0 +1,52 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
import QtQuick 2.0
|
||||
|
||||
import "utils.js" as Utils
|
||||
|
||||
ShaderEffect {
|
||||
property color _staticFrameColor: Utils.sum(appSettings.frameColor, Qt.rgba(0.1, 0.1, 0.1, 1.0))
|
||||
property color _backgroundColor: appSettings.backgroundColor
|
||||
property color _fontColor: appSettings.fontColor
|
||||
property color _lightColor: Utils.mix(_fontColor, _backgroundColor, 0.2)
|
||||
|
||||
property color frameColor: Utils.mix(
|
||||
Utils.scaleColor(_lightColor, 0.2),
|
||||
_staticFrameColor,
|
||||
0.125 + 0.750 * ambientLight
|
||||
)
|
||||
|
||||
property real screenCurvature: appSettings.screenCurvature * appSettings.screenCurvatureSize * terminalWindow.normalizedWindowScale
|
||||
|
||||
property real frameShininess: appSettings.frameShininess
|
||||
|
||||
property real frameSize: appSettings.frameSize * terminalWindow.normalizedWindowScale
|
||||
|
||||
property real screenRadius: appSettings.screenRadius
|
||||
|
||||
property size viewportSize: Qt.size(width / appSettings.windowScaling, height / appSettings.windowScaling)
|
||||
|
||||
property real ambientLight: appSettings.ambientLight
|
||||
|
||||
vertexShader: "qrc:/shaders/terminal_frame.vert.qsb"
|
||||
fragmentShader: "qrc:/shaders/terminal_frame.frag.qsb"
|
||||
|
||||
onStatusChanged: if (log) console.log(log) //Print warning messages
|
||||
}
|
||||
90
app/qml/TerminalTabs.qml
Normal file
@@ -0,0 +1,90 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: tabsRoot
|
||||
|
||||
readonly property string currentTitle: tabsModel.count > 0
|
||||
? (tabsModel.get(currentIndex).title ?? "cool-retro-term")
|
||||
: "cool-retro-term"
|
||||
readonly property size terminalSize: stack.currentItem ? stack.currentItem.terminalSize : Qt.size(0, 0)
|
||||
property int currentIndex: 0
|
||||
readonly property int count: tabsModel.count
|
||||
property var hostWindow
|
||||
property alias tabsModel: tabsModel
|
||||
|
||||
function normalizeTitle(rawTitle) {
|
||||
if (rawTitle === undefined || rawTitle === null) {
|
||||
return ""
|
||||
}
|
||||
return String(rawTitle).trim()
|
||||
}
|
||||
|
||||
function addTab() {
|
||||
tabsModel.append({ title: "" })
|
||||
currentIndex = tabsModel.count - 1
|
||||
}
|
||||
|
||||
function closeTab(index) {
|
||||
if (tabsModel.count <= 1) {
|
||||
hostWindow.close()
|
||||
return
|
||||
}
|
||||
|
||||
tabsModel.remove(index)
|
||||
currentIndex = Math.min(currentIndex, tabsModel.count - 1)
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: tabsModel
|
||||
}
|
||||
|
||||
Component.onCompleted: addTab()
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
StackLayout {
|
||||
id: stack
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
currentIndex: tabsRoot.currentIndex
|
||||
|
||||
Repeater {
|
||||
model: tabsModel
|
||||
TerminalContainer {
|
||||
property bool shouldHaveFocus: terminalWindow.active && StackLayout.isCurrentItem
|
||||
onShouldHaveFocusChanged: {
|
||||
if (shouldHaveFocus) {
|
||||
activate()
|
||||
}
|
||||
}
|
||||
onTitleChanged: tabsModel.setProperty(index, "title", normalizeTitle(title))
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
onSessionFinished: tabsRoot.closeTab(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
217
app/qml/TerminalTabsBar.qml
Normal file
@@ -0,0 +1,217 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Window
|
||||
|
||||
Item {
|
||||
id: barRoot
|
||||
|
||||
readonly property int innerPadding: 6
|
||||
readonly property int leftInset: (isMacOS && !showWindowControls) ? 72 : 0
|
||||
property var tabsController
|
||||
property var hostWindow
|
||||
property bool isMacOS: false
|
||||
property bool showWindowControls: true
|
||||
property bool windowControlsOnLeft: false
|
||||
property bool enableSystemMove: true
|
||||
property bool enableDoubleClickMaximize: true
|
||||
|
||||
implicitHeight: rowLayout.implicitHeight
|
||||
|
||||
function toggleMaximize() {
|
||||
if (!hostWindow) {
|
||||
return
|
||||
}
|
||||
hostWindow.visibility = (hostWindow.visibility === Window.Maximized)
|
||||
? Window.Windowed
|
||||
: Window.Maximized
|
||||
}
|
||||
|
||||
onTabsControllerChanged: {
|
||||
if (tabsController) {
|
||||
tabBar.currentIndex = tabsController.currentIndex
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (tabsController) {
|
||||
tabBar.currentIndex = tabsController.currentIndex
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: palette.window
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: leftInset
|
||||
visible: leftInset > 0
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: showWindowControls && windowControlsOnLeft
|
||||
sourceComponent: windowControlsComponent
|
||||
}
|
||||
|
||||
TabBar {
|
||||
id: tabBar
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
focusPolicy: Qt.NoFocus
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
if (tabsController && tabsController.currentIndex !== currentIndex) {
|
||||
tabsController.currentIndex = currentIndex
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: tabsController ? tabsController.tabsModel : null
|
||||
TabButton {
|
||||
id: tabButton
|
||||
contentItem: RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors { leftMargin: innerPadding; rightMargin: innerPadding }
|
||||
spacing: innerPadding
|
||||
|
||||
Label {
|
||||
text: model.title
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
text: "\u00d7"
|
||||
focusPolicy: Qt.NoFocus
|
||||
padding: innerPadding
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
onClicked: {
|
||||
if (tabsController) {
|
||||
tabsController.closeTab(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
id: addTabButton
|
||||
text: "+"
|
||||
focusPolicy: Qt.NoFocus
|
||||
Layout.fillHeight: true
|
||||
padding: innerPadding
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
onClicked: {
|
||||
if (tabsController) {
|
||||
tabsController.addTab()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: showWindowControls && !windowControlsOnLeft
|
||||
sourceComponent: windowControlsComponent
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: windowControlsComponent
|
||||
RowLayout {
|
||||
id: windowControls
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 0
|
||||
|
||||
ToolButton {
|
||||
text: "\u2212"
|
||||
focusPolicy: Qt.NoFocus
|
||||
padding: innerPadding
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
onClicked: {
|
||||
if (hostWindow) {
|
||||
hostWindow.visibility = Window.Minimized
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
text: hostWindow && hostWindow.visibility === Window.Maximized ? "\u2752" : "\u25a1"
|
||||
focusPolicy: Qt.NoFocus
|
||||
padding: innerPadding
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
onClicked: toggleMaximize()
|
||||
}
|
||||
|
||||
ToolButton {
|
||||
text: "\u00d7"
|
||||
focusPolicy: Qt.NoFocus
|
||||
padding: innerPadding
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
onClicked: {
|
||||
if (hostWindow) {
|
||||
hostWindow.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: tabsController
|
||||
function onCurrentIndexChanged() {
|
||||
if (tabBar.currentIndex !== tabsController.currentIndex) {
|
||||
tabBar.currentIndex = tabsController.currentIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DragHandler {
|
||||
acceptedDevices: PointerDevice.Mouse
|
||||
acceptedButtons: Qt.LeftButton
|
||||
grabPermissions: PointerHandler.CanTakeOverFromItems
|
||||
target: null
|
||||
onActiveChanged: {
|
||||
if (active && hostWindow && enableSystemMove) {
|
||||
hostWindow.startSystemMove()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onTapped: {
|
||||
if (tapCount === 2 && enableDoubleClickMaximize) {
|
||||
toggleMaximize()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
247
app/qml/TerminalWindow.qml
Normal file
@@ -0,0 +1,247 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
*
|
||||
* cool-retro-term is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Window 2.1
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts
|
||||
|
||||
import "menus"
|
||||
|
||||
ApplicationWindow {
|
||||
id: terminalWindow
|
||||
|
||||
width: 1024
|
||||
height: 768
|
||||
|
||||
// Show the window once it is ready.
|
||||
Component.onCompleted: {
|
||||
visible = true
|
||||
}
|
||||
|
||||
minimumWidth: 320
|
||||
minimumHeight: 240
|
||||
|
||||
visible: false
|
||||
|
||||
flags: Qt.Window | Qt.FramelessWindowHint
|
||||
|
||||
property bool fullscreen: appSettings.fullscreen
|
||||
onFullscreenChanged: visibility = (fullscreen ? Window.FullScreen : Window.Windowed)
|
||||
|
||||
menuBar: qtquickMenuLoader.item
|
||||
|
||||
Loader {
|
||||
id: qtquickMenuLoader
|
||||
active: !appSettings.isMacOS && appSettings.showMenubar
|
||||
sourceComponent: WindowMenu { }
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: globalMenuLoader
|
||||
active: appSettings.isMacOS
|
||||
sourceComponent: OSXMenu { }
|
||||
}
|
||||
|
||||
property real normalizedWindowScale: 1024 / ((0.5 * width + 0.5 * height))
|
||||
|
||||
color: "#00000000"
|
||||
|
||||
title: terminalTabs.currentTitle
|
||||
|
||||
Action {
|
||||
id: showMenubarAction
|
||||
text: qsTr("Show Menubar")
|
||||
enabled: !appSettings.isMacOS
|
||||
shortcut: "Ctrl+Shift+M"
|
||||
checkable: true
|
||||
checked: appSettings.showMenubar
|
||||
onTriggered: appSettings.showMenubar = !appSettings.showMenubar
|
||||
}
|
||||
Action {
|
||||
id: fullscreenAction
|
||||
text: qsTr("Fullscreen")
|
||||
enabled: !appSettings.isMacOS
|
||||
shortcut: "Alt+F11"
|
||||
onTriggered: appSettings.fullscreen = !appSettings.fullscreen
|
||||
checkable: true
|
||||
checked: appSettings.fullscreen
|
||||
}
|
||||
Action {
|
||||
id: newWindowAction
|
||||
text: qsTr("New Window")
|
||||
shortcut: "Ctrl+Shift+N"
|
||||
onTriggered: appRoot.createWindow()
|
||||
}
|
||||
Action {
|
||||
id: quitAction
|
||||
text: qsTr("Quit")
|
||||
shortcut: "Ctrl+Shift+Q"
|
||||
onTriggered: appSettings.close()
|
||||
}
|
||||
Action {
|
||||
id: showsettingsAction
|
||||
text: qsTr("Settings")
|
||||
onTriggered: {
|
||||
settingsWindow.show()
|
||||
settingsWindow.requestActivate()
|
||||
settingsWindow.raise()
|
||||
}
|
||||
}
|
||||
Action {
|
||||
id: copyAction
|
||||
text: qsTr("Copy")
|
||||
shortcut: "Ctrl+Shift+C"
|
||||
}
|
||||
Action {
|
||||
id: pasteAction
|
||||
text: qsTr("Paste")
|
||||
shortcut: "Ctrl+Shift+V"
|
||||
}
|
||||
Action {
|
||||
id: zoomIn
|
||||
text: qsTr("Zoom In")
|
||||
shortcut: "Ctrl++"
|
||||
onTriggered: appSettings.incrementScaling()
|
||||
}
|
||||
Action {
|
||||
id: zoomOut
|
||||
text: qsTr("Zoom Out")
|
||||
shortcut: "Ctrl+-"
|
||||
onTriggered: appSettings.decrementScaling()
|
||||
}
|
||||
Action {
|
||||
id: showAboutAction
|
||||
text: qsTr("About")
|
||||
onTriggered: {
|
||||
aboutDialog.show()
|
||||
aboutDialog.requestActivate()
|
||||
aboutDialog.raise()
|
||||
}
|
||||
}
|
||||
Action {
|
||||
id: newTabAction
|
||||
text: qsTr("New Tab")
|
||||
onTriggered: terminalTabs.addTab()
|
||||
}
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
TerminalTabsBar {
|
||||
Layout.fillWidth: true
|
||||
tabsController: terminalTabs
|
||||
hostWindow: terminalWindow
|
||||
isMacOS: appSettings.isMacOS
|
||||
showWindowControls: true
|
||||
windowControlsOnLeft: appSettings.isMacOS
|
||||
enableSystemMove: true
|
||||
enableDoubleClickMaximize: true
|
||||
}
|
||||
|
||||
TerminalTabs {
|
||||
id: terminalTabs
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
hostWindow: terminalWindow
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
active: appSettings.showTerminalSize
|
||||
sourceComponent: SizeOverlay {
|
||||
z: 3
|
||||
terminalSize: terminalTabs.terminalSize
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: resizeHandles
|
||||
anchors.fill: parent
|
||||
visible: true
|
||||
property int resizeMargin: 6
|
||||
|
||||
MouseArea {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: resizeHandles.resizeMargin
|
||||
cursorShape: Qt.SizeHorCursor
|
||||
onPressed: terminalWindow.startSystemResize(Qt.LeftEdge)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
width: resizeHandles.resizeMargin
|
||||
cursorShape: Qt.SizeHorCursor
|
||||
onPressed: terminalWindow.startSystemResize(Qt.RightEdge)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
height: resizeHandles.resizeMargin
|
||||
cursorShape: Qt.SizeVerCursor
|
||||
onPressed: terminalWindow.startSystemResize(Qt.BottomEdge)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: resizeHandles.resizeMargin
|
||||
height: resizeHandles.resizeMargin
|
||||
cursorShape: Qt.SizeFDiagCursor
|
||||
onPressed: terminalWindow.startSystemResize(Qt.TopEdge | Qt.LeftEdge)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
width: resizeHandles.resizeMargin
|
||||
height: resizeHandles.resizeMargin
|
||||
cursorShape: Qt.SizeBDiagCursor
|
||||
onPressed: terminalWindow.startSystemResize(Qt.TopEdge | Qt.RightEdge)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
width: resizeHandles.resizeMargin
|
||||
height: resizeHandles.resizeMargin
|
||||
cursorShape: Qt.SizeBDiagCursor
|
||||
onPressed: terminalWindow.startSystemResize(Qt.BottomEdge | Qt.LeftEdge)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
width: resizeHandles.resizeMargin
|
||||
height: resizeHandles.resizeMargin
|
||||
cursorShape: Qt.SizeFDiagCursor
|
||||
onPressed: terminalWindow.startSystemResize(Qt.BottomEdge | Qt.RightEdge)
|
||||
}
|
||||
}
|
||||
|
||||
onClosing: {
|
||||
appRoot.closeWindow(terminalWindow)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2013 "Filippo Scognamiglio"
|
||||
* Copyright (c) 2013-2021 "Filippo Scognamiglio"
|
||||
* https://github.com/Swordfish90/cool-retro-term
|
||||
*
|
||||
* This file is part of cool-retro-term.
|
||||
@@ -17,23 +17,29 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*******************************************************************************/
|
||||
import QtQuick
|
||||
|
||||
import QtQuick 2.2
|
||||
QtObject {
|
||||
id: timeManager
|
||||
|
||||
Timer{
|
||||
default property bool enableTimer: false
|
||||
property real time
|
||||
property bool enableTimer: false
|
||||
property real time: 0
|
||||
|
||||
NumberAnimation on time {
|
||||
from: 0
|
||||
to: 100000
|
||||
running: shadersettings.fps === 0 && enableTimer
|
||||
duration: 100000
|
||||
loops: Animation.Infinite
|
||||
property int framesPerUpdate: Math.max(1, appSettings.effectsFrameSkip)
|
||||
property int _frameCounter: 0
|
||||
|
||||
property var frameDriver: FrameAnimation {
|
||||
running: enableTimer
|
||||
onTriggered: {
|
||||
timeManager._frameCounter += 1
|
||||
|
||||
if (timeManager._frameCounter >= timeManager.framesPerUpdate) {
|
||||
time = elapsedTime
|
||||
timeManager._frameCounter = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onTriggered: time += interval
|
||||
running: shadersettings.fps !== 0 && enableTimer
|
||||
interval: Math.round(1000 / shadersettings.fps)
|
||||
repeat: true
|
||||
onEnableTimerChanged: if (!enableTimer) _frameCounter = 0
|
||||
onFramesPerUpdateChanged: _frameCounter = 0
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
Copyright (c) 2011-2012, Ricardo Banffy.
|
||||
Copyright (c) 1993-2011, Paul Mattes.
|
||||
Copyright (c) 2004-2005, Don Russell.
|
||||
Copyright (c) 2004, Dick Altenbern.
|
||||
Copyright (c) 1990, Jeff Sparkes.
|
||||
Copyright (c) 1989, Georgia Tech Research Corporation (GTRC), Atlanta, GA 30332.
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
Neither the names of Ricardo Banffy, Paul Mattes, Don Russell, Dick Altenbern, Jeff Sparkes, GTRC nor the names of their contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
THIS SOFTWARE IS PROVIDED BY PAUL MATTES, DON RUSSELL, DICK ALTENBERN, JEFF SPARKES AND GTRC "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PAUL MATTES, DON RUSSELL, DICK ALTENBERN, JEFF SPARKES OR GTRC BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -1,73 +0,0 @@
|
||||
3270font: A font for the nostalgic
|
||||
==================================
|
||||
https://github.com/rbanffy/3270font
|
||||
|
||||

|
||||
|
||||
A little bit of history
|
||||
-----------------------
|
||||
|
||||
This font is derived from the x3270 font, which, in turn, was translated
|
||||
from the one in Georgia Tech's 3270tool, which was itself hand-copied
|
||||
from a 3270 terminal. I built it because I felt terminals deserve to be
|
||||
pretty. The .sfd font file contains a x3270 bitmap font that was used
|
||||
for guidance.
|
||||
|
||||
![Using with the Cathode terminal program]
|
||||
(https://raw.github.com/wiki/rbanffy/3270font/cathode.png)
|
||||
|
||||
The format
|
||||
----------
|
||||
|
||||
This font was built with FontForge. You'll need it if you want to
|
||||
generate fonts for your platform. On most civilized operating systems,
|
||||
you can simply `apt-get install fontforge`, `yum install fontforge` or
|
||||
even `port install fontforge`. On others, you may need to grab your copy
|
||||
from http://fontforge.org/. I encourage you to drop by and read the
|
||||
tutorials.
|
||||
|
||||
![Powerline-shell compatible!]
|
||||
(https://raw.github.com/wiki/rbanffy/3270font/powerline.png)
|
||||
|
||||
Adobe Type 1, TTF, OTF and WOFF versions are available for download on
|
||||
http://s3.amazonaws.com/rbanffy/3270_fonts.zip for those who would just
|
||||
like to use them.
|
||||
|
||||
![Using it on OSX]
|
||||
(https://raw.github.com/wiki/rbanffy/3270font/osx_terminal.png)
|
||||
|
||||
Generating derived files
|
||||
------------------------
|
||||
|
||||
The script `generate_derived.pe` calls FontForge and generates
|
||||
PostScript, OTF, TTF and WOFF versions of the base font, as well as a
|
||||
slightly more condensed .sfd file with the base font narrowed to 488
|
||||
units, with no glyph rescaling and its corresponding PostScript, TTF,
|
||||
OTF and WOFF versions.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
I don't think GitHub's pull-request mechanism is FontForge-friendly. If
|
||||
you want to contribute (there are a lot of missing glyphs, such as the
|
||||
APL set and most non-latin alphabets which most likely were never built
|
||||
into 3270 terminals), get in touch and we will figure out how to do it
|
||||
right.
|
||||
|
||||
Preserving history
|
||||
------------------
|
||||
|
||||
I regard the history of electronic computing a very important part of
|
||||
our civilization's history. Consider donating to entities that help
|
||||
preserve it, such as the Computer History Museum
|
||||
(http://www.computerhistory.org/), the IT History Society
|
||||
(http://ithistory.org/) and many others around the world. If you have a
|
||||
historically significant piece of technology in your closet or garage,
|
||||
consider contacting a local technology or industrial-design-oriented
|
||||
museum for advice.
|
||||
|
||||
Known problems
|
||||
--------------
|
||||
|
||||
I have received errors when installing the OTF, TTF, and PFM fonts on
|
||||
Windows 7 and 8 (didn't try others).
|
||||
@@ -1,317 +0,0 @@
|
||||
{\rtf1\ansi\deff0\deftab720{\fonttbl{\f0\fswiss MS Sans Serif;}{\f1\froman\fcharset2 Symbol;}{\f2\fmodern\fprq1 Atari Classic Chunky;}{\f3\froman Times New Roman;}{\f4\fswiss\fprq2 Arial;}}
|
||||
{\colortbl\red0\green0\blue0;\red0\green0\blue255;}
|
||||
\deflang1033\pard\plain\f2\fs24\cf1 Atari Classic TrueType Fonts \plain\f2\fs24\cf0
|
||||
\par \plain\f4\fs16\cf0 (Windows Version 1.1)
|
||||
\par Created by Mark Simonson (v.1.0-1998, v.1.1-2001)
|
||||
\par marksim@bitstream.net
|
||||
\par Website: Mac/Atari Fusion--Atari Home Computer Resources for Mac Users
|
||||
\par http://www2.bitstream.net/~marksim/atarimac/
|
||||
\par Macintosh version also available.
|
||||
\par
|
||||
\par With these fonts installed, you can view and print Atari text files in any text editor that allows you to change fonts (WordPad, for example). Tip: In order to get the correct line breaks, you will need to change the ATASCII return character (155) to the DOS LF character. (In the Character Map accessory, the ATASCII return is the blank character that comes just before the inverse up-arrow.)
|
||||
\par
|
||||
\par There are three different fonts. \plain\f4\fs16\cf0\b Atari Classic Chunky \plain\f4\fs16\cf0 is a pixel-for-pixel copy of the original ATASCII character set. \plain\f4\fs16\cf0\b Atari Classic Smooth \plain\f4\fs16\cf0 interprets the pixel aliasing (stair steps) as diagonal lines. \plain\f4\fs16\cf0\b Atari Classic Extrasmooth \plain\f4\fs16\cf0 refines this idea further with the addition of curves. \plain\f4\fs16\cf0\b Smooth\plain\f4\fs16\cf0 and \plain\f4\fs16\cf0\b Extrasmooth\plain\f4\fs16\cf0 were designed for better appearance and legibility at larger sizes and on print-outs. Use the one that looks best to you.
|
||||
\par
|
||||
\par These fonts will tend to look uneven at font sizes that do not correspond to the 8-by-8 pixel grid that the characters are based on. Because Windows assumes 96ppi screen resolution, they will look best in a font size that is a multiple of 6 (i.e., 6pt, 12pt, 18pt, etc.). (In Windows, 6 points = 8 pixels.)
|
||||
\par
|
||||
\par The Atari Classic TrueType fonts duplicate the ATASCII character set on a low-level basis. Unlike a normal Windows font, ATASCII utilizes all character codes from $00 to $FF (0 to 255). The lower half are normal characters; the upper half are inverse versions of the lower half. The basic ASCII characters ($00 to $7F) correspond fairly closely except for the first 32, which don't normally contain characters in a Windows font.
|
||||
\par
|
||||
\par Due to differences between the way Windows and the Atari use character codes, not all characters will display properly in Windows. In fact, some characters will not display at all (though they do exist in the font). Unfortunately, this is due to certain character codes being reserved in Windows and there doesn't appear to be any way to work around it. The character codes affected are: $00-$1F (0-31), $7F-$81 (127-129), $8D-$90 (141-144), $9D (157), and $9F (158).
|
||||
\par
|
||||
\par Not all characters can be typed from the keyboard. You can however copy characters as needed from this document (see tables below). The Character Map desk accessory can help also.
|
||||
\par
|
||||
\par \plain\f4\fs16\cf0\b ATASCII CHARACTER SET TABLES
|
||||
\par \plain\f4\fs16\cf0
|
||||
\par In order to see the ATASCII character set with these tables, the Atari Classic TrueType fonts must be installed. Characters that are not displayed properly are due to character code usage differences between ATASCII and Windows (see above).
|
||||
\par
|
||||
\par
|
||||
\par \plain\f4\fs16\cf0\b TABLE 1: ATASCII Character Dump Block
|
||||
\par \plain\f4\fs16\cf0
|
||||
\par All characters (ATASCII $00 thru $FF) 16 characters per
|
||||
\par line.
|
||||
\par
|
||||
\par
|
||||
\par \plain\f2\fs12\cf0 \'01\'02\'03\'04\'05\'06\'07\'08\tab
|
||||
\par \'0b\'0c
|
||||
\par \'0e\'0f
|
||||
\par \'10\'11\'12\'13\'14\'15\'16\'17\'18\'19\'1a\'1b\'1c\'1d\'1e\'1f
|
||||
\par !"#$%&'()*+,-./
|
||||
\par 0123456789:;<=>?
|
||||
\par @ABCDEFGHIJKLMNO
|
||||
\par PQRSTUVWXYZ[\\]^_
|
||||
\par `abcdefghijklmno
|
||||
\par pqrstuvwxyz\{|\}~
|
||||
\par \'80\'81\'82\'83\'84\'85\'86\'87\'88\'89\'8a\'8b\'8c\'8d\'8e\'8f
|
||||
\par \'90''""\bullet \endash \emdash \'98\'99\'9a \'9c\'9d\'9e\'9f
|
||||
\par \~\'a1\'a2\'a3\'a4\'a5\'a6\'a7\'a8\'a9\'aa\'ab\'ac\'ad\'ae\'af
|
||||
\par \'b0\'b1\'b2\'b3\'b4\'b5\'b6\'b7\'b8\'b9\'ba\'bb\'bc\'bd\'be\'bf
|
||||
\par \'c0\'c1\'c2\'c3\'c4\'c5\'c6\'c7\'c8\'c9\'ca\'cb\'cc\'cd\'ce\'cf
|
||||
\par \'d0\'d1\'d2\'d3\'d4\'d5\'d6\'d7\'d8\'d9\'da\'db\'dc\'dd\'de\'df
|
||||
\par \'e0\'e1\'e2\'e3\'e4\'e5\'e6\'e7\'e8\'e9\'ea\'eb\'ec\'ed\'ee\'ef
|
||||
\par \'f0\'f1\'f2\'f3\'f4\'f5\'f6\'f7\'f8\'f9\'fa\'fb\'fc\'fd\'fe\'ff
|
||||
\par \plain\f4\fs16\cf0
|
||||
\par
|
||||
\par \plain\f4\fs16\cf0\b TABLE 2: ATASCII Character Dump List
|
||||
\par \plain\f4\fs16\cf0
|
||||
\par All characters (ATASCII $00 thru $FF) one character per
|
||||
\par line with hexadecimal value indicated on the left.
|
||||
\par
|
||||
\par \plain\f2\fs12\cf0 00=
|
||||
\par 01=\'01
|
||||
\par 02=\'02
|
||||
\par 03=\'03
|
||||
\par 04=\'04
|
||||
\par 05=\'05
|
||||
\par 06=\'06
|
||||
\par 07=\'07
|
||||
\par 08=\'08
|
||||
\par 09=\tab
|
||||
\par 0A=
|
||||
\par
|
||||
\par 0B=\'0b
|
||||
\par 0C=\'0c
|
||||
\par 0D=
|
||||
\par 0E=\'0e
|
||||
\par 0F=\'0f
|
||||
\par 10=\'10
|
||||
\par 11=\'11
|
||||
\par 12=\'12
|
||||
\par 13=\'13
|
||||
\par 14=\'14
|
||||
\par 15=\'15
|
||||
\par 16=\'16
|
||||
\par 17=\'17
|
||||
\par 18=\'18
|
||||
\par 19=\'19
|
||||
\par 1A=\'1a
|
||||
\par 1B=\'1b
|
||||
\par 1C=\'1c
|
||||
\par 1D=\'1d
|
||||
\par 1E=\'1e
|
||||
\par 1F=\'1f
|
||||
\par 20=
|
||||
\par 21=!
|
||||
\par 22="
|
||||
\par 23=#
|
||||
\par 24=$
|
||||
\par 25=%
|
||||
\par 26=&
|
||||
\par 27='
|
||||
\par 28=(
|
||||
\par 29=)
|
||||
\par 2A=*
|
||||
\par 2B=+
|
||||
\par 2C=,
|
||||
\par 2D=-
|
||||
\par 2E=.
|
||||
\par 2F=/
|
||||
\par 30=0
|
||||
\par 31=1
|
||||
\par 32=2
|
||||
\par 33=3
|
||||
\par 34=4
|
||||
\par 35=5
|
||||
\par 36=6
|
||||
\par 37=7
|
||||
\par 38=8
|
||||
\par 39=9
|
||||
\par 3A=:
|
||||
\par 3B=;
|
||||
\par 3C=<
|
||||
\par 3D==
|
||||
\par 3E=>
|
||||
\par 3F=?
|
||||
\par 40=@
|
||||
\par 41=A
|
||||
\par 42=B
|
||||
\par 43=C
|
||||
\par 44=D
|
||||
\par 45=E
|
||||
\par 46=F
|
||||
\par 47=G
|
||||
\par 48=H
|
||||
\par 49=I
|
||||
\par 4A=J
|
||||
\par 4B=K
|
||||
\par 4C=L
|
||||
\par 4D=M
|
||||
\par 4E=N
|
||||
\par 4F=O
|
||||
\par 50=P
|
||||
\par 51=Q
|
||||
\par 52=R
|
||||
\par 53=S
|
||||
\par 54=T
|
||||
\par 55=U
|
||||
\par 56=V
|
||||
\par 57=W
|
||||
\par 58=X
|
||||
\par 59=Y
|
||||
\par 5A=Z
|
||||
\par 5B=[
|
||||
\par 5C=\\
|
||||
\par 5D=]
|
||||
\par 5E=^
|
||||
\par 5F=_
|
||||
\par 60=`
|
||||
\par 61=a
|
||||
\par 62=b
|
||||
\par 63=c
|
||||
\par 64=d
|
||||
\par 65=e
|
||||
\par 66=f
|
||||
\par 67=g
|
||||
\par 68=h
|
||||
\par 69=i
|
||||
\par 6A=j
|
||||
\par 6B=k
|
||||
\par 6C=l
|
||||
\par 6D=m
|
||||
\par 6E=n
|
||||
\par 6F=o
|
||||
\par 70=p
|
||||
\par 71=q
|
||||
\par 72=r
|
||||
\par 73=s
|
||||
\par 74=t
|
||||
\par 75=u
|
||||
\par 76=v
|
||||
\par 77=w
|
||||
\par 78=x
|
||||
\par 79=y
|
||||
\par 7A=z
|
||||
\par 7B=\{
|
||||
\par 7C=|
|
||||
\par 7D=\}
|
||||
\par 7E=~
|
||||
\par 7F=
|
||||
\par 80=\'80
|
||||
\par 81=\'81
|
||||
\par 82=\'82
|
||||
\par 83=\'83
|
||||
\par 84=\'84
|
||||
\par 85=\'85
|
||||
\par 86=\'86
|
||||
\par 87=\'87
|
||||
\par 88=\'88
|
||||
\par 89=\'89
|
||||
\par 8A=\'8a
|
||||
\par 8B=\'8b
|
||||
\par 8C=\'8c
|
||||
\par 8D=\'8d
|
||||
\par 8E=\'8e
|
||||
\par 8F=\'8f
|
||||
\par 90=\'90
|
||||
\par 91='
|
||||
\par 92='
|
||||
\par 93="
|
||||
\par 94="
|
||||
\par 95=\bullet
|
||||
\par 96=\endash
|
||||
\par 97=\emdash
|
||||
\par 98=\'98
|
||||
\par 99=\'99
|
||||
\par 9A=\'9a
|
||||
\par 9B=
|
||||
\par 9C=\'9c
|
||||
\par 9D=\'9d
|
||||
\par 9E=\'9e
|
||||
\par 9F=\'9f
|
||||
\par A0=\~
|
||||
\par A1=\'a1
|
||||
\par A2=\'a2
|
||||
\par A3=\'a3
|
||||
\par A4=\'a4
|
||||
\par A5=\'a5
|
||||
\par A6=\'a6
|
||||
\par A7=\'a7
|
||||
\par A8=\'a8
|
||||
\par A9=\'a9
|
||||
\par AA=\'aa
|
||||
\par AB=\'ab
|
||||
\par AC=\'ac
|
||||
\par AD=\'ad
|
||||
\par AE=\'ae
|
||||
\par AF=\'af
|
||||
\par B0=\'b0
|
||||
\par B1=\'b1
|
||||
\par B2=\'b2
|
||||
\par B3=\'b3
|
||||
\par B4=\'b4
|
||||
\par B5=\'b5
|
||||
\par B6=\'b6
|
||||
\par B7=\'b7
|
||||
\par B8=\'b8
|
||||
\par B9=\'b9
|
||||
\par BA=\'ba
|
||||
\par BB=\'bb
|
||||
\par BC=\'bc
|
||||
\par BD=\'bd
|
||||
\par BE=\'be
|
||||
\par BF=\'bf
|
||||
\par C0=\'c0
|
||||
\par C1=\'c1
|
||||
\par C2=\'c2
|
||||
\par C3=\'c3
|
||||
\par C4=\'c4
|
||||
\par C5=\'c5
|
||||
\par C6=\'c6
|
||||
\par C7=\'c7
|
||||
\par C8=\'c8
|
||||
\par C9=\'c9
|
||||
\par CA=\'ca
|
||||
\par CB=\'cb
|
||||
\par CC=\'cc
|
||||
\par CD=\'cd
|
||||
\par CE=\'ce
|
||||
\par CF=\'cf
|
||||
\par D0=\'d0
|
||||
\par D1=\'d1
|
||||
\par D2=\'d2
|
||||
\par D3=\'d3
|
||||
\par D4=\'d4
|
||||
\par D5=\'d5
|
||||
\par D6=\'d6
|
||||
\par D7=\'d7
|
||||
\par D8=\'d8
|
||||
\par D9=\'d9
|
||||
\par DA=\'da
|
||||
\par DB=\'db
|
||||
\par DC=\'dc
|
||||
\par DD=\'dd
|
||||
\par DE=\'de
|
||||
\par DF=\'df
|
||||
\par E0=\'e0
|
||||
\par E1=\'e1
|
||||
\par E2=\'e2
|
||||
\par E3=\'e3
|
||||
\par E4=\'e4
|
||||
\par E5=\'e5
|
||||
\par E6=\'e6
|
||||
\par E7=\'e7
|
||||
\par E8=\'e8
|
||||
\par E9=\'e9
|
||||
\par EA=\'ea
|
||||
\par EB=\'eb
|
||||
\par EC=\'ec
|
||||
\par ED=\'ed
|
||||
\par EE=\'ee
|
||||
\par EF=\'ef
|
||||
\par F0=\'f0
|
||||
\par F1=\'f1
|
||||
\par F2=\'f2
|
||||
\par F3=\'f3
|
||||
\par F4=\'f4
|
||||
\par F5=\'f5
|
||||
\par F6=\'f6
|
||||
\par F7=\'f7
|
||||
\par F8=\'f8
|
||||
\par F9=\'f9
|
||||
\par FA=\'fa
|
||||
\par FB=\'fb
|
||||
\par FC=\'fc
|
||||
\par FD=\'fd
|
||||
\par FE=\'fe
|
||||
\par FF=\'ff
|
||||
\par }
|
||||
| ||||