aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2025-05-23 14:04:27 +0200
committerFelix Morgner <felix.morgner@gmail.com>2025-05-23 14:04:27 +0200
commit5d8f799a1171f92054d4b45ba130cd7fdad0bd01 (patch)
tree0f51290b3a60d71d25d7a49b66d5bd54dd7a4156
parentc45004b73bb045328a724d1d860df6d1515af6d4 (diff)
downloadturns-5d8f799a1171f92054d4b45ba130cd7fdad0bd01.tar.xz
turns-5d8f799a1171f92054d4b45ba130cd7fdad0bd01.zip
app: prepare restructuring
-rw-r--r--LICENSE.txt504
-rw-r--r--LICENSES/LGPL-2.1-only.txt (renamed from lib/LICENSES/LGPL-2.1-only.txt)0
-rw-r--r--app/CMakeLists.txt57
-rw-r--r--app/src/main.cpp97
-rw-r--r--core/CMakeLists.txt87
-rw-r--r--core/include/turns/core/json_ext.hpp43
-rw-r--r--core/include/turns/core/turn_order_model.hpp102
-rw-r--r--core/schemas/ch.arknet.Turns.gschema.xml25
-rw-r--r--core/src/turn_order_model.cpp312
-rw-r--r--core/tests/disposition.cpp32
-rw-r--r--core/tests/glib_test_init.cpp28
-rw-r--r--core/tests/participant.cpp310
-rw-r--r--core/tests/single_participant.trns11
-rw-r--r--core/tests/turn_order_bugs.cpp40
-rw-r--r--core/tests/turn_order_model.cpp314
-rw-r--r--gui/CMakeLists.txt59
-rw-r--r--gui/desktop.in (renamed from app/desktop.in)0
-rw-r--r--gui/lang/CMakeLists.txt (renamed from lang/CMakeLists.txt)0
-rw-r--r--gui/lang/include/turns/lang/messages.hpp (renamed from lang/include/turns/lang/messages.hpp)0
-rw-r--r--gui/lang/po/de.po (renamed from lang/po/de.po)0
-rw-r--r--gui/lang/po/de_CH.po (renamed from lang/po/de_CH.po)0
-rw-r--r--gui/lang/po/en.po (renamed from lang/po/en.po)0
-rw-r--r--gui/lang/tests/intl_test_init.cpp (renamed from lang/tests/intl_test_init.cpp)0
-rw-r--r--gui/lang/tests/messages.cpp (renamed from lang/tests/messages.cpp)0
-rw-r--r--gui/metainfo.xml (renamed from app/metainfo.xml)0
-rw-r--r--gui/mime.xml (renamed from app/mime.xml)0
-rw-r--r--gui/schemas/ch.arknet.Turns.gschema.xml (renamed from app/schemas/ch.arknet.Turns.gschema.xml)0
-rw-r--r--gui/settings.cpp (renamed from core/src/settings.cpp)0
-rw-r--r--gui/settings.hpp (renamed from core/include/turns/core/settings.hpp)0
-rw-r--r--gui/src/main.cpp97
-rw-r--r--gui/style/CMakeLists.txt (renamed from style/CMakeLists.txt)0
-rw-r--r--gui/style/style-dark.css (renamed from style/style-dark.css)0
-rw-r--r--gui/style/style.css (renamed from style/style.css)0
-rw-r--r--gui/ui/CMakeLists.txt (renamed from ui/CMakeLists.txt)0
-rw-r--r--gui/ui/include/turns/ui/fwd.hpp (renamed from ui/include/turns/ui/fwd.hpp)0
-rw-r--r--gui/ui/include/turns/ui/init.hpp (renamed from ui/include/turns/ui/init.hpp)0
-rw-r--r--gui/ui/include/turns/ui/participant_editor.hpp (renamed from ui/include/turns/ui/participant_editor.hpp)0
-rw-r--r--gui/ui/include/turns/ui/participant_row.hpp (renamed from ui/include/turns/ui/participant_row.hpp)0
-rw-r--r--gui/ui/include/turns/ui/preferences.hpp (renamed from ui/include/turns/ui/preferences.hpp)0
-rw-r--r--gui/ui/include/turns/ui/template_widget.hpp (renamed from ui/include/turns/ui/template_widget.hpp)0
-rw-r--r--gui/ui/include/turns/ui/tracker.hpp (renamed from ui/include/turns/ui/tracker.hpp)0
-rw-r--r--gui/ui/include/turns/ui/turn_order_view.hpp (renamed from ui/include/turns/ui/turn_order_view.hpp)0
-rw-r--r--gui/ui/src/init.cpp (renamed from ui/src/init.cpp)0
-rw-r--r--gui/ui/src/participant_editor.cpp (renamed from ui/src/participant_editor.cpp)0
-rw-r--r--gui/ui/src/participant_editor.ui (renamed from ui/src/participant_editor.ui)0
-rw-r--r--gui/ui/src/participant_row.cpp (renamed from ui/src/participant_row.cpp)0
-rw-r--r--gui/ui/src/participant_row.ui (renamed from ui/src/participant_row.ui)0
-rw-r--r--gui/ui/src/preferences.cpp (renamed from ui/src/preferences.cpp)0
-rw-r--r--gui/ui/src/preferences.ui (renamed from ui/src/preferences.ui)0
-rw-r--r--gui/ui/src/tracker.cpp (renamed from ui/src/tracker.cpp)0
-rw-r--r--gui/ui/src/tracker.ui (renamed from ui/src/tracker.ui)0
-rw-r--r--gui/ui/src/tracker/actions.cpp (renamed from ui/src/tracker/actions.cpp)0
-rw-r--r--gui/ui/src/tracker/event_handlers.cpp (renamed from ui/src/tracker/event_handlers.cpp)0
-rw-r--r--gui/ui/src/turn_order_view.cpp (renamed from ui/src/turn_order_view.cpp)0
-rw-r--r--gui/ui/src/turn_order_view.ui (renamed from ui/src/turn_order_view.ui)0
-rw-r--r--gui/ui/tests/gtk_test_init.cpp (renamed from ui/tests/gtk_test_init.cpp)0
-rw-r--r--gui/ui/tests/participant_editor.cpp (renamed from ui/tests/participant_editor.cpp)0
-rw-r--r--gui/ui/tests/participant_row.cpp (renamed from ui/tests/participant_row.cpp)0
-rw-r--r--gui/ui/tests/resources.cpp (renamed from ui/tests/resources.cpp)0
-rw-r--r--gui/ui/tests/tracker.cpp (renamed from ui/tests/tracker.cpp)0
-rw-r--r--gui/ui/ui.cmb (renamed from ui/ui.cmb)0
61 files changed, 156 insertions, 1962 deletions
diff --git a/LICENSE.txt b/LICENSE.txt
deleted file mode 100644
index 8000a6f..0000000
--- a/LICENSE.txt
+++ /dev/null
@@ -1,504 +0,0 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL. It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it. You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
- When we speak of free software, we are referring to freedom of use,
-not price. Our General Public Licenses are designed to make sure that
-you have the freedom to distribute copies of free software (and charge
-for this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
- To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights. These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
- To protect each distributor, we want to make it very clear that
-there is no warranty for the free library. Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-
- Finally, software patents pose a constant threat to the existence of
-any free program. We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder. Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
- Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License. This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License. We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
- When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library. The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom. The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
- We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License. It also provides other free software developers Less
-of an advantage over competing non-free programs. These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries. However, the Lesser license provides advantages in certain
-special circumstances.
-
- For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard. To achieve this, non-free programs must be
-allowed to use the library. A more frequent case is that a free
-library does the same job as widely used non-free libraries. In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
- In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software. For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
- Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-
- GNU LESSER GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-
- 6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (1) uses at run time a
- copy of the library already present on the user's computer system,
- rather than copying library functions into the executable, and (2)
- will operate properly with a modified version of the library, if
- the user installs one, as long as the modified version is
- interface-compatible with the version that the work was made with.
-
- c) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- d) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- e) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Libraries
-
- If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change. You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
- To apply these terms, attach the following notices to the library. It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
- <one line to give the library's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
- USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random
- Hacker.
-
- <signature of Ty Coon>, 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
diff --git a/lib/LICENSES/LGPL-2.1-only.txt b/LICENSES/LGPL-2.1-only.txt
index c6487f4..c6487f4 100644
--- a/lib/LICENSES/LGPL-2.1-only.txt
+++ b/LICENSES/LGPL-2.1-only.txt
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
deleted file mode 100644
index a231ec6..0000000
--- a/app/CMakeLists.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-add_executable("app"
- "src/main.cpp"
-)
-
-target_link_libraries("app" PRIVATE
- "$<$<AND:$<CXX_COMPILER_ID:GNU,Clang>,$<CONFIG:Debug>>:gcov>"
-
- "PkgConfig::gtkmm"
- "adwaitamm::adwaitamm"
-
- "turns::core"
- "turns::lang"
-
- "$<$<CXX_COMPILER_ID:GNU,Clang>:-Wl,--whole-archive>"
- "turns::ui"
- "turns::style"
- "$<$<CXX_COMPILER_ID:GNU,Clang>:-Wl,--no-whole-archive>"
-)
-
-target_add_glib_resources("app"
- PREFIX "/ch/arknet/Turns"
- UI_FILES "metainfo.xml"
-)
-
-set_target_properties("app" PROPERTIES
- OUTPUT_NAME "turns"
-)
-
-install(TARGETS "app"
- RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
-)
-
-install(FILES
- "${CMAKE_CURRENT_SOURCE_DIR}/metainfo.xml"
- DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo"
- RENAME "ch.arknet.Turns.metainfo.xml"
-)
-
-configure_file("desktop.in"
- "turns.desktop"
-)
-
-install(FILES
- "${CMAKE_CURRENT_BINARY_DIR}/turns.desktop"
- DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications"
- RENAME "ch.arknet.Turns.desktop"
-)
-
-configure_file("mime.xml"
- "turns.xml"
-)
-
-install(FILES
- "${CMAKE_CURRENT_BINARY_DIR}/turns.xml"
- DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/mime/packages"
- RENAME "ch.arknet.Turns.xml"
-)
diff --git a/app/src/main.cpp b/app/src/main.cpp
deleted file mode 100644
index f179cf8..0000000
--- a/app/src/main.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-#include "turns/core/init.hpp"
-#include "turns/core/settings.hpp"
-#include "turns/ui/init.hpp"
-#include "turns/ui/tracker.hpp"
-
-#include <sigc++/adaptors/bind.h>
-#include <sigc++/functors/mem_fun.h>
-
-#include <glibmm/refptr.h>
-
-#include <giomm/application.h>
-#include <giomm/settings.h>
-
-#include <gtkmm/application.h>
-#include <gtkmm/builder.h>
-#include <gtkmm/object.h>
-
-#include <adwaitamm/aboutdialog.hpp>
-#include <adwaitamm/application.hpp>
-#include <adwaitamm/enums.hpp>
-#include <adwaitamm/stylemanager.hpp>
-
-#include <libintl.h>
-
-#include <clocale>
-#include <print>
-
-auto show_about(Glib::RefPtr<Adwaita::Application> app)
-{
- auto active_window = app->get_active_window();
- auto dialog = Gtk::make_managed<Adwaita::AboutDialog>("/ch/arknet/Turns/metainfo.xml", "");
- dialog->present(active_window);
-}
-
-auto main(int argc, char * argv[]) -> int
-{
- setlocale(LC_ALL, "");
- bindtextdomain("turns", LOCALEDIR);
- bind_textdomain_codeset("turns", "UTF-8");
- textdomain("turns");
-
- auto app = Adwaita::Application::create("ch.arknet.Turns", Gio::Application::Flags::HANDLES_OPEN);
- auto settings = turns::core::get_settings();
-
- turns::core::register_types();
-
- app->signal_startup().connect([app] {
- turns::ui::register_types();
-
- auto style_manager = Adwaita::StyleManager::get_default();
- style_manager->set_color_scheme(Adwaita::ColorScheme::PreferLight);
-
- app->add_action("quit", sigc::mem_fun(*app, &Adwaita::Application::quit));
- app->add_action("about", sigc::bind(&show_about, app));
- app->set_accel_for_action("app.quit", "<Primary>q");
- app->set_accel_for_action("win.clear", "<Primary>x");
- app->set_accel_for_action("win.next", "<Primary>space");
- app->set_accel_for_action("win.previous", "<Primary>BackSpace");
- app->set_accel_for_action("win.add_participant", "<Primary>a");
- app->set_accel_for_action("win.open", "<Primary>o");
- app->set_accel_for_action("win.preferences", "<Primary>comma");
- app->set_accel_for_action("win.save", "<Primary>s");
- app->set_accel_for_action("win.save-as", "<Primary><Shift>s");
- });
-
- app->signal_activate().connect([app, settings] {
- auto window = new turns::ui::Tracker{app, settings};
- window->present();
- });
-
- app->signal_open().connect([app, settings](auto files, auto) {
- auto windows = app->get_windows();
- auto window = static_cast<turns::ui::Tracker *>(nullptr);
-
- if (windows.empty())
- {
- window = new turns::ui::Tracker{app, settings};
- }
- else
- {
- window = dynamic_cast<turns::ui::Tracker *>(windows[0]);
- }
-
- window->present();
- window->load(files[0]);
- });
-
- app->signal_window_removed().connect([](auto window) {
- auto tracker = dynamic_cast<turns::ui::Tracker *>(window);
- if (tracker)
- {
- delete tracker;
- }
- });
-
- return app->run(argc, argv);
-} \ No newline at end of file
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
deleted file mode 100644
index 788d80b..0000000
--- a/core/CMakeLists.txt
+++ /dev/null
@@ -1,87 +0,0 @@
-# Library
-
-add_library("core"
- "src/disposition.cpp"
- "src/init.cpp"
- "src/participant.cpp"
- "src/settings.cpp"
- "src/turn_order_model.cpp"
-
- "src/turns-participant.cpp"
-)
-
-add_library("turns::core" ALIAS "core")
-
-target_compile_options("core" PUBLIC
- "$<$<CXX_COMPILER_ID:GNU,Clang>:-Wall>"
- "$<$<CXX_COMPILER_ID:GNU,Clang>:-Wextra>"
- "$<$<CXX_COMPILER_ID:GNU,Clang>:-Werror>"
- "$<$<CXX_COMPILER_ID:GNU,Clang>:-pedantic-errors>"
-)
-
-if(NOT TURNS_USE_INSTALLED_SCHEMA_FILES)
- target_compile_definitions("core" PUBLIC
- "TURNS_SETTINGS_SCHEMA_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\""
- )
-endif()
-
-target_include_directories("core" PUBLIC
- "include"
-)
-
-target_link_libraries("core" PUBLIC
- "PkgConfig::giomm"
- "PkgConfig::glibmm"
- "nlohmann_json::nlohmann_json"
-)
-
-target_add_glib_schemas("core"
- SCHEMA_DIR "schemas"
-)
-
-target_add_glib_enums("core"
- HEADER_OUTPUT_DIR "turns"
- HEADER_TEMPLATE "include/turns/turns-enums.h.in"
- SOURCE_TEMPLATE "src/turns-enums.c.in"
- OUTPUT_NAME "turns-enums"
- HEADERS
- "include/turns/turns-disposition.h"
-)
-
-enable_coverage("core")
-
-install(FILES
- "schemas/ch.arknet.Turns.gschema.xml"
- DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/glib-2.0/schemas"
-)
-
-# Tests
-
-add_executable("core-tests"
- "tests/glib_test_init.cpp"
-
- "tests/disposition.cpp"
- "tests/participant.cpp"
- "tests/turn_order_bugs.cpp"
- "tests/turn_order_model.cpp"
-)
-
-target_link_libraries("core-tests" PRIVATE
- "Catch2::Catch2WithMain"
-
- "turns::core"
-)
-
-target_link_options("core-tests" PRIVATE
- "$<$<AND:$<CXX_COMPILER_ID:GNU,Clang>,$<CONFIG:Debug>>:--coverage>"
-)
-
-file(GLOB_RECURSE TEST_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/tests" CONFIGURE_DEPENDS "*.trns")
-
-target_add_glib_resources("core-tests"
- PREFIX "/ch/arknet/Turns/core-tests/"
- WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests"
- CSS_FILES ${TEST_FILES}
-)
-
-catch_discover_tests("core-tests") \ No newline at end of file
diff --git a/core/include/turns/core/json_ext.hpp b/core/include/turns/core/json_ext.hpp
deleted file mode 100644
index 3eedb64..0000000
--- a/core/include/turns/core/json_ext.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef TURNS_CORE_JSON_EXT_HPP
-#define TURNS_CORE_JSON_EXT_HPP
-
-#include <glibmm/property.h>
-#include <glibmm/ustring.h>
-
-#include <nlohmann/json.hpp>
-
-#include <string>
-
-NLOHMANN_JSON_NAMESPACE_BEGIN
-
-template<typename T>
-struct adl_serializer<Glib::Property<T>>
-{
- static void to_json(json & to, Glib::Property<T> const & from)
- {
- to = from.get_value();
- }
-
- static void from_json(json const & from, Glib::Property<T> & to)
- {
- to = from.template get<T>();
- }
-};
-
-template<>
-struct adl_serializer<Glib::ustring>
-{
- static void to_json(json & to, Glib::ustring const & from)
- {
- to = static_cast<std::string>(from);
- }
-
- static void from_json(json const & from, Glib::ustring & to)
- {
- to = from.template get<std::string>();
- }
-};
-
-NLOHMANN_JSON_NAMESPACE_END
-
-#endif \ No newline at end of file
diff --git a/core/include/turns/core/turn_order_model.hpp b/core/include/turns/core/turn_order_model.hpp
deleted file mode 100644
index b7ce484..0000000
--- a/core/include/turns/core/turn_order_model.hpp
+++ /dev/null
@@ -1,102 +0,0 @@
-#ifndef TURNS_CORE_TURN_ORDER_MODEL_HPP
-#define TURNS_CORE_TURN_ORDER_MODEL_HPP
-
-#include "turns/core/fwd.hpp"
-
-#include <glibmm/object.h>
-#include <glibmm/property.h>
-#include <glibmm/propertyproxy.h>
-#include <glibmm/refptr.h>
-#include <glibmm/ustring.h>
-
-#include <giomm/listmodel.h>
-
-#include <glib-object.h>
-#include <nlohmann/json_fwd.hpp>
-
-#include <limits>
-#include <optional>
-#include <vector>
-
-namespace turns::core
-{
-
- struct TurnOderModel : Gio::ListModel,
- Glib::Object
- {
- using value_type = Glib::RefPtr<Participant>;
- using container_type = std::vector<value_type>;
- using iterator = container_type::iterator;
- using const_iterator = container_type::const_iterator;
-
- using active_participant_type = unsigned int;
- using is_empty_type = bool;
- using has_next_type = bool;
- using has_previous_type = bool;
- using is_running_type = bool;
- using progress_type = double;
- using round_number_type = unsigned int;
- using skip_defeated_type = bool;
-
- // auto static constexpr invalid_participant_index = std::numeric_limits<active_participant_type>::max();
- // auto static constexpr invalid_round_number = std::numeric_limits<round_number_type>::max();
-
- /** Life-time */
- // TurnOderModel();
-
- // auto static create() -> Glib::RefPtr<TurnOderModel>;
- // auto static create(nlohmann::json const & from) -> Glib::RefPtr<TurnOderModel>;
-
- /** Properties */
- // auto is_empty() const -> Glib::PropertyProxy_ReadOnly<is_empty_type>;
- auto has_next() const -> Glib::PropertyProxy_ReadOnly<has_next_type>;
- auto has_previous() const -> Glib::PropertyProxy_ReadOnly<has_previous_type>;
- auto is_running() const -> Glib::PropertyProxy_ReadOnly<is_running_type>;
- auto progress() const -> Glib::PropertyProxy_ReadOnly<progress_type>;
- auto round_number() const -> Glib::PropertyProxy_ReadOnly<round_number_type>;
- auto skip_defeated() -> Glib::PropertyProxy<skip_defeated_type>;
-
- /** Element Modifications */
- // auto add(Glib::ustring const & name, float priority, Disposition disposition) -> void;
- // auto clear() -> void;
- // auto remove(unsigned index) -> void;
-
- /** Turn Modification */
- auto next() -> void;
- auto previous() -> void;
- auto start() -> void;
- auto stop() -> void;
-
- /** Serialization */
- auto load(nlohmann::json const & from) -> void;
- auto serialize() -> nlohmann::json;
-
- private:
- explicit TurnOderModel(nlohmann::json const & from);
-
- auto get_item_type_vfunc() -> GType override;
- auto get_n_items_vfunc() -> unsigned override;
- auto get_item_vfunc(unsigned position) -> void * override;
-
- /** Signal handlers */
- auto handle_priority_changed(value_type entry) -> void;
-
- /** Data management */
- auto find(value_type entry) const -> const_iterator;
- auto insert(value_type entry) -> const_iterator;
-
- container_type m_data{};
- std::optional<unsigned> m_active{};
-
- Glib::Property<has_next_type> m_has_next{*this, "has-next", false};
- Glib::Property<has_previous_type> m_has_previous{*this, "has-previous", false};
- Glib::Property<is_empty_type> m_is_empty{*this, "is-empty", true};
- Glib::Property<is_running_type> m_is_running{*this, "is-running", false};
- Glib::Property<progress_type> m_progress{*this, "progress", 0.0};
- Glib::Property<round_number_type> m_round_number{*this, "round-number", invalid_round_number};
- Glib::Property<skip_defeated_type> m_skip_defeated{*this, "skip-defeated", false};
- };
-
-} // namespace turns::core
-
-#endif \ No newline at end of file
diff --git a/core/schemas/ch.arknet.Turns.gschema.xml b/core/schemas/ch.arknet.Turns.gschema.xml
deleted file mode 100644
index d764608..0000000
--- a/core/schemas/ch.arknet.Turns.gschema.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<schemalist>
- <schema path="/ch/arknet/Turns/" id="ch.arknet.Turns">
- <key name="disposition-color-friendly" type="s">
- <default>'#33d17a'</default>
- <summary>Friendly Disposition Color</summary>
- <description>The color used to shade friendly participants.</description>
- </key>
- <key name="disposition-color-hostile" type="s">
- <default>'#e01b24'</default>
- <summary>Hostile Disposition Color</summary>
- <description>The color used to shade hostile participants.</description>
- </key>
- <key name="disposition-color-secret" type="s">
- <default>'#9141ac'</default>
- <summary>Secret Disposition Color</summary>
- <description>The color used to shade secret participants.</description>
- </key>
- <key name="skip-defeated" type="b">
- <default>false</default>
- <summary>Skip Defeated Participants</summary>
- <description>Whether or not defeated participants shall be skipped while stepping through the turn order.</description>
- </key>
- </schema>
-</schemalist> \ No newline at end of file
diff --git a/core/src/turn_order_model.cpp b/core/src/turn_order_model.cpp
deleted file mode 100644
index e430fed..0000000
--- a/core/src/turn_order_model.cpp
+++ /dev/null
@@ -1,312 +0,0 @@
-#include "turns/core/turn_order_model.hpp"
-
-#include "turns/core/disposition.hpp"
-#include "turns/core/json_ext.hpp"
-#include "turns/core/participant.hpp"
-
-#include <sigc++/adaptors/bind.h>
-#include <sigc++/functors/mem_fun.h>
-
-#include <glibmm/objectbase.h>
-#include <glibmm/propertyproxy.h>
-#include <glibmm/refptr.h>
-#include <glibmm/ustring.h>
-#include <glibmm/wrap.h>
-
-#include <giomm/listmodel.h>
-
-#include <glib-object.h>
-#include <nlohmann/json.hpp>
-
-#include <algorithm>
-#include <functional>
-#include <iterator>
-#include <ranges>
-#include <typeinfo>
-#include <vector>
-
-using namespace std::placeholders;
-
-namespace turns::core
-{
-
- namespace
- {
- auto constexpr comparator = [](auto lhs, auto rhs) {
- return *lhs > *rhs;
- };
- } // namespace
-
- /** Construction */
-
- TurnOderModel::TurnOderModel()
- : Glib::ObjectBase{typeid(TurnOderModel)}
- , Gio::ListModel{}
- {
- }
-
- TurnOderModel::TurnOderModel(nlohmann::json const & from)
- : TurnOderModel{}
- {
- load(from);
- }
-
- auto TurnOderModel::create() -> Glib::RefPtr<TurnOderModel>
- {
- return Glib::make_refptr_for_instance(new TurnOderModel{});
- }
-
- auto TurnOderModel::create(nlohmann::json const & from) -> Glib::RefPtr<TurnOderModel>
- {
- return Glib::make_refptr_for_instance(new TurnOderModel{from});
- }
-
- /** Queries */
-
- auto TurnOderModel::is_empty() const -> Glib::PropertyProxy_ReadOnly<is_empty_type>
- {
- return m_is_empty.get_proxy();
- }
-
- auto TurnOderModel::has_next() const -> Glib::PropertyProxy_ReadOnly<has_next_type>
- {
- return m_has_next.get_proxy();
- }
-
- auto TurnOderModel::has_previous() const -> Glib::PropertyProxy_ReadOnly<has_previous_type>
- {
- return m_has_previous.get_proxy();
- }
-
- auto TurnOderModel::is_running() const -> Glib::PropertyProxy_ReadOnly<is_running_type>
- {
- return m_is_running.get_proxy();
- }
-
- auto TurnOderModel::progress() const -> Glib::PropertyProxy_ReadOnly<progress_type>
- {
- return m_progress.get_proxy();
- }
-
- auto TurnOderModel::round_number() const -> Glib::PropertyProxy_ReadOnly<round_number_type>
- {
- return m_round_number.get_proxy();
- }
-
- auto TurnOderModel::skip_defeated() -> Glib::PropertyProxy<skip_defeated_type>
- {
- return m_skip_defeated.get_proxy();
- }
-
- /** Modifiers */
-
- auto TurnOderModel::add(Glib::ustring const & name, float priority, Disposition disposition) -> void
- {
- auto entry = Participant::create(name, priority, disposition);
- entry->property_priority().signal_changed().connect(sigc::bind(sigc::mem_fun(*this, &TurnOderModel::handle_priority_changed), entry));
- auto position = std::distance(m_data.cbegin(), insert(entry));
- items_changed(position, 0, 1);
-
- if (get_n_items() == 1)
- {
- m_is_empty = false;
- m_has_next = true;
- }
- }
-
- auto TurnOderModel::clear() -> void
- {
- m_is_running = false;
- m_is_empty = true;
- m_has_next = false;
- m_has_previous = false;
- m_active.reset();
- m_round_number = invalid_round_number;
- m_progress = 0;
-
- auto old_size = get_n_items();
- m_data.clear();
- items_changed(0, old_size, 0);
- }
-
- auto TurnOderModel::next() -> void
- {
- auto old_active = *m_active;
- m_active = m_active.transform([this](auto index) { return (index + 1) % get_n_items(); });
-
- m_has_previous = true;
- m_data[old_active]->property_is_active() = false;
- m_data[*m_active]->property_is_active() = true;
-
- m_progress = (static_cast<float>(*m_active) + 1) / get_n_items();
-
- if (m_active == 0)
- {
- m_round_number = m_round_number + 1;
- }
- }
-
- auto TurnOderModel::previous() -> void
- {
- if (!(m_has_previous && m_is_running))
- {
- return;
- }
-
- auto old_active = *m_active;
- m_active = m_active.transform([this](auto index) { return index ? index - 1 : get_n_items() - 1; });
-
- m_has_previous = m_round_number > 0 || m_active > 0;
- m_data[old_active]->property_is_active() = false;
- m_data[*m_active]->property_is_active() = true;
-
- m_progress = (static_cast<float>(*m_active) + 1) / get_n_items();
-
- if (m_active == 0 && m_round_number > 0)
- {
- m_round_number = m_round_number - 1;
- }
- }
-
- auto TurnOderModel::remove(unsigned index) -> void
- {
- if (index >= get_n_items())
- {
- return;
- }
-
- auto position = m_data.begin() + index;
- m_data.erase(position);
- items_changed(index, 1, 0);
- if (get_n_items() == 0)
- {
- m_is_empty = true;
- m_is_running = false;
- m_has_next = false;
- }
- }
-
- auto TurnOderModel::start() -> void
- {
- if (!m_active)
- {
- m_active = 0;
- m_data[*m_active]->property_is_active() = true;
- }
- if (m_round_number == invalid_round_number)
- {
- m_round_number = 0;
- }
- m_is_running = true;
-
- m_progress = (static_cast<float>(*m_active) + 1) / get_n_items();
- }
-
- auto TurnOderModel::stop() -> void
- {
- m_is_running = false;
- m_progress = 0;
- }
-
- /** Serialization */
- auto TurnOderModel::load(nlohmann::json const & from) -> void
- {
- auto old_size = get_n_items();
-
- this->freeze_notify();
-
- m_round_number = from.value("round", invalid_round_number);
-
- m_data.clear();
- auto participants = from.value("participants", std::vector<nlohmann::json>{});
- auto factory = [](auto s) {
- return Participant::create(s);
- };
- auto inserter = std::bind(&TurnOderModel::insert, this, _1);
- std::ranges::for_each(participants | std::views::transform(factory), inserter);
-
- auto active = std::ranges::find_if(m_data, [](auto participant) { return participant->property_is_active(); });
- if (active != std::ranges::end(m_data))
- {
- m_active = std::ranges::distance(std::ranges::begin(m_data), active);
- }
-
- m_is_empty = m_data.empty();
- m_has_next = !m_is_empty;
- m_has_previous = m_round_number > 0 || m_active > 0;
-
- this->thaw_notify();
-
- items_changed(0, old_size, get_n_items());
- }
-
- auto TurnOderModel::serialize() -> nlohmann::json
- {
- auto serialized = nlohmann::json{};
- if (m_round_number != invalid_round_number)
- {
- serialized["round"] = m_round_number;
- }
- serialized["participants"] = m_data | std::views::transform([](auto const & p) { return p->serialize(); }) | std::ranges::to<std::vector>();
- ;
- return serialized;
- }
-
- /** ListModel implementation */
-
- auto TurnOderModel::get_item_type_vfunc() -> GType
- {
- return Participant::get_type();
- }
-
- auto TurnOderModel::get_n_items_vfunc() -> unsigned
- {
- return m_data.size();
- }
-
- auto TurnOderModel::get_item_vfunc(unsigned position) -> void *
- {
- if (position >= get_n_items())
- {
- return nullptr;
- }
- auto item = m_data[position];
- item->reference();
- return Glib::unwrap(item);
- }
-
- /** Signal handlers */
-
- auto TurnOderModel::handle_priority_changed(value_type entry) -> void
- {
- auto original_position = find(entry);
- auto original_index = distance(m_data.cbegin(), original_position);
- auto target_position = std::ranges::upper_bound(m_data, entry, comparator);
- if (original_position == target_position)
- {
- return;
- }
-
- m_data.erase(original_position);
- auto inserted_position = insert(entry);
- items_changed(0, get_n_items(), get_n_items());
- if (m_active == original_index)
- {
- m_active = distance(m_data.cbegin(), inserted_position);
- m_has_previous = m_round_number > 0 || m_active > 0;
- }
- }
-
- /** Data management */
-
- auto TurnOderModel::find(value_type entry) const -> const_iterator
- {
- return std::ranges::find(m_data, entry);
- }
-
- auto TurnOderModel::insert(value_type entry) -> const_iterator
- {
- return m_data.insert(std::ranges::upper_bound(m_data, entry, comparator), entry);
- }
-
-} // namespace turns::core \ No newline at end of file
diff --git a/core/tests/disposition.cpp b/core/tests/disposition.cpp
deleted file mode 100644
index fadf476..0000000
--- a/core/tests/disposition.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "turns/core/disposition.hpp"
-
-#include <catch2/catch_test_macros.hpp>
-#include <catch2/generators/catch_generators.hpp>
-
-#include <glibmm/i18n.h>
-#include <glibmm/ustring.h>
-
-#include <format>
-#include <limits>
-#include <type_traits>
-#include <utility>
-
-namespace turns::core::tests
-{
-
- TEST_CASE("to_presentation_name returns the correct string for the current language", "[disposition]")
- {
- auto [value, name] = GENERATE(std::pair{Disposition::Neutral, Glib::ustring{_("Neutral")}},
- std::pair{Disposition::Friendly, Glib::ustring{_("Friendly")}},
- std::pair{Disposition::Hostile, Glib::ustring{_("Hostile")}},
- std::pair{Disposition::Secret, Glib::ustring{_("Secret")}},
- std::pair{static_cast<Disposition>(std::numeric_limits<std::underlying_type_t<Disposition>>::max()),
- Glib::ustring{_("Unknown disposition value")}});
-
- SECTION(std::format("the presentation name for '{}' is '{}'", static_cast<std::underlying_type_t<Disposition>>(value), name.c_str()))
- {
- REQUIRE(presentation_name_for(value) == name);
- }
- }
-
-} // namespace turns::core::tests \ No newline at end of file
diff --git a/core/tests/glib_test_init.cpp b/core/tests/glib_test_init.cpp
deleted file mode 100644
index b521189..0000000
--- a/core/tests/glib_test_init.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "turns/core/init.hpp"
-
-#include <catch2/reporters/catch_reporter_event_listener.hpp>
-#include <catch2/reporters/catch_reporter_registrars.hpp>
-
-#include <glibmm/init.h>
-
-#include <giomm/init.h>
-
-namespace turns::core::tests
-{
-
- struct glib_test_init : Catch::EventListenerBase
- {
- using Catch::EventListenerBase::EventListenerBase;
-
- auto testRunStarting(Catch::TestRunInfo const &) -> void override
- {
- Gio::init();
- Glib::init();
-
- register_types();
- }
- };
-
- CATCH_REGISTER_LISTENER(glib_test_init);
-
-} // namespace turns::core::tests \ No newline at end of file
diff --git a/core/tests/participant.cpp b/core/tests/participant.cpp
deleted file mode 100644
index b417e36..0000000
--- a/core/tests/participant.cpp
+++ /dev/null
@@ -1,310 +0,0 @@
-#include "turns/core/participant.hpp"
-
-#include "turns/core/disposition.hpp"
-
-#include <catch2/catch_approx.hpp>
-#include <catch2/catch_test_macros.hpp>
-
-#include <nlohmann/json.hpp>
-
-#include <compare>
-
-namespace turns::core::tests
-{
-
- TEST_CASE("Constructing a participant", "[core][construction]")
- {
- auto constexpr name = "Participant #1";
- auto constexpr priority = 17;
- auto constexpr disposition = Disposition::Friendly;
-
- auto json = nlohmann::json::parse(R"(
- {
- "name": "Participant #1",
- "priority": 17,
- "disposition": 1,
- "is-active": false,
- "is-defeated": false
- }
- )");
-
- SECTION("Can be constructed using default ctor")
- {
- auto instance = Participant{};
- REQUIRE(instance.property_name() == "");
- REQUIRE(instance.property_priority() == 0);
- REQUIRE(instance.property_disposition() == Disposition::Neutral);
- REQUIRE(!instance.property_is_active());
- REQUIRE(!instance.property_is_defeated());
- }
-
- SECTION("Can be constructed using ctor")
- {
- auto instance = Participant{name, priority, disposition};
- REQUIRE(instance.property_name() == name);
- REQUIRE(instance.property_priority() == priority);
- REQUIRE(instance.property_disposition() == disposition);
- REQUIRE(!instance.property_is_active());
- REQUIRE(!instance.property_is_defeated());
- }
-
- SECTION("Can be constructed using factory")
- {
- auto instance = Participant::create(name, priority, disposition);
- REQUIRE(instance->property_name() == name);
- REQUIRE(instance->property_priority() == priority);
- REQUIRE(instance->property_disposition() == disposition);
- REQUIRE(!instance->property_is_active());
- REQUIRE(!instance->property_is_defeated());
- }
-
- SECTION("Can be constructed using JSON factory", "[json]")
- {
- auto instance = Participant::create(json);
- REQUIRE(instance->property_name() == name);
- REQUIRE(instance->property_priority() == priority);
- REQUIRE(instance->property_disposition() == disposition);
- REQUIRE(!instance->property_is_active());
- REQUIRE(!instance->property_is_defeated());
- }
- }
-
- TEST_CASE("Setting properties on participant", "[core][properties]")
- {
- auto constexpr name = "Participant #2";
- auto constexpr priority = 10;
- auto constexpr disposition = Disposition::Hostile;
-
- auto instance = Participant{name, priority, disposition};
-
- SECTION("Setting '::disposition' via proxy changes the 'disposition' value")
- {
- auto old = instance.property_disposition().get_value();
- instance.property_disposition() = static_cast<core::Disposition>(static_cast<int>(disposition) - 1);
- REQUIRE(instance.property_disposition() != old);
- }
-
- SECTION("Setting '::disposition' via glib changes the 'disposition' value")
- {
- auto old = instance.property_disposition().get_value();
- instance.set_property("disposition", static_cast<core::Disposition>(static_cast<int>(disposition) - 1));
- REQUIRE(instance.property_disposition() != old);
- }
-
- SECTION("Setting '::is-active' via proxy changes the 'is_active' value")
- {
- auto old = instance.property_is_active().get_value();
- instance.property_is_active() = !old;
- REQUIRE(instance.property_is_active() != old);
- }
-
- SECTION("Setting '::is-active' via glib changes the 'is_active' value")
- {
- auto old = instance.property_is_active().get_value();
- instance.set_property("is-active", !old);
- REQUIRE(instance.property_is_active() != old);
- }
-
- SECTION("Setting '::is-defeated' via proxy changes the 'is_defeated' value")
- {
- auto old = instance.property_is_defeated().get_value();
- instance.property_is_defeated() = !old;
- REQUIRE(instance.property_is_defeated() != old);
- }
-
- SECTION("Setting '::is-defeated' via glib changes the 'is_defeated' value")
- {
- auto old = instance.property_is_defeated().get_value();
- instance.set_property("is-defeated", !old);
- REQUIRE(instance.property_is_defeated() != old);
- }
-
- SECTION("Setting '::name' via proxy changes the 'name' value")
- {
- auto old = instance.property_name().get_value();
- instance.property_name() = old + " Changed";
- REQUIRE(instance.property_name().get_value() != old);
- }
-
- SECTION("Setting '::name' via glib changes the 'name' value")
- {
- auto old = instance.property_name().get_value();
- instance.set_property("name", old + " Changed");
- REQUIRE(instance.property_name().get_value() != old);
- }
-
- SECTION("Setting '::priority' via proxy changes the 'priority' value")
- {
- auto old = instance.property_priority().get_value();
- instance.property_priority() = old + 1;
- REQUIRE(instance.property_priority() != old);
- }
-
- SECTION("Setting '::priority' via glib changes the 'priority' value")
- {
- auto old = instance.property_priority().get_value();
- instance.set_property("priority", old + 1);
- REQUIRE(instance.property_priority() != old);
- }
- }
-
- TEST_CASE("A freshly constructed participant")
- {
- auto constexpr constructed_name = "Vana Thistletop";
- auto constexpr constructed_priority = 17;
- auto constexpr constructed_disposition = Disposition::Friendly;
- auto instance = Participant{constructed_name, constructed_priority, constructed_disposition};
-
- SECTION("can be created")
- {
- REQUIRE(Participant::create(constructed_name, constructed_priority, constructed_disposition));
- }
-
- SECTION("allows access to its disposition")
- {
- SECTION("allowing to get it")
- {
- REQUIRE(instance.property_disposition() == constructed_disposition);
- }
-
- SECTION("allowing to get it via a constant object")
- {
- auto const & cref = instance;
- REQUIRE(cref.property_disposition() == constructed_disposition);
- }
-
- SECTION("allowing to set it")
- {
- instance.property_disposition() = Disposition::Hostile;
- REQUIRE(instance.property_disposition() == Disposition::Hostile);
- }
- }
-
- SECTION("allows access to its name")
- {
- SECTION("allowing to get it")
- {
- REQUIRE(instance.property_name() == constructed_name);
- }
-
- SECTION("allowing to get it via a constant object")
- {
- auto const & cref = instance;
- REQUIRE(cref.property_name() == constructed_name);
- }
-
- SECTION("allowing to set it")
- {
- instance.property_name() = "replaced";
- REQUIRE(instance.property_name() == "replaced");
- }
- }
-
- SECTION("allows access to its priority")
- {
- SECTION("allowing to get it")
- {
- REQUIRE(instance.property_priority() == constructed_priority);
- }
-
- SECTION("allowing to get it via a constant object")
- {
- auto const & cref = instance;
- REQUIRE(cref.property_priority() == constructed_priority);
- }
-
- SECTION("allowing to set it")
- {
- instance.property_priority() = 4;
- REQUIRE(instance.property_priority() == 4);
- }
- }
-
- SECTION("can be compared with another participant")
- {
- auto equivalent_instance = Participant{"Equivalent", constructed_priority, constructed_disposition};
- auto lesser_instance = Participant{"Lesser", constructed_priority - 1, constructed_disposition};
- auto greater_instance = Participant{"Greater", constructed_priority + 1, constructed_disposition};
-
- SECTION("yielding std::partial_ordering::equivalent for itself")
- {
- REQUIRE((instance <=> equivalent_instance) == std::partial_ordering::equivalent);
- }
-
- SECTION("yielding std::partial_ordering::equivalent for an equivalent participant")
- {
- REQUIRE((instance <=> equivalent_instance) == std::partial_ordering::equivalent);
- }
-
- SECTION("yielding std::partial_ordering::greater for a lesser participant")
- {
- REQUIRE((instance <=> lesser_instance) == std::partial_ordering::greater);
- }
-
- SECTION("yielding std::partial_ordering::less for a greater participant")
- {
- REQUIRE((instance <=> greater_instance) == std::partial_ordering::less);
- }
- }
- }
-
- TEST_CASE("Serializing a participant")
- {
- auto instance = Participant::create("Participant #0", 17.2, Disposition::Friendly);
- auto serialized = instance->serialize();
-
- SECTION("the active state is serialized correctly")
- {
- REQUIRE_FALSE(serialized.at("is-active"));
- }
-
- SECTION("the disposition is serialized correctly")
- {
- REQUIRE(serialized.at("disposition") == Disposition::Friendly);
- }
-
- SECTION("the name is serialized correctly")
- {
- REQUIRE(serialized.at("name") == "Participant #0");
- }
-
- SECTION("the priority is serialized correctly")
- {
- REQUIRE(serialized.at("priority") == Catch::Approx{17.2});
- }
- }
-
- TEST_CASE("De-Serializing a participant")
- {
- auto serialized = nlohmann::json::parse(R"(
- {
- "name": "Participant #1",
- "priority": -2.3,
- "disposition": 2,
- "is-active": true
- }
- )");
- auto instance = Participant::create(serialized);
-
- SECTION("the active state is de-serialized correctly")
- {
- REQUIRE(instance->property_is_active());
- }
-
- SECTION("the disposition is de-serialized correctly")
- {
- REQUIRE(instance->property_disposition() == Disposition::Hostile);
- }
-
- SECTION("the name is de-serialized correctly")
- {
- REQUIRE(instance->property_name() == "Participant #1");
- }
-
- SECTION("the priority is de-serialized correctly")
- {
- REQUIRE(instance->property_priority() == Catch::Approx{-2.3});
- }
- }
-
-} // namespace turns::core::tests \ No newline at end of file
diff --git a/core/tests/single_participant.trns b/core/tests/single_participant.trns
deleted file mode 100644
index bcce137..0000000
--- a/core/tests/single_participant.trns
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "participants": [
- {
- "disposition": 0,
- "is-active": false,
- "is-defeated": false,
- "name": "Riamin",
- "priority": 0.0
- }
- ]
-} \ No newline at end of file
diff --git a/core/tests/turn_order_bugs.cpp b/core/tests/turn_order_bugs.cpp
deleted file mode 100644
index 7bfde78..0000000
--- a/core/tests/turn_order_bugs.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "turns/core/disposition.hpp"
-#include "turns/core/turn_order_model.hpp"
-
-#include <catch2/catch_test_macros.hpp>
-
-namespace turns::core::tests
-{
- /**
- * Bug description:
- *
- * After having stepped according to the step pattern below, tt was possible to step backward often enough to underflow the round number:
- * - forward
- * - backward
- * - forward
- */
- SCENARIO("Can step back infinitely", "[turn_order][bug]")
- {
- GIVEN("a non-empty turn_order")
- {
- auto instance = TurnOderModel::create();
-
- instance->add("A", 0, Disposition::Neutral);
-
- WHEN("it is started and then stepped forward, backward, forward")
- {
- instance->start();
- instance->next();
- instance->previous();
- instance->next();
-
- THEN("it is not possible to step backwards more than once")
- {
- instance->previous();
- instance->previous();
- REQUIRE(instance->round_number() == 0);
- }
- }
- }
- }
-} // namespace turns::core::tests \ No newline at end of file
diff --git a/core/tests/turn_order_model.cpp b/core/tests/turn_order_model.cpp
deleted file mode 100644
index 1cd3633..0000000
--- a/core/tests/turn_order_model.cpp
+++ /dev/null
@@ -1,314 +0,0 @@
-#include "turns/core/turn_order_model.hpp"
-
-#include "turns/core/disposition.hpp"
-#include "turns/core/participant.hpp"
-
-#include <catch2/catch_test_macros.hpp>
-
-#include <giomm/resource.h>
-
-#include <nlohmann/json.hpp>
-
-#include <string_view>
-
-namespace turns::core::tests
-{
- SCENARIO("Queries on a fresh turn_order instance", "[turn_order]")
- {
- GIVEN("an empty turn_order")
- {
- auto instance = TurnOderModel::create();
-
- THEN("get_n_items() returns 0")
- {
- REQUIRE(instance->get_n_items() == 0);
- }
-
- THEN("get_type() returns participant::get_type()")
- {
- REQUIRE(instance->get_item_type() == Participant::get_type());
- }
-
- THEN("get_typed_object(0) returns nullptr")
- {
- REQUIRE(instance->get_typed_object<Participant>(0) == nullptr);
- }
-
- THEN("has_next() returns false")
- {
- REQUIRE_FALSE(instance->has_next());
- }
-
- THEN("has_previous() returns false")
- {
- REQUIRE_FALSE(instance->has_previous());
- }
-
- THEN("is_empty() returns true")
- {
- REQUIRE(instance->is_empty());
- }
-
- THEN("is_running() returns false")
- {
- REQUIRE_FALSE(instance->is_running());
- }
-
- THEN("round_number() returns invalid_round_number")
- {
- REQUIRE(instance->round_number() == TurnOderModel::invalid_round_number);
- }
- }
- }
-
- SCENARIO("Adding participants")
- {
- auto instance = TurnOderModel::create();
-
- GIVEN("a participant has been added to a turn_order")
- {
- instance->add("Participant #0", 0, Disposition::Neutral);
-
- THEN("get_n_items() returns 1")
- {
- REQUIRE(instance->get_n_items() == 1);
- }
-
- THEN("get_typed_object(0) returns a non-null pointer")
- {
- REQUIRE(instance->get_typed_object<Participant>(0) != nullptr);
- }
-
- THEN("has_next() returns true")
- {
- REQUIRE(instance->has_next());
- }
-
- THEN("has_previous() returns false")
- {
- REQUIRE_FALSE(instance->has_previous());
- }
-
- THEN("is_empty() returns false")
- {
- REQUIRE_FALSE(instance->is_empty());
- }
-
- THEN("is_running() returns false")
- {
- REQUIRE_FALSE(instance->is_running());
- }
-
- THEN("round_number() returns invalid_round_number")
- {
- REQUIRE(instance->round_number() == TurnOderModel::invalid_round_number);
- }
-
- WHEN("the turn_order is start()ed")
- {
- instance->start();
-
- THEN("get_n_items() still returns 1")
- {
- REQUIRE(instance->get_n_items() == 1);
- }
-
- THEN("get_typed_object(0) still returns a non-null pointer")
- {
- REQUIRE(instance->get_typed_object<Participant>(0) != nullptr);
- }
-
- THEN("has_next() still returns true")
- {
- REQUIRE(instance->has_next());
- }
-
- THEN("has_previous() still returns false")
- {
- REQUIRE_FALSE(instance->has_previous());
- }
-
- THEN("is_empty() still returns false")
- {
- REQUIRE_FALSE(instance->is_empty());
- }
-
- THEN("is_running() returns true")
- {
- REQUIRE(instance->is_running());
- }
-
- THEN("round_number() returns 0")
- {
- REQUIRE(instance->round_number() == 0);
- }
-
- AND_WHEN("invoking previous()")
- {
- instance->previous();
-
- THEN("get_n_items() still returns 1")
- {
- REQUIRE(instance->get_n_items() == 1);
- }
-
- THEN("get_typed_object(0) still returns a non-null pointer")
- {
- REQUIRE(instance->get_typed_object<Participant>(0) != nullptr);
- }
-
- THEN("has_next() still returns true")
- {
- REQUIRE(instance->has_next());
- }
-
- THEN("has_previous() still returns false")
- {
- REQUIRE_FALSE(instance->has_previous());
- }
-
- THEN("is_empty() still returns false")
- {
- REQUIRE_FALSE(instance->is_empty());
- }
-
- THEN("is_running() returns true")
- {
- REQUIRE(instance->is_running());
- }
-
- THEN("round_number() returns 0")
- {
- REQUIRE(instance->round_number() == 0);
- }
- }
-
- AND_WHEN("invoking next()")
- {
- instance->next();
-
- THEN("get_n_items() still returns 1")
- {
- REQUIRE(instance->get_n_items() == 1);
- }
-
- THEN("get_typed_object(0) still returns a non-null pointer")
- {
- REQUIRE(instance->get_typed_object<Participant>(0) != nullptr);
- }
-
- THEN("has_next() still returns true")
- {
- REQUIRE(instance->has_next());
- }
-
- THEN("has_previous() returns true")
- {
- REQUIRE(instance->has_previous());
- }
-
- THEN("is_empty() still returns false")
- {
- REQUIRE_FALSE(instance->is_empty());
- }
-
- THEN("is_running() returns true")
- {
- REQUIRE(instance->is_running());
- }
-
- THEN("round_number() returns 1")
- {
- REQUIRE(instance->round_number() == 1);
- }
- }
- }
- }
- }
-
- SCENARIO("Loading from json data")
- {
- GIVEN("an empty turn order")
- {
- auto instance = TurnOderModel{};
- CHECK(instance.is_empty());
-
- WHEN("loading a serialized turn order with one named participant")
- {
- auto data = Gio::Resource::lookup_data_global("/ch/arknet/Turns/core-tests/single_participant.trns");
- auto size = 0uz;
- instance.load(nlohmann::json::parse(std::string_view{static_cast<char const *>(data->get_data(size)), data->get_size()}));
-
- THEN("it is no longer empty")
- {
- REQUIRE_FALSE(instance.is_empty());
- }
-
- THEN("it has 1 element")
- {
- REQUIRE(instance.get_n_items() == 1);
- }
-
- THEN("the single participant's name is set")
- {
- auto participant = instance.get_typed_object<Participant>(0);
- REQUIRE_FALSE(participant->get_name().empty());
- }
-
- AND_THEN("adding another participant with a higher priority")
- {
- auto participant = instance.get_typed_object<Participant>(0);
- instance.add("Higher Priority", 100.0f, Disposition::Neutral);
-
- THEN("the index of the test participant is 1")
- {
- CHECK(instance.get_typed_object<Participant>(0) != participant);
- REQUIRE(instance.get_typed_object<Participant>(1) == participant);
- }
- }
-
- AND_WHEN("calling clear")
- {
- instance.clear();
-
- THEN("it is empty")
- {
- REQUIRE(instance.is_empty());
- }
- }
- }
- }
- }
-
- SCENARIO("Sorting of participants")
- {
- GIVEN("A turn order with 3 participants (A,B,C) of priorities 100, 0, and -100 respectively")
- {
- auto instance = TurnOderModel{};
-
- instance.add("A", 100, Disposition::Friendly);
- instance.add("B", 0, Disposition::Friendly);
- instance.add("C", -100, Disposition::Friendly);
-
- THEN("A comes before B comes before C")
- {
- REQUIRE(instance.get_typed_object<Participant>(0)->get_name() == "A");
- REQUIRE(instance.get_typed_object<Participant>(1)->get_name() == "B");
- REQUIRE(instance.get_typed_object<Participant>(2)->get_name() == "C");
- }
-
- WHEN("changing the priority of the B to 50")
- {
- instance.get_typed_object<Participant>(1)->set_priority(50);
-
- THEN("the order stays the same")
- {
- REQUIRE(instance.get_typed_object<Participant>(0)->get_name() == "A");
- REQUIRE(instance.get_typed_object<Participant>(1)->get_name() == "B");
- REQUIRE(instance.get_typed_object<Participant>(2)->get_name() == "C");
- }
- }
- }
- }
-
-} // namespace turns::core::tests \ No newline at end of file
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
new file mode 100644
index 0000000..1ae7a31
--- /dev/null
+++ b/gui/CMakeLists.txt
@@ -0,0 +1,59 @@
+
+
+# add_executable("app"
+# "src/main.cpp"
+# )
+
+# target_link_libraries("app" PRIVATE
+# "$<$<AND:$<CXX_COMPILER_ID:GNU,Clang>,$<CONFIG:Debug>>:gcov>"
+
+# "PkgConfig::gtkmm"
+# "adwaitamm::adwaitamm"
+
+# "turns::core"
+# "turns::lang"
+
+# "$<$<CXX_COMPILER_ID:GNU,Clang>:-Wl,--whole-archive>"
+# "turns::ui"
+# "turns::style"
+# "$<$<CXX_COMPILER_ID:GNU,Clang>:-Wl,--no-whole-archive>"
+# )
+
+# target_add_glib_resources("app"
+# PREFIX "/ch/arknet/Turns"
+# UI_FILES "metainfo.xml"
+# )
+
+# set_target_properties("app" PROPERTIES
+# OUTPUT_NAME "turns"
+# )
+
+# install(TARGETS "app"
+# RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+# )
+
+# install(FILES
+# "${CMAKE_CURRENT_SOURCE_DIR}/metainfo.xml"
+# DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo"
+# RENAME "ch.arknet.Turns.metainfo.xml"
+# )
+
+# configure_file("desktop.in"
+# "turns.desktop"
+# )
+
+# install(FILES
+# "${CMAKE_CURRENT_BINARY_DIR}/turns.desktop"
+# DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications"
+# RENAME "ch.arknet.Turns.desktop"
+# )
+
+# configure_file("mime.xml"
+# "turns.xml"
+# )
+
+# install(FILES
+# "${CMAKE_CURRENT_BINARY_DIR}/turns.xml"
+# DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/mime/packages"
+# RENAME "ch.arknet.Turns.xml"
+# )
diff --git a/app/desktop.in b/gui/desktop.in
index 99c0307..99c0307 100644
--- a/app/desktop.in
+++ b/gui/desktop.in
diff --git a/lang/CMakeLists.txt b/gui/lang/CMakeLists.txt
index 1842615..1842615 100644
--- a/lang/CMakeLists.txt
+++ b/gui/lang/CMakeLists.txt
diff --git a/lang/include/turns/lang/messages.hpp b/gui/lang/include/turns/lang/messages.hpp
index e57fce4..e57fce4 100644
--- a/lang/include/turns/lang/messages.hpp
+++ b/gui/lang/include/turns/lang/messages.hpp
diff --git a/lang/po/de.po b/gui/lang/po/de.po
index 15c2d72..15c2d72 100644
--- a/lang/po/de.po
+++ b/gui/lang/po/de.po
diff --git a/lang/po/de_CH.po b/gui/lang/po/de_CH.po
index e79f91e..e79f91e 100644
--- a/lang/po/de_CH.po
+++ b/gui/lang/po/de_CH.po
diff --git a/lang/po/en.po b/gui/lang/po/en.po
index 54df09f..54df09f 100644
--- a/lang/po/en.po
+++ b/gui/lang/po/en.po
diff --git a/lang/tests/intl_test_init.cpp b/gui/lang/tests/intl_test_init.cpp
index 5438179..5438179 100644
--- a/lang/tests/intl_test_init.cpp
+++ b/gui/lang/tests/intl_test_init.cpp
diff --git a/lang/tests/messages.cpp b/gui/lang/tests/messages.cpp
index cecb038..cecb038 100644
--- a/lang/tests/messages.cpp
+++ b/gui/lang/tests/messages.cpp
diff --git a/app/metainfo.xml b/gui/metainfo.xml
index 621c1ee..621c1ee 100644
--- a/app/metainfo.xml
+++ b/gui/metainfo.xml
diff --git a/app/mime.xml b/gui/mime.xml
index 92e0ff4..92e0ff4 100644
--- a/app/mime.xml
+++ b/gui/mime.xml
diff --git a/app/schemas/ch.arknet.Turns.gschema.xml b/gui/schemas/ch.arknet.Turns.gschema.xml
index d764608..d764608 100644
--- a/app/schemas/ch.arknet.Turns.gschema.xml
+++ b/gui/schemas/ch.arknet.Turns.gschema.xml
diff --git a/core/src/settings.cpp b/gui/settings.cpp
index 13cf665..13cf665 100644
--- a/core/src/settings.cpp
+++ b/gui/settings.cpp
diff --git a/core/include/turns/core/settings.hpp b/gui/settings.hpp
index 304394d..304394d 100644
--- a/core/include/turns/core/settings.hpp
+++ b/gui/settings.hpp
diff --git a/gui/src/main.cpp b/gui/src/main.cpp
new file mode 100644
index 0000000..030aa0f
--- /dev/null
+++ b/gui/src/main.cpp
@@ -0,0 +1,97 @@
+// #include "turns/core/init.hpp"
+// #include "turns/core/settings.hpp"
+// #include "turns/ui/init.hpp"
+// #include "turns/ui/tracker.hpp"
+
+// #include <sigc++/adaptors/bind.h>
+// #include <sigc++/functors/mem_fun.h>
+
+// #include <glibmm/refptr.h>
+
+// #include <giomm/application.h>
+// #include <giomm/settings.h>
+
+// #include <gtkmm/application.h>
+// #include <gtkmm/builder.h>
+// #include <gtkmm/object.h>
+
+// #include <adwaitamm/aboutdialog.hpp>
+// #include <adwaitamm/application.hpp>
+// #include <adwaitamm/enums.hpp>
+// #include <adwaitamm/stylemanager.hpp>
+
+// #include <libintl.h>
+
+// #include <clocale>
+// #include <print>
+
+// auto show_about(Glib::RefPtr<Adwaita::Application> app)
+// {
+// auto active_window = app->get_active_window();
+// auto dialog = Gtk::make_managed<Adwaita::AboutDialog>("/ch/arknet/Turns/metainfo.xml", "");
+// dialog->present(active_window);
+// }
+
+// auto main(int argc, char * argv[]) -> int
+// {
+// setlocale(LC_ALL, "");
+// bindtextdomain("turns", LOCALEDIR);
+// bind_textdomain_codeset("turns", "UTF-8");
+// textdomain("turns");
+
+// auto app = Adwaita::Application::create("ch.arknet.Turns", Gio::Application::Flags::HANDLES_OPEN);
+// auto settings = turns::core::get_settings();
+
+// turns::core::register_types();
+
+// app->signal_startup().connect([app] {
+// turns::ui::register_types();
+
+// auto style_manager = Adwaita::StyleManager::get_default();
+// style_manager->set_color_scheme(Adwaita::ColorScheme::PreferLight);
+
+// app->add_action("quit", sigc::mem_fun(*app, &Adwaita::Application::quit));
+// app->add_action("about", sigc::bind(&show_about, app));
+// app->set_accel_for_action("app.quit", "<Primary>q");
+// app->set_accel_for_action("win.clear", "<Primary>x");
+// app->set_accel_for_action("win.next", "<Primary>space");
+// app->set_accel_for_action("win.previous", "<Primary>BackSpace");
+// app->set_accel_for_action("win.add_participant", "<Primary>a");
+// app->set_accel_for_action("win.open", "<Primary>o");
+// app->set_accel_for_action("win.preferences", "<Primary>comma");
+// app->set_accel_for_action("win.save", "<Primary>s");
+// app->set_accel_for_action("win.save-as", "<Primary><Shift>s");
+// });
+
+// app->signal_activate().connect([app, settings] {
+// auto window = new turns::ui::Tracker{app, settings};
+// window->present();
+// });
+
+// app->signal_open().connect([app, settings](auto files, auto) {
+// auto windows = app->get_windows();
+// auto window = static_cast<turns::ui::Tracker *>(nullptr);
+
+// if (windows.empty())
+// {
+// window = new turns::ui::Tracker{app, settings};
+// }
+// else
+// {
+// window = dynamic_cast<turns::ui::Tracker *>(windows[0]);
+// }
+
+// window->present();
+// window->load(files[0]);
+// });
+
+// app->signal_window_removed().connect([](auto window) {
+// auto tracker = dynamic_cast<turns::ui::Tracker *>(window);
+// if (tracker)
+// {
+// delete tracker;
+// }
+// });
+
+// return app->run(argc, argv);
+// } \ No newline at end of file
diff --git a/style/CMakeLists.txt b/gui/style/CMakeLists.txt
index 8ddbae8..8ddbae8 100644
--- a/style/CMakeLists.txt
+++ b/gui/style/CMakeLists.txt
diff --git a/style/style-dark.css b/gui/style/style-dark.css
index 928264a..928264a 100644
--- a/style/style-dark.css
+++ b/gui/style/style-dark.css
diff --git a/style/style.css b/gui/style/style.css
index a185c9b..a185c9b 100644
--- a/style/style.css
+++ b/gui/style/style.css
diff --git a/ui/CMakeLists.txt b/gui/ui/CMakeLists.txt
index 1584479..1584479 100644
--- a/ui/CMakeLists.txt
+++ b/gui/ui/CMakeLists.txt
diff --git a/ui/include/turns/ui/fwd.hpp b/gui/ui/include/turns/ui/fwd.hpp
index 69dc0b5..69dc0b5 100644
--- a/ui/include/turns/ui/fwd.hpp
+++ b/gui/ui/include/turns/ui/fwd.hpp
diff --git a/ui/include/turns/ui/init.hpp b/gui/ui/include/turns/ui/init.hpp
index 77bd009..77bd009 100644
--- a/ui/include/turns/ui/init.hpp
+++ b/gui/ui/include/turns/ui/init.hpp
diff --git a/ui/include/turns/ui/participant_editor.hpp b/gui/ui/include/turns/ui/participant_editor.hpp
index 0fbc504..0fbc504 100644
--- a/ui/include/turns/ui/participant_editor.hpp
+++ b/gui/ui/include/turns/ui/participant_editor.hpp
diff --git a/ui/include/turns/ui/participant_row.hpp b/gui/ui/include/turns/ui/participant_row.hpp
index 561214b..561214b 100644
--- a/ui/include/turns/ui/participant_row.hpp
+++ b/gui/ui/include/turns/ui/participant_row.hpp
diff --git a/ui/include/turns/ui/preferences.hpp b/gui/ui/include/turns/ui/preferences.hpp
index b68b91c..b68b91c 100644
--- a/ui/include/turns/ui/preferences.hpp
+++ b/gui/ui/include/turns/ui/preferences.hpp
diff --git a/ui/include/turns/ui/template_widget.hpp b/gui/ui/include/turns/ui/template_widget.hpp
index 7147560..7147560 100644
--- a/ui/include/turns/ui/template_widget.hpp
+++ b/gui/ui/include/turns/ui/template_widget.hpp
diff --git a/ui/include/turns/ui/tracker.hpp b/gui/ui/include/turns/ui/tracker.hpp
index 2e3adf5..2e3adf5 100644
--- a/ui/include/turns/ui/tracker.hpp
+++ b/gui/ui/include/turns/ui/tracker.hpp
diff --git a/ui/include/turns/ui/turn_order_view.hpp b/gui/ui/include/turns/ui/turn_order_view.hpp
index 8dae4e4..8dae4e4 100644
--- a/ui/include/turns/ui/turn_order_view.hpp
+++ b/gui/ui/include/turns/ui/turn_order_view.hpp
diff --git a/ui/src/init.cpp b/gui/ui/src/init.cpp
index 1c0295a..1c0295a 100644
--- a/ui/src/init.cpp
+++ b/gui/ui/src/init.cpp
diff --git a/ui/src/participant_editor.cpp b/gui/ui/src/participant_editor.cpp
index 8c83559..8c83559 100644
--- a/ui/src/participant_editor.cpp
+++ b/gui/ui/src/participant_editor.cpp
diff --git a/ui/src/participant_editor.ui b/gui/ui/src/participant_editor.ui
index 6bcf83e..6bcf83e 100644
--- a/ui/src/participant_editor.ui
+++ b/gui/ui/src/participant_editor.ui
diff --git a/ui/src/participant_row.cpp b/gui/ui/src/participant_row.cpp
index 7ce8e53..7ce8e53 100644
--- a/ui/src/participant_row.cpp
+++ b/gui/ui/src/participant_row.cpp
diff --git a/ui/src/participant_row.ui b/gui/ui/src/participant_row.ui
index b53cc53..b53cc53 100644
--- a/ui/src/participant_row.ui
+++ b/gui/ui/src/participant_row.ui
diff --git a/ui/src/preferences.cpp b/gui/ui/src/preferences.cpp
index 88e6d0f..88e6d0f 100644
--- a/ui/src/preferences.cpp
+++ b/gui/ui/src/preferences.cpp
diff --git a/ui/src/preferences.ui b/gui/ui/src/preferences.ui
index 0ee2699..0ee2699 100644
--- a/ui/src/preferences.ui
+++ b/gui/ui/src/preferences.ui
diff --git a/ui/src/tracker.cpp b/gui/ui/src/tracker.cpp
index d67a6e0..d67a6e0 100644
--- a/ui/src/tracker.cpp
+++ b/gui/ui/src/tracker.cpp
diff --git a/ui/src/tracker.ui b/gui/ui/src/tracker.ui
index c4fe324..c4fe324 100644
--- a/ui/src/tracker.ui
+++ b/gui/ui/src/tracker.ui
diff --git a/ui/src/tracker/actions.cpp b/gui/ui/src/tracker/actions.cpp
index ba48177..ba48177 100644
--- a/ui/src/tracker/actions.cpp
+++ b/gui/ui/src/tracker/actions.cpp
diff --git a/ui/src/tracker/event_handlers.cpp b/gui/ui/src/tracker/event_handlers.cpp
index 78eb82b..78eb82b 100644
--- a/ui/src/tracker/event_handlers.cpp
+++ b/gui/ui/src/tracker/event_handlers.cpp
diff --git a/ui/src/turn_order_view.cpp b/gui/ui/src/turn_order_view.cpp
index 08fdf5d..08fdf5d 100644
--- a/ui/src/turn_order_view.cpp
+++ b/gui/ui/src/turn_order_view.cpp
diff --git a/ui/src/turn_order_view.ui b/gui/ui/src/turn_order_view.ui
index 28a4bd0..28a4bd0 100644
--- a/ui/src/turn_order_view.ui
+++ b/gui/ui/src/turn_order_view.ui
diff --git a/ui/tests/gtk_test_init.cpp b/gui/ui/tests/gtk_test_init.cpp
index bfa885f..bfa885f 100644
--- a/ui/tests/gtk_test_init.cpp
+++ b/gui/ui/tests/gtk_test_init.cpp
diff --git a/ui/tests/participant_editor.cpp b/gui/ui/tests/participant_editor.cpp
index fee0313..fee0313 100644
--- a/ui/tests/participant_editor.cpp
+++ b/gui/ui/tests/participant_editor.cpp
diff --git a/ui/tests/participant_row.cpp b/gui/ui/tests/participant_row.cpp
index 20eaa5c..20eaa5c 100644
--- a/ui/tests/participant_row.cpp
+++ b/gui/ui/tests/participant_row.cpp
diff --git a/ui/tests/resources.cpp b/gui/ui/tests/resources.cpp
index a091266..a091266 100644
--- a/ui/tests/resources.cpp
+++ b/gui/ui/tests/resources.cpp
diff --git a/ui/tests/tracker.cpp b/gui/ui/tests/tracker.cpp
index 0d5e983..0d5e983 100644
--- a/ui/tests/tracker.cpp
+++ b/gui/ui/tests/tracker.cpp
diff --git a/ui/ui.cmb b/gui/ui/ui.cmb
index b246448..b246448 100644
--- a/ui/ui.cmb
+++ b/gui/ui/ui.cmb