Add support for auto-generated widget bindings

Additionally fix an update problem occurring with custom views
This commit is contained in:
david-swift 2024-01-22 21:41:21 +01:00
parent e5b5459d42
commit d8de611510
158 changed files with 13299 additions and 3050 deletions

View File

@ -12,14 +12,6 @@ body:
validations:
required: false
- type: textarea
attributes:
label: Name the equivalents in Libadwaita.
placeholder: >-
A list of the equivalents in the Libadwaita library (see dependencies).
validations:
required: true
- type: textarea
attributes:
label: Describe your idea for the implementation.

View File

@ -160,3 +160,6 @@ type_contents_order:
- view_life_cycle_method
- ib_action
- other_method
excluded:
- Sources/Adwaita/View/Generated/

View File

@ -36,6 +36,8 @@ Open the project folder in GNOME Builder, Xcode or another IDE.
- `User Interface` contains protocols and structures that are the basis of presenting content to the user.
- `View` contains structures that conform to the `View` protocol and provide an easier-to-use wrapper around a GTUI `NativeWidgetPeer` type.
- `Window` contains structures that conform to the `Window` protocol and simplify the creation of different types of windows.
- `CAdw` contains the reference to the C library.
- `Generation` contains the code for the auto-generation of Adwaita and Gtk widgets.
- `Tests` contains an example application for testing `Adwaita`.
### 4. Edit the Code

View File

@ -1,675 +1,21 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, 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
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state 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 program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
MIT License
Copyright (c) 2024 david-swift
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -15,25 +15,39 @@ let package = Package(
.library(
name: "Adwaita",
targets: ["Adwaita"]
),
.library(
name: "CAdw",
targets: ["CAdw"]
)
],
dependencies: [
.package(url: "https://github.com/AparokshaUI/Libadwaita", from: "0.1.6"),
.package(
url: "https://github.com/david-swift/LevenshteinTransformations",
from: "0.1.1"
)
),
.package(url: "https://github.com/CoreOffice/XMLCoder", from: "0.17.1")
],
targets: [
.systemLibrary(
name: "CAdw",
pkgConfig: "libadwaita-1"
),
.target(
name: "Adwaita",
dependencies: [
.product(name: "Libadwaita", package: "Libadwaita"),
"CAdw",
.product(name: "LevenshteinTransformations", package: "LevenshteinTransformations")
]
),
.executableTarget(
name: "Swift Adwaita Demo",
name: "Generation",
dependencies: [
.product(name: "XMLCoder", package: "XMLCoder")
]
),
.executableTarget(
name: "Demo",
dependencies: ["Adwaita"],
path: "Tests"
)

View File

@ -1,6 +1,6 @@
<p align="center">
<img width="256" alt="Adwaita Icon" src="Icons/AdwaitaIcon.png">
<h1 align="center">Adwaita</h1>
<h1 align="center">Adwaita for Swift</h1>
</p>
<p align="center">
@ -110,15 +110,17 @@ I recommend using the [template repository](https://github.com/AparokshaUI/Adwai
### Information
* [Widgets](user-manual/Information/Widgets.md)
* [Auto-Generated Widgets](user-manual/Information/AutoGeneratedWidgets.md)
## Thanks
### Dependencies
- [Libadwaita][18] licensed under the [GPL-3.0 license][19]
- [XMLCoder][18] licensed under the [MIT license][19]
- [Levenshtein Transformations](https://github.com/david-swift/LevenshteinTransformations) licensed under the [MIT license](https://github.com/david-swift/LevenshteinTransformations/blob/main/LICENSE.md)
### Other Thanks
- The [contributors][20]
- The auto-generation of widgets is based on [Swift Cross UI](https://github.com/stackotter/swift-cross-ui)
- [SwiftLint][21] for checking whether code style conventions are violated
- The programming language [Swift][22]
- [SourceDocs][23] used for generating the [docs][24]
@ -140,8 +142,8 @@ I recommend using the [template repository](https://github.com/AparokshaUI/Adwai
[15]: user-manual/Basics/Windows.md
[16]: user-manual/Basics/KeyboardShortcuts.md
[17]: user-manual/Advanced/CreatingWidgets.md
[18]: https://github.com/AparokshaUI/Libadwaita
[19]: https://github.com/AparokshaUI/Libadwaita/blob/main/LICENSE.md
[18]: https://github.com/CoreOffice/XMLCoder
[19]: https://github.com/CoreOffice/XMLCoder/blob/main/LICENSE
[20]: Contributors.md
[21]: https://github.com/realm/SwiftLint
[22]: https://github.com/apple/swift

View File

@ -17,6 +17,7 @@
## Information
* [Widgets](user-manual/Information/Widgets.md)
* [Auto-Generated Widgets](user-manual/Information/AutoGeneratedWidgets.md)
[1]: README.md
[2]: user-manual/GettingStarted.md

View File

@ -5,7 +5,7 @@
// Created by david-swift on 22.10.23.
//
import Libadwaita
import CAdw
/// A button widget for menus.
public struct MenuButton: MenuItem {
@ -19,6 +19,9 @@ public struct MenuButton: MenuItem {
/// Whether to prefer adding the action to the application window.
var preferApplicationWindow: Bool
/// The action label.
var filteredLabel: String { label.filter { $0.isLetter || $0.isNumber || $0 == "-" || $0 == "." } }
/// Initialize a menu button.
/// - Parameters:
/// - label: The buttons label.
@ -35,11 +38,13 @@ public struct MenuButton: MenuItem {
/// - menu: The menu.
/// - app: The application containing the menu.
/// - window: The application window containing the menu.
public func addMenuItem(menu: Libadwaita.Menu, app: GTUIApp, window: GTUIApplicationWindow?) {
public func addMenuItem(menu: OpaquePointer?, app: GTUIApp, window: GTUIApplicationWindow?) {
if let window, preferApplicationWindow {
_ = menu.append(label, window: window, shortcut: shortcut, handler: handler)
window.addKeyboardShortcut(shortcut, id: filteredLabel, handler: handler)
g_menu_append(menu, label, "win." + filteredLabel)
} else {
_ = menu.append(label, app: app, shortcut: shortcut, handler: handler)
app.addKeyboardShortcut(shortcut, id: filteredLabel, handler: handler)
g_menu_append(menu, label, "app." + filteredLabel)
}
}

View File

@ -5,7 +5,7 @@
// Created by david-swift on 22.10.23.
//
import Libadwaita
import CAdw
/// A section for menus.
public struct MenuSection: MenuItem {
@ -24,9 +24,9 @@ public struct MenuSection: MenuItem {
/// - menu: The menu.
/// - app: The application containing the menu.
/// - window: The application window containing the menu.
public func addMenuItem(menu: Libadwaita.Menu, app: GTUIApp, window: GTUIApplicationWindow?) {
let section = Libadwaita.Menu()
_ = menu.append("", section: section)
public func addMenuItem(menu: OpaquePointer?, app: GTUIApp, window: GTUIApplicationWindow?) {
let section = g_menu_new()
g_menu_append_section(menu, nil, section?.cast())
for element in sectionContent {
element.addMenuItems(menu: section, app: app, window: window)
}

View File

@ -5,7 +5,7 @@
// Created by david-swift on 22.10.23.
//
import Libadwaita
import CAdw
/// A submenu widget.
public struct Submenu: MenuItem {
@ -29,9 +29,9 @@ public struct Submenu: MenuItem {
/// - menu: The menu.
/// - app: The application containing the menu.
/// - window: The application window containing the menu.
public func addMenuItem(menu: Libadwaita.Menu, app: GTUIApp, window: GTUIApplicationWindow?) {
let submenu = Libadwaita.Menu()
_ = menu.append(label, submenu: submenu)
public func addMenuItem(menu: OpaquePointer?, app: GTUIApp, window: GTUIApplicationWindow?) {
let submenu = g_menu_new()
g_menu_append_submenu(menu, label, submenu?.cast())
for element in submenuContent {
element.addMenuItems(menu: submenu, app: app, window: window)
}

View File

@ -9,8 +9,6 @@
// https://gist.github.com/JadenGeller/c375fc15ad5900a0ddac4ed8ba8307a9
//
import Foundation
/// The ``ArrayBuilder`` is a simple result builder that outputs an array of any type.
///
/// You can define any array using Swift's DSL:

View File

@ -5,8 +5,8 @@
// Created by david-swift on 06.08.23.
//
import CAdw
import Foundation
import Libadwaita
/// A property wrapper for properties in a view that should be stored throughout view updates.
@propertyWrapper
@ -110,11 +110,23 @@ public struct State<Value>: StateProtocol {
}
}
/// The directory used for storing user data.
/// - Returns: The URL.
public static func userDataDir() -> URL {
.init(fileURLWithPath: .init(cString: g_get_user_data_dir()))
}
/// Copy a text to the clipboard.
/// - Parameter text: The text.
public static func copy(_ text: String) {
let clipboard = gdk_display_get_clipboard(gdk_display_get_default())
gdk_clipboard_set_text(clipboard, text)
}
/// Get the settings directory path.
/// - Returns: The path.
private func dirPath() -> URL {
NativePeer
.getUserDataDirectory()
Self.userDataDir()
.appendingPathComponent(content.storage.folder ?? GTUIApp.appID, isDirectory: true)
}

View File

@ -0,0 +1,44 @@
//
// Alignment.swift
// Adwaita
//
// Created by david-swift on 21.01.24.
//
import CAdw
/// The alignment for a widget.
public enum Alignment: Int {
/// The widget will fill the available space.
case fill
/// The widget will start at the beginning of the available space.
case start
/// The widget will end at the end of the available space.
case end
/// The widget will be centered in the available space.
case center
/// The widget will be baseline aligned in the available space.
case baselineFill
/// The widget will be baseline aligned at the start of the available space.
case baselineCenter
/// Get the GtkAlign alignment.
public var cAlign: GtkAlign {
switch self {
case .fill:
return GTK_ALIGN_FILL
case .start:
return GTK_ALIGN_START
case .end:
return GTK_ALIGN_END
case .center:
return GTK_ALIGN_CENTER
case .baselineFill:
return GTK_ALIGN_BASELINE_FILL
case .baselineCenter:
return GTK_ALIGN_BASELINE_CENTER
}
}
}

View File

@ -0,0 +1,20 @@
//
// Edge.swift
// Adwaita
//
// Created by david-swift on 21.01.24.
//
/// The edges for a widget.
public enum Edge {
/// The leading (start) edge.
case leading
/// The trailing (end) edge.
case trailing
/// The top edge.
case top
/// The bottom edge.
case bottom
}

View File

@ -0,0 +1,767 @@
//
// Icon.swift
// Adwaita
//
// Created by david-swift on 21.01.24.
//
import Foundation
// swiftlint:disable type_body_length file_length
/// An icon.
public enum Icon {
/// A preinstalled icon.
/// - Parameter icon: The default icon.
case `default`(icon: DefaultIcon)
/// A custom icon.
/// - Parameter name: The icon's name.
case custom(name: String)
/// A string representation of the icon.
public var string: String {
switch self {
case let .default(icon):
return icon.string
case let .custom(name):
return name
}
}
/// A preinstalled icon.
public enum DefaultIcon: String {
// swiftlint:disable missing_docs identifier_name
case acAdapter
case accessoriesCalculator
case accessoriesCharacterMap
case accessoriesDictionary
case accessoriesTextEditor
case actionUnavailable
case addressBookNew
case airplaneMode
case alarm
case appRemove
case appletsScreenshooter
case applicationCertificate
case applicationExitRtl
case applicationExit
case applicationRss_plus_xml
case applicationXAddon
case applicationXAppliance
case applicationXExecutable
case applicationXFirmware
case applicationXSharedlib
case applicationsEngineering
case applicationsGames
case applicationsGraphics
case applicationsMultimedia
case applicationsScience
case applicationsSystem
case applicationsUtilities
case appointmentMissed
case appointmentNew
case appointmentSoon
case audioCard
case audioHeadphones
case audioHeadset
case audioInputMicrophone
case audioSpeakersRtl
case audioSpeakers
case audioVolumeHighRtl
case audioVolumeHigh
case audioVolumeLowRtl
case audioVolumeLow
case audioVolumeMediumRtl
case audioVolumeMedium
case audioVolumeMutedRtl
case audioVolumeMuted
case audioVolumeOveramplifiedRtl
case audioVolumeOveramplified
case audioXGeneric
case authFace
case authFingerprint
case authSimLocked
case authSimMissing
case authSim
case authSmartcard
case avatarDefault
case batteryAction
case batteryCautionCharging
case batteryCaution
case batteryEmptyCharging
case batteryEmpty
case batteryFullCharged
case batteryFullCharging
case batteryFull
case batteryGoodCharging
case batteryGood
case batteryLevel_0Charging
case batteryLevel_0
case batteryLevel_10Charging
case batteryLevel_10
case batteryLevel_100Charged
case batteryLevel_100
case batteryLevel_20Charging
case batteryLevel_20
case batteryLevel_30Charging
case batteryLevel_30
case batteryLevel_40Charging
case batteryLevel_40
case batteryLevel_50Charging
case batteryLevel_50
case batteryLevel_60Charging
case batteryLevel_60
case batteryLevel_70Charging
case batteryLevel_70
case batteryLevel_80Charging
case batteryLevel_80
case batteryLevel_90Charging
case batteryLevel_90
case batteryLowCharging
case batteryLow
case batteryMissing
case battery
case bluetoothAcquiring
case bluetoothActive
case bluetoothDisabled
case bluetoothDisconnected
case bluetoothHardwareDisabled
case bluetooth
case bookmarkNew
case callIncoming
case callMissed
case callOutgoing
case callStart
case callStop
case cameraDisabled
case cameraHardwareDisabled
case cameraPhoto
case cameraSwitch
case cameraVideo
case cameraWeb
case capsLock
case changesAllow
case changesPrevent
case channelInsecure
case channelSecure
case chatMessageNew
case checkboxChecked
case checkboxMixed
case checkbox
case colorSelect
case colorimeterColorhug
case completionSnippet
case completionWord
case computerAppleIpad
case computerFail
case computer
case contactNew
case contentLoading
case daytimeSunrise
case daytimeSunset
case dialogError
case dialogInformation
case dialogPassword
case dialogQuestion
case dialogWarning
case displayBrightness
case displayProjector
case documentEdit
case documentNew
case documentOpenRecent
case documentOpen
case documentPageSetup
case documentPrintPreview
case documentPrint
case documentProperties
case documentRevertRtl
case documentRevert
case documentSaveAs
case documentSave
case documentSend
case driveHarddiskIeee1394
case driveHarddiskSolidstate
case driveHarddisk
case driveHarddiskSystem
case driveHarddiskUsb
case driveMultidisk
case driveOptical
case driveRemovableMedia
case editClearAll
case editClearRtl
case editClear
case editCopy
case editCut
case editDelete
case editFindReplace
case editFind
case editPaste
case editRedo
case editSelectAll
case editSelect
case editUndo
case emblemDefault
case emblemDocuments
case emblemFavorite
case emblemImportant
case emblemMusic
case emblemOk
case emblemPhotos
case emblemShared
case emblemSynchronizing
case emblemSystem
case emblemVideos
case emojiActivities
case emojiBody
case emojiFlags
case emojiFood
case emojiNature
case emojiObjects
case emojiPeople
case emojiRecent
case emojiSymbols
case emojiTravel
case emoteLove
case errorCorrect
case faceAngel
case faceAngry
case faceConfused
case faceCool
case faceCrying
case faceDevilish
case faceEmbarrassed
case faceGlasses
case faceKiss
case faceLaugh
case faceMonkey
case facePlain
case faceRaspberry
case faceSad
case faceShutmouth
case faceSick
case faceSmileBig
case faceSmile
case faceSmirk
case faceSurprise
case faceTired
case faceUncertain
case faceWink
case faceWorried
case faceYawn
case findLocation
case focusLegacySystray
case focusTopBar
case focusWindows
case folderDocuments
case folderDownload
case folderDragAccept
case folderMusic
case folderNew
case folderOpen
case folderPictures
case folderPublicshare
case folderRemote
case folderSavedSearch
case folder
case folderTemplates
case folderVideos
case folderVisiting
case fontSelect
case fontXGeneric
case formatIndentLessRtl
case formatIndentLess
case formatIndentMoreRtl
case formatIndentMore
case formatJustifyCenter
case formatJustifyFill
case formatJustifyLeft
case formatJustifyRight
case formatTextBold
case formatTextDirectionLtr
case formatTextDirectionRtl
case formatTextDirection
case formatTextItalic
case formatTextPlaintext
case formatTextRich
case formatTextStrikethrough
case formatTextUnderline
case functionLinear
case gestureSwipeLeft
case gestureSwipeRight
case gnomeDisksStateStandby
case gnomePowerManager
case goBottom
case goDown
case goFirst
case goHome
case goJumpRtl
case goJump
case goLast
case goNext
case goPrevious
case goTop
case goUp
case goaAccountExchange
case goaAccountGoogle
case goaAccountLastfm
case goaAccountMsn
case goaAccountOwncloud
case goaAccount
case goaPanel
case gtk3Demo
case gtk3WidgetFactory
case helpAbout
case helpBrowser
case helpContents
case helpFaq
case imageLoading
case imageMissing
case imageXGeneric
case info
case inodeDirectory
case inputDialpad
case inputGaming
case inputKeyboard
case inputMouse
case inputTablet
case inputTouchpad
case insertImage
case insertLink
case insertObject
case insertText
case keyboardBrightness
case langClass
case langDefine
case langEnum
case langEnumValue
case langFunction
case langInclude
case langMethod
case langNamespace
case langStructField
case langStruct
case langTypedef
case langUnion
case langVariable
case libreofficeBase
case libreofficeCalc
case libreofficeDraw
case libreofficeImpress
case libreofficeMain
case libreofficeMath
case libreofficeWriter
case listAdd
case listDragHandle
case listRemoveAll
case listRemove
case locationServicesActive
case locationServicesDisabled
case mailAttachment
case mailForward
case mailMarkImportant
case mailMarkJunk
case mailMarkNotjunk
case mailMessageNew
case mailRead
case mailRepliedRtl
case mailReplied
case mailReplyAllRtl
case mailReplyAll
case mailReplySender
case mailSendReceive
case mailSend
case mailUnread
case markLocation
case mediaEject
case mediaFlash
case mediaFloppy
case mediaOpticalBd
case mediaOpticalCdAudio
case mediaOpticalCd
case mediaOpticalDvd
case mediaOptical
case mediaPlaybackPause
case mediaPlaybackStart
case mediaPlaybackStop
case mediaPlaylistConsecutive
case mediaPlaylistRepeatSong
case mediaPlaylistRepeat
case mediaPlaylistShuffle
case mediaRecord
case mediaRemovable
case mediaSeekBackward
case mediaSeekForward
case mediaSkipBackward
case mediaSkipForward
case mediaTape
case mediaViewSubtitles
case mediaZip
case microphoneDisabled
case microphoneHardwareDisabled
case microphoneSensitivityHigh
case microphoneSensitivityLow
case microphoneSensitivityMedium
case microphoneSensitivityMuted
case modem
case multimediaPlayerAppleIpodTouch
case multimediaPlayer
case multimediaVolumeControl
case networkCellular_2g
case networkCellular_3g
case networkCellular_4g
case networkCellular_5g
case networkCellularAcquiringRtl
case networkCellularAcquiring
case networkCellularConnected
case networkCellularDisabledRtl
case networkCellularDisabled
case networkCellularEdge
case networkCellularGprs
case networkCellularHardwareDisabledRtl
case networkCellularHardwareDisabled
case networkCellularHspa
case networkCellularNoRouteRtl
case networkCellularNoRoute
case networkCellularOfflineRtl
case networkCellularOffline
case networkCellularSignalExcellentRtl
case networkCellularSignalExcellent
case networkCellularSignalGoodRtl
case networkCellularSignalGood
case networkCellularSignalNoneRtl
case networkCellularSignalNone
case networkCellularSignalOkRtl
case networkCellularSignalOk
case networkCellularSignalWeakRtl
case networkCellularSignalWeak
case networkCellular
case networkError
case networkIdle
case networkNoRoute
case networkOffline
case networkReceive
case networkServer
case networkTransmitReceive
case networkTransmit
case networkVpnAcquiring
case networkVpnDisabled
case networkVpnDisconnected
case networkVpnNoRoute
case networkVpn
case networkWiredAcquiring
case networkWiredDisconnected
case networkWiredNoRoute
case networkWired
case networkWirelessAcquiring
case networkWirelessConnected
case networkWirelessDisabled
case networkWirelessEncrypted
case networkWirelessHardwareDisabled
case networkWirelessHotspot
case networkWirelessNoRoute
case networkWirelessOffline
case networkWirelessSignalExcellent
case networkWirelessSignalGood
case networkWirelessSignalNone
case networkWirelessSignalOk
case networkWirelessSignalWeak
case networkWireless
case networkWorkgroup
case nightLightDisabled
case nightLight
case nmDeviceWiredSecure
case nmDeviceWired
case nmDeviceWwan
case nonStarred
case notificationsDisabled
case objectFlipHorizontal
case objectFlipVertical
case objectRotateLeft
case objectRotateRight
case objectSelect
case openMenu
case orca
case fedoraprojectAnacondaInstaller = "org.fedoraproject.AnacondaInstaller"
case freedesktopMalcontentControl = "org.freedesktop.MalcontentControl"
case gnomeAdwaita1Demo = "org.gnome.Adwaita1.Demo"
case gnomeBoxes = "org.gnome.Boxes"
case gnomeBuilder = "org.gnome.Builder"
case gnomeCalculator = "org.gnome.Calculator"
case gnomeCharacters = "org.gnome.Characters"
case gnomeCheese = "org.gnome.Cheese"
case gnomeConsole = "org.gnome.Console"
case gnomeDiskUtility = "org.gnome.DiskUtility"
case gnomeEpiphany = "org.gnome.Epiphany"
case gnomeEvince = "org.gnome.Evince"
case gnomeLogs = "org.gnome.Logs"
case gnomeMaps = "org.gnome.Maps"
case gnomeNautilus = "org.gnome.Nautilus"
case gnomePhotos = "org.gnome.Photos"
case gnomeRhythmbox3 = "org.gnome.Rhythmbox3"
case gnomeSettingsAbout = "org.gnome.Settings-about"
case gnomeSettingsAccessibility = "org.gnome.Settings-accessibility"
case gnomeSettingsAppearance = "org.gnome.Settings-appearance"
case gnomeSettingsApplications = "org.gnome.Settings-applications"
case gnomeSettingsBluetooth = "org.gnome.Settings-bluetooth"
case gnomeSettingsCamera = "org.gnome.Settings-camera"
case gnomeSettingsColor = "org.gnome.Settings-color"
case gnomeSettingsDefaultApps = "org.gnome.Settings-default-apps"
case gnomeSettingsDiagnostics = "org.gnome.Settings-diagnostics"
case gnomeSettingsDisplay = "org.gnome.Settings-display"
case gnomeSettingsFileHistory = "org.gnome.Settings-file-history"
case gnomeSettingsKeyboard = "org.gnome.Settings-keyboard"
case gnomeSettingsLocation = "org.gnome.Settings-location"
case gnomeSettingsMicrophone = "org.gnome.Settings-microphone"
case gnomeSettingsMobileNetwork = "org.gnome.Settings-mobile-network"
case gnomeSettingsMouse = "org.gnome.Settings-mouse"
case gnomeSettingsMultitasking = "org.gnome.Settings-multitasking"
case gnomeSettingsNetwork = "org.gnome.Settings-network"
case gnomeSettingsNotifications = "org.gnome.Settings-notifications"
case gnomeSettingsOnlineAccounts = "org.gnome.Settings-online-accounts"
case gnomeSettingsPower = "org.gnome.Settings-power"
case gnomeSettingsPinters = "org.gnome.Setting-printers"
case gnomeSettingsRegion = "org.gnome.Settings-region"
case gnomeSettingsRemovableMedia = "org.gnome.Settings-removable-media"
case gnomeSettingsSearch = "org.gnome.Settings-search"
case gnomeSettingsSharing = "org.gnome.Settings-sharing"
case gnomeSettingsSound = "org.gnome.Settings-sound"
case gnomeSettings = "org.gnome.Settings"
case gnomeSettingsSystemLockScreen = "org.gnome.Settings-system-lock-screen"
case gnomeSettingsThunderbolt = "org.gnome.Settings-thunderbolt"
case gnomeSettingsTime = "org.gnome.Settings-time"
case gnomeSettingsUsers = "org.gnome.Settings-users"
case gnomeSettingsWacom = "org.gnome.Settings-wacom"
case gnomeShellExtensions = "org.gnome.Shell.Extensions"
case gnomeSoftware = "org.gnome.Software"
case gnomeSystemMonitor = "org.gnome.SystemMonitor"
case gnomeTextEditor = "org.gnome.TextEditor"
case gnomeTotem = "org.gnome.Totem"
case gnomeWeather = "org.gnome.Weather"
case gnomeYelp = "org.gnome.Yelp"
case gnomeBaobab = "org.gnome.baobab"
case gnomeClocks = "org.gnome.clocks"
case gnomeDesignIconLibrary = "org.gnome.design.IconLibrary"
case gnomeEog = "org.gnome.eog"
case gnomeFontViewer = "org.gnome.font-viewer"
case gnomeTweaks = "org.gnome.tweaks"
case gtkDemo4 = "org.gtk.Demo4"
case gtkIconBrowser4 = "org.gtk.IconBrowser4"
case gtkPrintEditor4 = "org.gtk.PrintEditor4"
case gtkWidgetFactory4 = "org.gtk.WidgetFactory4"
case gtkGtk4NodeEditor = "org.gtk.gtk4.NodeEditor"
case orientationLandscapeInverse
case orientationLandscape
case orientationPortraitInverse
case orientationPortraitLeft
case orientationPortraitRight
case orientationProtrait
case packageXGeneric
case panDown
case panEnd
case panStart
case panUp
case panelBottom
case panelCenter
case panelLeft
case panelModified
case panelRight
case panelTop
case pda
case phoneAppleIphone
case phoneOld
case phone
case powerProfileBalancedRtl
case powerProfileBalanced
case powerProfilePerformanceRtl
case powerProfilePerformance
case powerProfilePowerSaverRtl
case powerProfilePowerSaver
case preferencesColor
case preferencesDesktopAccessibility
case preferencesDesktopAppearance
case preferencesDesktopApps
case preferencesDesktopDisplay
case preferencesDesktopFont
case preferencesDesktopKeyboardShortcuts
case preferencesDesktopKeyboard
case preferencesDesktopLocale
case preferencesDesktopMultitasking
case preferencesDesktopRemoteDesktop
case preferencesDesktopScreensaver
case preferencesDesktopWallpaper
case preferencesOther
case preferencesSystemDetails
case preferencesSystemDevices
case preferencesSystemNetworkProxy
case preferencesSystemNetwork
case preferencesSystemNotifications
case preferencesSystemParentalControls
case preferencesSystemPrivacy
case preferencesSystemSearch
case preferencesSystemSharing
case preferencesSystem
case preferencesSystemTime
case printerError
case printerNetwork
case printerPrinting
case printer
case printerWarning
case processStop
case processWorking
case radioChecked
case radioMixed
case radio
case rotationAllowed
case rotationLocked
case scanner
case screenShared
case securityHigh
case securityLow
case securityMediumRtl
case securityMedium
case selectionEnd
case selectionMode
case selectionStart
case semiStarredRtl
case semiStarred
case sendTo
case sidebarShowRight
case sidebarShow
case softwareUpdateAvailable
case softwareUpdateUrgent
case speedometer
case starNew
case starred
case startHere
case switchOff
case switchOn
case systemFileManager
case systemHelp
case systemLockScreen
case systemLogOutRtl
case systemLogOut
case systemReboot
case systemRun
case systemSearch
case systemShutdown
case systemSoftwareInstall
case systemSwitchUserRtl
case systemSwitchUser
case systemUsers
case tabNew
case tablet
case taskDue
case taskPastDue
case temperature
case textEditor
case textXGeneric
case thunderboltAcquiring
case thunderbolt
case toolsCheckSpelling
case totemTv
case touchDisabled
case touchpadDisabled
case tv
case uninterruptiblePowerSupply
case userAvailable
case userAway
case userBookmarks
case userBusy
case userDesktop
case userHome
case userIdle
case userInfo
case userInvisible
case userNotTracked
case userOffline
case userStatusPending
case userTrashFull
case userTrash
case utilitiesTerminal
case valueDecrease
case valueIncrease
case videoDisplay
case videoJoineDisplays
case videoSingleDisplay
case videoXGeneric
case viewAppGrid
case viewConceal
case viewContinuous
case viewDual
case viewFullscreen
case viewGrid
case viewListBulletRtl
case viewListBullet
case viewListOrderedRtl
case viewListOrdered
case viewListRtl
case viewList
case viewMirror
case viewMoreHorizontal
case viewMore
case viewPagedRtl
case viewPaged
case viewPin
case viewRefresh
case viewRestore
case viewReveal
case viewSortAscendingRtl
case viewSortAscending
case viewSortDescendingRtl
case viewSortDescending
case viewWrappedRtl
case viewWrapped
case weatherClearNight
case weatherClear
case weatherFewCloudsNight
case weatherFewClouds
case weatherFog
case weatherHourly
case weatherOvercast
case weatherSevereAlert
case weatherShowersScattered
case weatherShowers
case weatherSnow
case weatherStorm
case weatherTornado
case weatherWindy
case webBrowser
case windowClose
case windowMaximize
case windowMinimize
case windowNew
case windowRestore
case xOfficeAddressBook
case xOfficeCalendar
case xOfficeDocument
case xOfficeDrawing
case xOfficePresentation
case xOfficeSpreadsheet
case zoomFitBest
case zoomIn
case zoomOriginal
case zoomOut
// swiftlint:enable missing_docs identifier_name
/// A string representation of the icon.
public var string: String {
var string = rawValue
if !string.hasPrefix("org.") {
let result = string
.map { letter in
if letter.isUppercase {
return "-\(letter)"
} else {
return "\(letter)"
}
}
.joined()
string = result.lowercased()
}
string = string.replacingOccurrences(of: "_plus_", with: "+")
string = string.replacingOccurrences(of: "_", with: "-")
return string + "-symbolic"
}
}
}
// swiftlint:enable type_body_length file_length

View File

@ -0,0 +1,75 @@
//
// Transition.swift
// Adwaita
//
// Created by david-swift on 21.01.24.
//
import CAdw
/// A transition for a stack.
public enum Transition: Int {
// swiftlint:disable missing_docs discouraged_none_name
case none
case crossfade
case slideRight, slideLeft, slideUp, slideDown, slideLeftRight, slideUpDown
case coverUp, coverDown, coverLeft, coverRight
case uncoverUp, uncoverDown, uncoverLeft, uncoverRight
case coverUpDown, coverDownUp, coverLeftRight, coverRightLeft
case rotateLeft, rotateRight, rotateLeftRight
// swiftlint:enable missing_docs discouraged_none_name
/// Get the GtkStackTransitionType transition.
public var cTransition: GtkStackTransitionType {
switch self {
case .none:
return GTK_STACK_TRANSITION_TYPE_NONE
case .crossfade:
return GTK_STACK_TRANSITION_TYPE_CROSSFADE
case .slideRight:
return GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT
case .slideLeft:
return GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT
case .slideUp:
return GTK_STACK_TRANSITION_TYPE_SLIDE_UP
case .slideDown:
return GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN
case .slideLeftRight:
return GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT
case .slideUpDown:
return GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN
case .coverUp:
return GTK_STACK_TRANSITION_TYPE_OVER_UP
case .coverDown:
return GTK_STACK_TRANSITION_TYPE_OVER_DOWN
case .coverLeft:
return GTK_STACK_TRANSITION_TYPE_OVER_LEFT
case .coverRight:
return GTK_STACK_TRANSITION_TYPE_OVER_RIGHT
case .uncoverUp:
return GTK_STACK_TRANSITION_TYPE_UNDER_UP
case .uncoverDown:
return GTK_STACK_TRANSITION_TYPE_UNDER_DOWN
case .uncoverLeft:
return GTK_STACK_TRANSITION_TYPE_UNDER_LEFT
case .uncoverRight:
return GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT
case .coverUpDown:
return GTK_STACK_TRANSITION_TYPE_OVER_UP_DOWN
case .coverDownUp:
return GTK_STACK_TRANSITION_TYPE_OVER_DOWN_UP
case .coverLeftRight:
return GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT
case .coverRightLeft:
return GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT
case .rotateLeft:
return GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT
case .rotateRight:
return GTK_STACK_TRANSITION_TYPE_ROTATE_RIGHT
case .rotateLeftRight:
return GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT_RIGHT
}
}
}

View File

@ -5,7 +5,7 @@
// Created by david-swift on 06.08.23.
//
import Libadwaita
import Foundation
extension Array: View where Element == View {
@ -22,7 +22,7 @@ extension Array: View where Element == View {
var modified = self
for (index, view) in modified.enumerated() {
for modifier in modifiers {
modified[index] = modifier(view)
modified[safe: index] = modifier(view)
}
}
return VStack { modified }
@ -53,6 +53,28 @@ extension Array where Element == WindowSceneGroup {
}
extension Array where Element == String {
/// Get the C version of the array.
var cArray: UnsafePointer<UnsafePointer<CChar>?>? {
let cStrings = self.map { $0.utf8CString }
let cStringPointers = cStrings.map { $0.withUnsafeBufferPointer { $0.baseAddress } }
let optionalCStringPointers = cStringPointers + [nil]
var optionalCStringPointersCopy = optionalCStringPointers
optionalCStringPointersCopy.withUnsafeMutableBufferPointer { bufferPointer in
bufferPointer.baseAddress?.advanced(by: cStrings.count).pointee = nil
}
let flatArray = optionalCStringPointersCopy.compactMap { $0 }
let pointer = UnsafeMutablePointer<UnsafePointer<CChar>?>.allocate(capacity: flatArray.count + 1)
for (index, element) in flatArray.enumerated() {
pointer.advanced(by: index).pointee = element
}
pointer.advanced(by: flatArray.count).pointee = nil
return UnsafePointer(pointer)
}
}
extension Array {
/// Accesses the element at the specified position safely.

View File

@ -0,0 +1,15 @@
//
// Bool.swift
// Adwaita
//
// Created by david-swift on 15.01.24.
//
extension Bool {
/// Get the gboolean for C.
public var cBool: Int32 {
self ? 1 : 0
}
}

View File

@ -0,0 +1,17 @@
//
// Int.swift
// Adwaita
//
// Created by david-swift on 15.01.24.
//
extension Int: Identifiable {
/// Get the integer itself as the identifier.
public var id: Int { self }
/// The C integer.
public var cInt: Int32 {
.init(self)
}
}

View File

@ -1,74 +0,0 @@
//
// Libadwaita.FileDialog.swift
// Adwaita
//
// Created by david-swift on 09.12.23.
//
import Foundation
import Libadwaita
extension Libadwaita.FileDialog: WindowType {
/// An ID for the importer field.
static var importer: String { "importer" }
/// An ID for the folder field.
static var folder: String { "folder" }
/// An ID for the result field.
static var result: String { "result" }
/// An ID for the cancel field.
static var cancel: String { "cancel" }
/// Whether the file dialog is an importer.
var isImporter: Bool {
get {
fields[Self.importer] as? Bool ?? true
}
set {
fields[Self.importer] = newValue
}
}
/// The selected folder in the file dialog.
var folder: URL? {
get {
fields[Self.folder] as? URL
}
set {
fields[Self.folder] = newValue
}
}
/// A closure triggered on selecting a file in the dialog.
var onResult: ((URL) -> Void) {
get {
fields[Self.result] as? (URL) -> Void ?? { _ in }
}
set {
fields[Self.result] = newValue
}
}
/// A closure triggered when the dialog is canceled.
var onCancel: (() -> Void) {
get {
fields[Self.cancel] as? () -> Void ?? { }
}
set {
fields[Self.cancel] = newValue
}
}
/// Set the window's parent window.
/// - Parameter parent: The parent window.
///
/// Currently not implemented.
public func setParentWindow(_ parent: WindowType) { }
/// Display the file dialog.
public func show() {
if isImporter {
self.open(folder: folder, onResult, onClose: onCancel)
} else {
self.save(folder: folder, onResult, onClose: onCancel)
}
}
}

View File

@ -1,37 +0,0 @@
//
// NativeWidgetPeer.swift
// Adwaita
//
// Created by david-swift on 05.08.23.
//
import Libadwaita
extension NativeWidgetPeer: Widget {
/// A `Libadwaita.NativeWidgetPeer` is static.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) { }
/// A `Libadwaita.NativeWidgetPeer`'s container is itself.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let bold = "\(modifier(code: 1))"
let yellow = 33
let warning = "\(modifier(code: yellow))\(bold)"
let reset = modifier(code: 0)
print("\(warning)warning: \(reset)discouraged use of GTUI widgets (here: \(bold)\(Self.self)\(reset)) in views")
return .init(self)
}
/// Get a modifier stirng.
/// - Parameter code: The modifier.
/// - Returns: The string.
private func modifier(code: Int) -> String {
"\u{001B}[\(code)m"
}
}

View File

@ -0,0 +1,16 @@
//
// OpaquePointer.swift
// Adwaita
//
// Created by david-swift on 15.01.23.
//
extension OpaquePointer {
/// Convert an opaque pointer into an unsafe mutable pointer with a defined type.
/// - Returns: The unsafe mutable pointer.
public func cast<T>() -> UnsafeMutablePointer<T> {
.init(self)
}
}

View File

@ -0,0 +1,35 @@
//
// Set.swift
// Adwaita
//
// Created by david-swift on 21.01.24.
//
extension Set where Element == Edge {
/// Horizontal and vertical edges.
public static var all: Self { vertical.union(horizontal) }
/// Top and bottom edges.
public static var vertical: Self { top.union(bottom) }
/// Leading and trailing edges.
public static var horizontal: Self { leading.union(trailing) }
/// Top edge.
public static var top: Self { [.top] }
/// Bottom edge.
public static var bottom: Self { [.bottom] }
/// Leading edge.
public static var leading: Self { [.leading] }
/// Trailing edge.
public static var trailing: Self { [.trailing] }
/// Add a collection of edges to a collection of edges.
/// - Parameter edges: The collection of edges.
/// - Returns: Both collections combined.
public func add(_ edges: Self) -> Self { union(edges) }
}

View File

@ -14,4 +14,28 @@ extension String {
/// A label for the navigation label in a GTUI widget's fields.
static var navigationLabel: Self { "navigation-label" }
/// Add the Ctrl key to a shortcut.
/// - Returns: The shortcut.
public func ctrl() -> String { "<Ctrl>\(self)" }
/// Add the Shift key to a shortcut.
/// - Returns: The shortcut.
public func shift() -> String { "<Shift>\(self)" }
/// Add the Alt key to a shortcut.
/// - Returns: The shortcut.
public func alt() -> String { "<Alt>\(self)" }
/// Add the Meta key to a shortcut.
/// - Returns: The shortcut.
public func meta() -> String { "<Meta>\(self)" }
/// Add the Super key to a shortcut.
/// - Returns: The shortcut.
public func `super`() -> String { "<Super>\(self)" }
/// Add the Hyper key to a shortcut.
/// - Returns: The shortcut.
public func hyper() -> String { "<Hyper>\(self)" }
}

View File

@ -0,0 +1,15 @@
//
// UInt.swift
// Adwaita
//
// Created by david-swift on 19.01.24.
//
extension UInt {
/// Convert an unsigned integer into the C form.
public var cInt: UInt32 {
.init(self)
}
}

View File

@ -0,0 +1,23 @@
//
// UnsafeMutablePointer.swift
// Adwaita
//
// Created by david-swift on 15.01.24.
//
extension UnsafeMutablePointer {
/// Convert into an opaque pointer.
/// - Returns: The opaque pointer.
public func opaque() -> OpaquePointer {
.init(self)
}
/// Convert into an unsafe mutable pointer of another type.
/// - Returns: The unsafe mutable pointer.
public func cast<T>() -> UnsafeMutablePointer<T> {
let pointer = UnsafeMutableRawPointer(self).bindMemory(to: T.self, capacity: 1)
return UnsafeMutablePointer<T>(mutating: pointer)
}
}

View File

@ -0,0 +1,17 @@
//
// UnsafeMutableRawPointer.swift
// Adwaita
//
// Created by david-swift on 15.01.24.
//
extension UnsafeMutableRawPointer {
/// Convert into an unsafe mutable pointer of a certain type.
/// - Returns: The unsafe mutable pointer.
public func cast<T>() -> UnsafeMutablePointer<T> {
let pointer = UnsafeMutableRawPointer(self).bindMemory(to: T.self, capacity: 1)
return UnsafeMutablePointer<T>(mutating: pointer)
}
}

View File

@ -5,8 +5,6 @@
// Created by david-swift on 05.08.23.
//
import Libadwaita
/// A structure conforming to `App` is the entry point of your app.
///
/// ```swift

View File

@ -5,16 +5,21 @@
// Created by david-swift on 05.08.23.
//
import Libadwaita
import CAdw
/// The GTUI application.
public class GTUIApp: Application {
public class GTUIApp {
/// The handlers which are called when a state changes.
static var updateHandlers: [() -> Void] = []
/// The app's id for the file name for storing the data.
static var appID = "temporary"
/// The pointer to the application.
public var pointer: UnsafeMutablePointer<GtkApplication>?
/// Fields for additional information.
public var fields: [String: Any] = [:]
/// The app's content.
var body: () -> App
/// The scenes that are displayed.
@ -28,11 +33,11 @@ public class GTUIApp: Application {
/// - body: The application's content.
init(_ id: String, body: @escaping () -> App) {
self.body = body
super.init(name: id)
self.pointer = adw_application_new(id, G_APPLICATION_DEFAULT_FLAGS)?.cast()
}
/// The entry point of the application.
override public func onActivate() {
public func onActivate() {
let body = body()
for windowScene in body.scene.windows() {
for _ in 0..<windowScene.open {
@ -42,6 +47,53 @@ public class GTUIApp: Application {
}
}
/// Run the application.
public func run() {
let data = ViewStorage.SignalData { self.onActivate() }
fields["run"] = data
g_signal_connect_data(
pointer?.cast(),
"activate",
unsafeBitCast(data.handler, to: GCallback.self),
Unmanaged.passUnretained(data).toOpaque().cast(),
nil,
G_CONNECT_AFTER
)
g_application_run(pointer?.cast(), 0, nil)
}
/// Add a keyboard shortcut to the application.
/// - Parameters:
/// - shortcut: The keyboard shortcut.
/// - id: The action's id.
/// - window: Optionally an application window.
/// - handler: The action's handler.
public func addKeyboardShortcut(
_ shortcut: String,
id: String,
window: GTUIApplicationWindow? = nil,
handler: @escaping () -> Void
) {
let action = g_simple_action_new(id, nil)
let data = ViewStorage.SignalData(closure: handler)
g_signal_connect_data(
action?.cast(),
"activate",
unsafeBitCast(data.threeParamsHandler, to: GCallback.self),
Unmanaged.passUnretained(data).toOpaque().cast(),
nil,
G_CONNECT_AFTER
)
if let window {
g_action_map_add_action(.init(window.pointer), action)
window.fields[id] = data
} else {
g_action_map_add_action(.init(pointer), action)
fields[id] = data
}
gtk_application_set_accels_for_action(pointer, (window == nil ? "app." : "win.") + id, [shortcut].cArray)
}
/// Focus the window with a certain id. Create the window if it doesn't already exist.
/// - Parameters:
/// - id: The window's id.
@ -75,4 +127,10 @@ public class GTUIApp: Application {
}
}
}
/// Terminate the application.
public func quit() {
g_application_quit(pointer?.cast())
}
}

View File

@ -5,7 +5,7 @@
// Created by david-swift on 22.10.23.
//
import Libadwaita
import CAdw
/// A structure representing the content for a certain menu item type.
public protocol MenuItem: MenuItemGroup {
@ -15,7 +15,7 @@ public protocol MenuItem: MenuItemGroup {
/// - menu: The menu.
/// - app: The application containing the menu.
/// - window: The application window containing the menu.
func addMenuItem(menu: Libadwaita.Menu, app: GTUIApp, window: GTUIApplicationWindow?)
func addMenuItem(menu: OpaquePointer?, app: GTUIApp, window: GTUIApplicationWindow?)
}

View File

@ -5,7 +5,7 @@
// Created by david-swift on 22.10.23.
//
import Libadwaita
import CAdw
/// A structure conforming to `MenuItemGroup` can be added to the content accepting a menu.
public protocol MenuItemGroup {
@ -19,7 +19,7 @@ extension MenuItemGroup {
/// Add the menu items described by the group to a menu.
/// - Parameter menu: The menu.
func addMenuItems(menu: Libadwaita.Menu, app: GTUIApp, window: GTUIApplicationWindow?) {
func addMenuItems(menu: OpaquePointer?, app: GTUIApp, window: GTUIApplicationWindow?) {
for element in content {
if let item = element as? MenuItem {
item.addMenuItem(menu: menu, app: app, window: window)

View File

@ -5,8 +5,6 @@
// Created by david-swift on 05.08.23.
//
import Libadwaita
/// A structure conforming to `View` is referred to as a view.
/// It can be part of a body.
///
@ -37,13 +35,7 @@ extension View {
if let peer = modified as? Widget {
return peer
} else {
var state: [String: StateProtocol] = [:]
for property in Mirror(reflecting: self).children {
if let label = property.label, let value = property.value as? StateProtocol {
state[label] = value
}
}
return StateWrapper(content: { view }, state: state)
return StateWrapper(content: { view }, state: getState())
}
}
@ -56,10 +48,20 @@ extension View {
if let widget = modified as? Widget {
widget.update(storage, modifiers: modifiers)
} else {
StateWrapper { self }.update(storage, modifiers: modifiers)
StateWrapper(content: { view }, state: getState()).update(storage, modifiers: modifiers)
}
}
func getState() -> [String: StateProtocol] {
var state: [String: StateProtocol] = [:]
for property in Mirror(reflecting: self).children {
if let label = property.label, let value = property.value as? StateProtocol {
state[label] = value
}
}
return state
}
/// Get a storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The storage.

View File

@ -5,31 +5,194 @@
// Created by david-swift on 31.08.23.
//
import Libadwaita
import CAdw
/// Store a rendered view in a view storage.
public class ViewStorage {
/// The GTUI widget.
public var view: NativeWidgetPeer
/// The pointer.
public var pointer: OpaquePointer?
/// The view's content.
public var content: [String: [ViewStorage]]
/// The view's state (used in `StateWrapper`).
public var state: [String: StateProtocol]
/// The signal handlers.
public var handlers: [String: SignalData] = [:]
/// Other properties.
public var fields: [String: Any] = [:]
/// Initialize a view storage.
/// - Parameters:
/// - view: The GTUI widget.
/// - pointer: The pointer to the Gtk widget.
/// - content: The view's content.
/// - state: The view's state.
public init(
_ view: NativeWidgetPeer,
_ pointer: OpaquePointer?,
content: [String: [ViewStorage]] = [:],
state: [String: StateProtocol] = [:]
) {
self.view = view
self.pointer = pointer
self.content = content
self.state = state
}
/// Data to pass to signal handlers.
public class SignalData {
/// The closure.
public var closure: ([UnsafeMutableRawPointer]) -> Void
/// The closure as a C handler.
var handler: @convention(c) (UnsafeMutableRawPointer, UnsafeMutableRawPointer) -> Void {
{ _, data in
let data = unsafeBitCast(data, to: SignalData.self)
data.closure([])
}
}
/// The closure as a C handler with three parameters.
var threeParamsHandler: @convention(c) (
UnsafeMutableRawPointer,
UnsafeMutableRawPointer,
UnsafeMutableRawPointer
) -> Void {
{ _, arg1, data in
let data = unsafeBitCast(data, to: SignalData.self)
data.closure([arg1])
}
}
/// The closure as a C handler with four parameters.
var fourParamsHandler: @convention(c) (
UnsafeMutableRawPointer,
UnsafeMutableRawPointer,
UnsafeMutableRawPointer,
UnsafeMutableRawPointer
) -> Void {
{ _, arg1, arg2, data in
let data = unsafeBitCast(data, to: SignalData.self)
data.closure([arg1, arg2])
}
}
/// The closure as a C handler with five parameters.
var fiveParamsHandler: @convention(c) (
UnsafeMutableRawPointer,
UnsafeMutableRawPointer,
UnsafeMutableRawPointer,
UnsafeMutableRawPointer,
UnsafeMutableRawPointer
) -> Void {
{ _, arg1, arg2, arg3, data in
let data = unsafeBitCast(data, to: SignalData.self)
data.closure([arg1, arg2, arg3])
print("Hi")
}
}
/// Initialize the signal data.
/// - Parameter closure: The signal's closure.
public convenience init(closure: @escaping () -> Void) {
self.init { _ in closure() }
}
/// Initialize the signal data.
/// - Parameter closure: The signal's closure.
public init(closure: @escaping ([UnsafeMutableRawPointer]) -> Void) {
self.closure = closure
}
}
/// Connect a handler to the observer of a property.
/// - Parameters:
/// - name: The property's name.
/// - id: The handlers id to separate form others connecting to the signal.
/// - connectFlags: The GConnectFlags.
/// - handler: The signal's handler.
public func notify(
name: String,
id: String = "",
connectFlags: GConnectFlags = G_CONNECT_AFTER,
handler: @escaping () -> Void
) {
let name = "notify::" + name
connectSignal(name: name, id: id, connectFlags: connectFlags, argCount: 1, handler: handler)
}
/// Connect a handler to a signal.
/// - Parameters:
/// - name: The signal's name.
/// - id: The handlers id to separate form others connecting to the signal.
/// - connectFlags: The GConnectFlags.
/// - argCount: The number of additional arguments (without the first and the last one).
/// - handler: The signal's handler.
public func connectSignal(
name: String,
id: String = "",
connectFlags: GConnectFlags = G_CONNECT_AFTER,
argCount: Int = 0,
handler: @escaping () -> Void
) {
connectSignal(name: name, id: id, connectFlags: connectFlags, argCount: argCount) { _ in
handler()
}
}
/// Connect a handler to a signal.
/// - Parameters:
/// - name: The signal's name.
/// - id: The handlers id to separate form others connecting to the signal.
/// - connectFlags: The GConnectFlags.
/// - argCount: The number of additional arguments (without the first and the last one).
/// - handler: The signal's handler.
public func connectSignal(
name: String,
id: String = "",
connectFlags: GConnectFlags = G_CONNECT_AFTER,
argCount: Int = 0,
handler: @escaping ([UnsafeMutableRawPointer]) -> Void
) {
if let data = handlers[name + id] {
data.closure = handler
} else {
let data = SignalData(closure: handler)
handlers[name + id] = data
let callback: GCallback
let three = 3
let two = 2
if argCount >= three {
callback = unsafeBitCast(data.fiveParamsHandler, to: GCallback.self)
} else if argCount == two {
callback = unsafeBitCast(data.fourParamsHandler, to: GCallback.self)
} else if argCount == 1 {
callback = unsafeBitCast(data.threeParamsHandler, to: GCallback.self)
} else {
callback = unsafeBitCast(data.handler, to: GCallback.self)
}
g_signal_connect_data(
pointer?.cast(),
name,
callback,
Unmanaged.passUnretained(data).toOpaque().cast(),
nil,
connectFlags
)
}
}
/// Modify the view.
/// - Parameter modify: The modification function.
public func modify(_ modify: (OpaquePointer?) -> Void) {
modify(pointer)
}
/// Convert the pointer to a pointer of a certain type and modify the view.
/// - Parameters:
/// - type: The pointer's type.
/// - modify: The modification function.
public func modify<T>(_ type: T.Type, _ modify: (UnsafeMutablePointer<T>?) -> Void) {
modify(pointer?.cast())
}
}

View File

@ -5,8 +5,6 @@
// Created by david-swift on 16.08.23.
//
import Libadwaita
/// A widget is a view that know about its GTUI widget.
public protocol Widget: View {

View File

@ -0,0 +1,49 @@
//
// GTUIAboutWindow.swift
// Adwaita
//
// Created by david-swift on 21.01.24.
//
import CAdw
/// A GTUI about window.
public class GTUIAboutWindow: GTUIWindow {
/// Initialize an about window using the AppStream metadata.
/// - Parameter filePath: The path.
public init(filePath: String? = nil) {
super.init(fields: [:])
if let filePath {
pointer = adw_about_window_new_from_appdata(filePath, nil)?.cast()
} else {
pointer = adw_about_window_new()?.cast()
}
}
/// Set the general data.
/// - Parameters:
/// - title: The app name.
/// - icon: The app icon.
/// - developer: The app's developer.
/// - version: The app's version.
public func generalData(title: String, icon: Icon, developer: String, version: String) {
adw_about_window_set_application_name(.init(pointer), title)
adw_about_window_set_application_icon(.init(pointer), icon.string)
adw_about_window_set_developer_name(.init(pointer), developer)
adw_about_window_set_version(.init(pointer), version)
}
/// Set the website.
/// - Parameter url: The website.
public func website(url: String) {
adw_about_window_set_website(.init(pointer), url)
}
/// Set the URL for issues.
/// - Parameter issues: The issues website.
public func issues(url: String) {
adw_about_window_set_issue_url(.init(pointer), url)
}
}

View File

@ -5,7 +5,35 @@
// Created by david-swift on 19.10.23.
//
import Libadwaita
import CAdw
/// A GTUI application window.
public typealias GTUIApplicationWindow = Libadwaita.ApplicationWindow
public class GTUIApplicationWindow: GTUIWindow {
/// The window's parent app.
public var app: GTUIApp
/// Initialize the application window.
/// - Parameter app: The application.
public init(app: GTUIApp) {
self.app = app
super.init(fields: [:])
pointer = adw_application_window_new(app.pointer)?.cast()
}
/// Add a keyboard shortcut.
/// - Parameters:
/// - shortcut: The keyboard shortcut.
/// - id: The action's id.
/// - handler: The action's handler.
public func addKeyboardShortcut(_ shortcut: String, id: String, handler: @escaping () -> Void) {
app.addKeyboardShortcut(shortcut, id: id, window: self, handler: handler)
}
/// Set the window's child.
/// - Parameter child: The child.
override public func setChild(_ child: OpaquePointer?) {
adw_application_window_set_content(pointer?.cast(), child?.cast())
}
}

View File

@ -0,0 +1,138 @@
//
// GTUIFileDialog.swift
// Adwaita
//
// Created by david-swift on 09.12.23.
//
import CAdw
import Foundation
/// A GTUI file dialog window.
public class GTUIFileDialog: WindowType {
/// The file dialog's pointer.
public var pointer: OpaquePointer?
/// Fields for additional data.
public var fields: [String: Any] = [:]
/// A link to the file dialog.
var selfAddr: UInt64 {
unsafeBitCast(self, to: UInt64.self)
}
/// The parent window.
var parent: OpaquePointer?
/// Whether the file dialog is an importer.
var isImporter = false
/// The selected folder in the file dialog.
var folder: URL?
/// A closure triggered on selecting a file in the dialog.
var onResult: (URL) -> Void = { _ in }
/// A closure triggered when the dialog is canceled.
var onCancel: () -> Void = { }
/// Initialize the window.
public init() {
pointer = gtk_file_dialog_new()
}
/// Set the window's parent window.
/// - Parameter parent: The parent window.
public func setParentWindow(_ parent: WindowType) {
if let window = parent as? GTUIWindow {
self.parent = .init(window.pointer)
}
}
/// Set the initial name.
/// - Parameter name: The parent window.
public func setInitialName(_ name: String) {
gtk_file_dialog_set_initial_name(pointer, name)
}
// swiftlint:disable discouraged_optional_collection
/// Set the allowed file extensions.
/// - Parameters:
/// - extensions: The file extensions.
public func setExtensions(_ extensions: [String]?) {
if let extensions {
let filter = gtk_file_filter_new()
for name in extensions {
gtk_file_filter_add_suffix(filter, name)
}
gtk_file_dialog_set_default_filter(pointer, filter)
} else {
gtk_file_dialog_set_default_filter(pointer, nil)
}
}
// swiftlint:enable discouraged_optional_collection
/// Display the file dialog.
public func show() {
if let folder {
gtk_file_dialog_set_initial_folder(pointer, g_file_new_for_path(folder.absoluteString))
}
if isImporter {
gtui_filedialog_open(UInt64(Int(bitPattern: pointer)), selfAddr, UInt64(Int(bitPattern: parent)))
} else {
gtui_filedialog_save(UInt64(Int(bitPattern: pointer)), selfAddr, UInt64(Int(bitPattern: parent)))
}
}
/// Run this when a file gets opened.
/// - Parameter path: The file path.
func onOpen(_ path: String) {
let url = URL(fileURLWithPath: path)
onResult(url)
}
/// Run this when a file gets saved.
/// - Parameter path: The file path.
func onSave(_ path: String) {
let url = URL(fileURLWithPath: path)
onResult(url)
}
/// Run this when the user cancels the action.
func onClose() {
onCancel()
}
}
/// Run when a file should be opened.
/// - Parameters:
/// - ptr: The pointer.
/// - file: The path to the file.
/// - userData: The file dialog data.
@_cdecl("filedialog_on_open_cb")
func filedialog_on_open_cb(
ptr: UnsafeMutableRawPointer,
file: UnsafePointer<CChar>?,
userData: UnsafeMutableRawPointer
) {
let dialog = Unmanaged<GTUIFileDialog>.fromOpaque(userData).takeUnretainedValue()
if let file {
dialog.onOpen(.init(cString: file))
} else {
dialog.onClose()
}
}
/// Run when a file should be saved.
/// - Parameters:
/// - ptr: The pointer.
/// - file: The path to the file.
/// - userData: The file dialog data.
@_cdecl("filedialog_on_save_cb")
func filedialog_on_save_cb(
ptr: UnsafeMutableRawPointer,
file: UnsafePointer<CChar>?,
userData: UnsafeMutableRawPointer
) {
let dialog = Unmanaged<GTUIFileDialog>.fromOpaque(userData).takeUnretainedValue()
if let file {
dialog.onSave(.init(cString: file))
} else {
dialog.onClose()
}
}

View File

@ -5,19 +5,93 @@
// Created by david-swift on 12.10.23.
//
import Libadwaita
import CAdw
/// A GTUI window.
public typealias GTUIWindow = Libadwaita.Window
public class GTUIWindow: WindowType {
extension GTUIWindow: WindowType {
/// The window's pointer.
public var pointer: UnsafeMutablePointer<GtkWindow>?
/// Fields for additional information.
public var fields: [String: Any] = [:]
/// Initialize the window.
public init() {
pointer = adw_window_new()?.cast()
}
/// Initialize the window, but not the pointer.
/// - Parameter fields: The fields.
init(fields: [String: Any]) {
self.fields = fields
}
/// Set the default window size.
/// - Parameters:
/// - width: The width.
/// - height: The height.
public func setDefaultSize(width: Int?, height: Int?) {
gtk_window_set_default_size(pointer, width?.cInt ?? -1, height?.cInt ?? -1)
}
/// Set the resizability.
/// - Parameter resizable: Whether the window is resizable.
public func setResizability(_ resizable: Bool) {
gtk_window_set_resizable(pointer, resizable.cBool)
}
/// Set the deletability.
/// - Parameter deletable: Whether the window is deletable.
public func setDeletability(_ deletable: Bool) {
gtk_window_set_deletable(pointer, deletable.cBool)
}
/// Set the window title.
/// - Parameter title: The window's title.
public func setTitle(_ title: String) {
gtk_window_set_title(pointer, title)
}
/// Set the window's child.
/// - Parameter child: The child.
public func setChild(_ child: OpaquePointer?) {
gtk_window_set_child(pointer, child?.cast())
}
/// Present the window.
public func show() {
gtk_window_present(pointer)
}
/// Observe when the window is being closed.
/// - Parameter observer: The signal closure.
public func observeHide(observer: @escaping () -> Void) {
let hideObserver = ViewStorage.SignalData(closure: observer)
self.fields["observe-hide"] = hideObserver
g_signal_connect_data(
pointer?.cast(),
"destroy",
unsafeBitCast(hideObserver.handler, to: GCallback.self),
Unmanaged.passUnretained(hideObserver).toOpaque().cast(),
nil,
G_CONNECT_AFTER
)
}
/// Close the window.
public func close() {
gtk_window_close(pointer)
}
/// Set the window's parent window.
/// - Parameter parent: The parent window.
public func setParentWindow(_ parent: WindowType) {
// swiftlint:disable prefer_self_in_static_references
if let window = parent as? GTUIWindow {
self.setParent(window)
gtk_window_set_modal(pointer, 1)
gtk_window_set_transient_for(pointer, window.pointer)
}
// swiftlint:enable prefer_self_in_static_references
}
}

View File

@ -5,8 +5,6 @@
// Created by david-swift on 05.08.23.
//
import Libadwaita
/// A structure representing the content for a certain window type.
public protocol WindowScene: WindowSceneGroup {

View File

@ -5,8 +5,6 @@
// Created by david-swift on 31.08.23.
//
import Libadwaita
/// A storage for an app's window.
public class WindowStorage {

View File

@ -5,8 +5,6 @@
// Created by david-swift on 09.12.23.
//
import Libadwaita
/// A window type.
public protocol WindowType {

View File

@ -0,0 +1,33 @@
//
// Banner+.swift
// Adwaita
//
// Created by david-swift on 17.01.24.
//
import CAdw
extension Banner {
/// Initialize a text widget.
/// - Parameters:
/// - title: The content.
/// - visible: Whether the banner is visible.
public init(_ title: String, visible: Bool) {
self.init(title: title)
self = self.revealed(visible)
}
/// Configure the banner's button.
/// - Parameters:
/// - label: The button's title.
/// - handler: The button's handler.
/// - Returns: The banner.
public func button(_ label: String, handler: @escaping () -> Void) -> Self {
buttonLabel(label)
.buttonClicked {
handler()
}
}
}

View File

@ -1,76 +0,0 @@
//
// Banner.swift
// Adwaita
//
// Created by david-swift on 03.01.24.
//
import Libadwaita
/// A banner widget.
public struct Banner: Widget {
/// The content.
var title: String
/// Whether the banner is visible.
var visible: Bool
/// The button's label.
var buttonLabel: String?
/// The button's handler.
var handler: () -> Void = { }
/// Initialize a text widget.
/// - Parameters:
/// - title: The content.
/// - visible: Whether the banner is visible.
public init(_ title: String, visible: Bool) {
self.title = title
self.visible = visible
}
/// Update the view storage of the text widget.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let banner = storage.view as? Libadwaita.Banner {
update(banner: banner)
}
}
/// Get the container of the text widget.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let banner = Libadwaita.Banner(title)
update(banner: banner)
return .init(banner)
}
/// Update the banner.
/// - Parameter banner: The banner.
func update(banner: Libadwaita.Banner) {
_ = banner.title(title)
if let buttonLabel {
_ = banner.buttonLabel(buttonLabel)
_ = banner.buttonHandler(handler)
}
if visible {
banner.show()
} else {
banner.hide()
}
}
/// Configure the banner's button.
/// - Parameters:
/// - label: The button's title.
/// - handler: The button's handler.
/// - Returns: The banner.
public func button(_ label: String, handler: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.buttonLabel = label
newSelf.handler = handler
return newSelf
}
}

View File

@ -0,0 +1,64 @@
//
// Button+.swift
// Adwaita
//
// Created by david-swift on 15.01.24.
//
import CAdw
/// A button widget.
extension Button {
// swiftlint:disable function_default_parameter_at_end
/// Initialize a button.
/// - Parameters:
/// - label: The button's label.
/// - icon: The button's icon.
/// - handler: The button's action handler.
public init(_ label: String? = nil, icon: Icon, handler: @escaping () -> Void) {
self.init()
self = self.child {
ButtonContent()
.label(label)
.iconName(icon.string)
}
self = self.clicked(handler)
}
// swiftlint:enable function_default_parameter_at_end
/// Initialize a button.
/// - Parameters:
/// - label: The buttons label.
/// - handler: The button's action handler.
public init(_ label: String, handler: @escaping () -> Void) {
self.init()
self = self.label(label)
self = self.clicked(handler)
}
/// Create a keyboard shortcut for an application window from a button.
///
/// Note that the keyboard shortcut is available after the view has been visible for the first time.
/// - Parameters:
/// - shortcut: The keyboard shortcut.
/// - window: The application window.
/// - Returns: The button.
public func keyboardShortcut(_ shortcut: String, window: GTUIApplicationWindow) -> Self {
window.addKeyboardShortcut(shortcut, id: shortcut) { self.clicked?() }
return self
}
/// Create a keyboard shortcut for an application from a button.
///
/// Note that the keyboard shortcut is available after the view has been visible for the first time.
/// - Parameters:
/// - shortcut: The keyboard shortcut.
/// - window: The application.
/// - Returns: The button.
public func keyboardShortcut(_ shortcut: String, app: GTUIApp) -> Self {
app.addKeyboardShortcut(shortcut, id: shortcut) { self.clicked?() }
return self
}
}

View File

@ -1,98 +0,0 @@
//
// Button.swift
// Adwaita
//
// Created by david-swift on 10.09.23.
//
import Libadwaita
/// A button widget.
public struct Button: Widget {
/// The button's label.
var label: String?
/// The button's icon.
var icon: Icon?
/// The button's action handler.
var handler: () -> Void
// swiftlint:disable function_default_parameter_at_end
/// Initialize a button.
/// - Parameters:
/// - label: The button's label.
/// - icon: The button's icon.
/// - handler: The button's action handler.
public init(_ label: String? = nil, icon: Icon, handler: @escaping () -> Void) {
self.label = label
self.icon = icon
self.handler = handler
}
// swiftlint:enable function_default_parameter_at_end
/// Initialize a button.
/// - Parameters:
/// - label: The buttons label.
/// - handler: The button's action handler.
public init(_ label: String, handler: @escaping () -> Void) {
self.label = label
self.handler = handler
}
/// Update a button's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let button = storage.view as? Libadwaita.Button {
let content = button.getContent()
if let label {
if icon == nil {
button.setLabel(label)
} else {
content?.setLabel(label)
}
}
if let icon {
content?.setIcon(icon)
}
_ = button.handler(handler)
}
}
/// Get a button's view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The button's view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
if let icon {
return .init(Libadwaita.Button(label, icon: icon).handler(handler))
} else {
return .init(Libadwaita.Button(label ?? .init()).handler(handler))
}
}
/// Create a keyboard shortcut for an application window from a button.
///
/// Note that the keyboard shortcut is available after the view has been visible for the first time.
/// - Parameters:
/// - shortcut: The keyboard shortcut.
/// - window: The application window.
/// - Returns: The button.
public func keyboardShortcut(_ shortcut: String, window: GTUIApplicationWindow) -> Self {
window.addKeyboardShortcut(shortcut, id: shortcut, handler: handler)
return self
}
/// Create a keyboard shortcut for an application from a button.
///
/// Note that the keyboard shortcut is available after the view has been visible for the first time.
/// - Parameters:
/// - shortcut: The keyboard shortcut.
/// - window: The application.
/// - Returns: The button.
public func keyboardShortcut(_ shortcut: String, app: GTUIApp) -> Self {
app.addKeyboardShortcut(shortcut, id: shortcut, handler: handler)
return self
}
}

View File

@ -0,0 +1,17 @@
//
// Carousel+.swift
// Adwaita
//
// Created by david-swift on 18.01.24.
//
extension Carousel {
/// Set whether long swipes are allowed or not.
/// - Parameter longSwipes: Whether long swipes are allowed.
/// - Returns: The carousel.
public func longSwipes(_ longSwipes: Bool = true) -> Self {
allowLongSwipes(longSwipes)
}
}

View File

@ -1,49 +0,0 @@
//
// Carousel.swift
// Adwaita
//
// Created by david-swift on 01.01.24.
//
import Libadwaita
/// A carousel view.
public struct Carousel<Element>: View where Element: Identifiable {
/// The elements.
var elements: [Element]
/// The content.
var content: (Element) -> Body
/// Whether long swipes are allowed.
var allowLongSwipes = false
/// The view.
public var view: Body {
Container(elements, content: content) {
Libadwaita.Carousel()
}
.inspect { _ = ($0 as? Libadwaita.Carousel)?.longSwipes(allowLongSwipes) }
}
/// Initialize `Carousel`.
/// - Parameters:
/// - elements: The elements.
/// - content: The view for an element.
public init(
_ elements: [Element],
@ViewBuilder content: @escaping (Element) -> Body
) {
self.content = content
self.elements = elements
}
/// Set whether long swipes are allowed or not.
/// - Parameter longSwipes: Whether long swipes are allowed.
/// - Returns: The carousel.
public func longSwipes(_ longSwipes: Bool = true) -> Self {
var newSelf = self
newSelf.allowLongSwipes = longSwipes
return newSelf
}
}

View File

@ -1,101 +0,0 @@
//
// Container.swift
// Adwaita
//
// Created by david-swift on 01.01.24.
//
import LevenshteinTransformations
import Libadwaita
/// A container widget.
public struct Container<Type, Element>: Widget
where Element: Identifiable, Type: InsertableContainer, Type: NativeWidgetPeer {
/// The elements.
var elements: [Element]
/// The content.
var content: (Element) -> Body
/// Get the container for initialization.
var container: () -> Type
/// The identifier of the elements storage.
let elementsID = "elements"
/// Initialize `Container`.
/// - Parameters:
/// - elements: The elements.
/// - content: The view for an element.
/// - container: Get the initial Libadwaita container widget.
public init(
_ elements: [Element],
@ViewBuilder content: @escaping (Element) -> Body,
container: @escaping () -> Type
) {
self.content = content
self.elements = elements
self.container = container
}
/// Update a view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let container = storage.view as? Type {
var content: [ViewStorage] = storage.content[.mainContent] ?? []
updateContainer(container, content: .init { content } set: { content = $0 }, modifiers: modifiers)
storage.content[.mainContent] = content
for (index, element) in elements.enumerated() {
self.content(element).widget(modifiers: modifiers).update(content[index], modifiers: modifiers)
}
}
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let container = self.container()
var content: [ViewStorage] = []
updateContainer(container, content: .init { content } set: { content = $0 }, modifiers: modifiers)
return .init(container, content: [.mainContent: content])
}
/// Update the container's content.
/// - Parameters:
/// - container: The container.
/// - content: The content's view storage.
/// - modifiers: The view modifiers.
func updateContainer(_ container: Type, content: Binding<[ViewStorage]>, modifiers: [(View) -> View]) {
let old = container.fields[elementsID] as? [Element] ?? []
old.identifiableTransform(
to: elements,
functions: .init { index, element in
let widget = getWidget(element: element, modifiers: modifiers)
_ = container.removeWidgets([content.wrappedValue[index].view])
_ = container.insert(widget.view, at: index)
content.wrappedValue.remove(at: index)
content.wrappedValue.insert(widget, at: index)
} delete: { index in
_ = container.removeWidgets([content.wrappedValue[index].view])
content.wrappedValue.remove(at: index)
} insert: { index, element in
let widget = getWidget(element: element, modifiers: modifiers)
_ = container.insert(widget.view, at: index)
content.wrappedValue.insert(widget, at: index)
}
)
container.fields[elementsID] = elements
}
/// Get the view storage of an element.
/// - Parameters:
/// - element: The element.
/// - modifiers: The modifiers.
/// - Returns: The view storage.
func getWidget(element: Element, modifiers: [(View) -> View]) -> ViewStorage {
self.content(element).widget(modifiers: modifiers).container(modifiers: modifiers)
}
}

View File

@ -0,0 +1,17 @@
//
// ActionRow+.swift
// Adwaita
//
// Created by david-swift on 20.01.24.
//
/// A form content row showing a title and optionally a subtitle and widgets.
extension ActionRow {
/// Initialize an action row.
/// - Parameter title: The row's title.
public init(_ title: String) {
self = self.title(title)
}
}

View File

@ -1,99 +0,0 @@
//
// ActionRow.swift
// Adwaita
//
// Created by david-swift on 03.01.24.
//
import Libadwaita
/// A form content row showing a title and optionally a subtitle and widgets.
public struct ActionRow: Widget {
/// The title.
var title: String
/// The subtitle.
var subtitle = ""
/// The prefix.
var prefix: Body = []
/// The suffix.
var suffix: Body = []
/// The identifier for the prefix content.
let prefixID = "prefix"
/// The identifier for the suffix content.
let suffixID = "suffix"
/// Initialize an action row.
/// - Parameter title: The row's title.
public init(_ title: String) {
self.title = title
}
/// Update a view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let row = storage.view as? Libadwaita.ActionRow {
update(row: row)
}
if let prefixStorage = storage.content[prefixID]?.first {
prefix.widget(modifiers: modifiers).update(prefixStorage, modifiers: modifiers)
}
if let suffixStorage = storage.content[suffixID]?.first {
suffix.widget(modifiers: modifiers).update(suffixStorage, modifiers: modifiers)
}
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let row: Libadwaita.ActionRow = .init(title: title, subtitle: subtitle)
let prefixContent = prefix.widget(modifiers: modifiers).container(modifiers: modifiers)
let suffixContent = suffix.widget(modifiers: modifiers).container(modifiers: modifiers)
if !prefix.isEmpty {
_ = row.addPrefix(prefixContent.view)
}
if !suffix.isEmpty {
_ = row.addSuffix(suffixContent.view)
}
return .init(row, content: [prefixID: [prefixContent], suffixID: [suffixContent]])
}
/// Update the action row.
/// - Parameter row: The action row.
func update(row: Libadwaita.ActionRow) {
_ = row.title(title)
_ = row.subtitle(subtitle)
}
/// Set the action row's subtitle.
/// - Parameter subtitle: The subtitle.
/// - Returns: The action row.
public func subtitle(_ subtitle: String) -> Self {
var newSelf = self
newSelf.subtitle = subtitle
return newSelf
}
/// Set the action row's prefix view.
/// - Parameter prefix: The prefix.
/// - Returns: The action row.
public func prefix(@ViewBuilder _ prefix: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.prefix = prefix()
return newSelf
}
/// Set the action row's suffix view.
/// - Parameter suffix: The suffix.
/// - Returns: The action row.
public func suffix(@ViewBuilder _ suffix: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.suffix = suffix()
return newSelf
}
}

View File

@ -0,0 +1,61 @@
//
// ComboRow+.swift
// Adwaita
//
// Created by david-swift on 20.01.24.
//
import CAdw
import LevenshteinTransformations
/// A row for selecting an element out of a list of elements.
extension ComboRow {
static var values: String { "values" }
static var stringList: String { "string-list" }
/// Initialize a combo row.
/// - Parameters:
/// - title: The row's title.
/// - selection: The selected value.
/// - values: The available values.
public init<Element>(
_ title: String,
selection: Binding<Element.ID>,
values: [Element]
) where Element: Identifiable, Element: CustomStringConvertible {
self = self.title(title)
self = self.selected(.init {
.init(values.firstIndex { $0.id == selection.wrappedValue } ?? 0)
} set: { index in
if let id = values[safe: .init(index)]?.id {
selection.wrappedValue = id
}
})
appearFunctions.append { storage in
let list = gtk_string_list_new(nil)
storage.fields[Self.stringList] = list
adw_combo_row_set_model(storage.pointer?.cast(), list)
}
updateFunctions.append { storage in
if let list = storage.fields[Self.stringList] as? OpaquePointer {
let old = storage.fields[Self.values] as? [Element] ?? []
var new = values.filter { element in !old.contains { $0.id == element.id } }
new = old + new
old.identifiableTransform(
to: new,
functions: .init { index, element in
gtk_string_list_remove(list, .init(index))
gtk_string_list_append(list, element.description)
} delete: { index in
gtk_string_list_remove(list, .init(index))
} insert: { _, element in
gtk_string_list_append(list, element.description)
}
)
storage.fields[Self.values] = new
}
}
}
}

View File

@ -1,132 +0,0 @@
//
// ComboRow.swift
// Adwaita
//
// Created by david-swift on 04.01.24.
//
import Libadwaita
/// A row for selecting an element out of a list of elements.
public struct ComboRow<Element>: Widget
where Element: CustomStringConvertible, Element: Identifiable, Element: Equatable {
/// The title.
var title: String
/// The selected element.
@Binding var selection: Element.ID
/// The content.
var content: [Element]
/// The subtitle.
var subtitle = ""
/// The prefix.
var prefix: Body = []
/// The suffix.
var suffix: Body = []
/// The identifier for the prefix content.
let prefixID = "prefix"
/// The identifier for the suffix content.
let suffixID = "suffix"
/// The identifier for the elements.
let elementsID = "elements"
/// Initialize a combo row.
/// - Parameters:
/// - title: The row's title.
/// - selection: The selected value.
/// - values: The available values.
public init(_ title: String, selection: Binding<Element.ID>, values: [Element]) {
self.title = title
self._selection = selection
content = values
}
/// Update a view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let row = storage.view as? Libadwaita.ComboRow {
update(row: row)
}
if let prefixStorage = storage.content[prefixID]?.first {
prefix.widget(modifiers: modifiers).update(prefixStorage, modifiers: modifiers)
}
if let suffixStorage = storage.content[suffixID]?.first {
suffix.widget(modifiers: modifiers).update(suffixStorage, modifiers: modifiers)
}
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let row: Libadwaita.ComboRow = .init(title: title, subtitle: subtitle)
let prefixContent = prefix.widget(modifiers: modifiers).container(modifiers: modifiers)
let suffixContent = suffix.widget(modifiers: modifiers).container(modifiers: modifiers)
if !prefix.isEmpty {
_ = row.addPrefix(prefixContent.view)
}
if !suffix.isEmpty {
_ = row.addSuffix(suffixContent.view)
}
update(row: row)
_ = row.onChange {
if let element = content.first(where: { $0.description == row.selected() }), element.id != selection {
selection = element.id
}
}
return .init(row, content: [prefixID: [prefixContent], suffixID: [suffixContent]])
}
/// Update the combo row.
/// - Parameter row: The combo row.
func update(row: Libadwaita.ComboRow) {
_ = row.title(title)
_ = row.subtitle(subtitle)
let oldElements = row.fields[elementsID] as? [Element] ?? []
if oldElements != content {
for element in oldElements {
row.remove(at: 0)
}
for element in content {
row.append(element.description)
}
}
let index = content.firstIndex { $0.id == selection } ?? 0
if row.selected() != content[safe: index]?.description {
row.select(at: index)
}
row.fields[elementsID] = content
}
/// Set the combo row's subtitle.
/// - Parameter subtitle: The subtitle.
/// - Returns: The combo row.
public func subtitle(_ subtitle: String) -> Self {
var newSelf = self
newSelf.subtitle = subtitle
return newSelf
}
/// Set the combo row's prefix view.
/// - Parameter prefix: The prefix.
/// - Returns: The combo row.
public func prefix(@ViewBuilder _ prefix: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.prefix = prefix()
return newSelf
}
/// Set the combo row's suffix view.
/// - Parameter suffix: The suffix.
/// - Returns: The combo row.
public func suffix(@ViewBuilder _ suffix: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.suffix = suffix()
return newSelf
}
}

View File

@ -0,0 +1,59 @@
//
// EntryRow+.swift
// Adwaita
//
// Created by david-swift on 20.01.24.
//
import CAdw
extension EntryRow {
static var textField: String { "text" }
/// Initialize an entry row.
/// - Parameters:
/// - title: The row's title.
/// - text: The text.
public init(_ title: String, text: Binding<String>) {
self.init()
self = self.title(title)
appearFunctions.append { storage in
storage.fields[Self.textField] = text
storage.notify(name: "text") {
if let binding = storage.fields[Self.textField] as? Binding<String> {
binding.wrappedValue = .init(cString: gtk_editable_get_text(storage.pointer))
}
}
}
updateFunctions.append { storage in
if text.wrappedValue != .init(cString: gtk_editable_get_text(storage.pointer)) {
gtk_editable_set_text(storage.pointer, text.wrappedValue)
}
}
}
/// Set the entry row's subtitle.
/// - Parameter subtitle: The subtitle.
/// - Returns: The entry row.
public func onSubmit(_ onSubmit: @escaping () -> Void) -> Self {
showApplyButton()
.apply(onSubmit)
}
/// Let the user securely enter private text.
/// - Parameter: The text.
/// - Returns: The entry row.
public func secure(text: Binding<String>? = nil) -> PasswordEntryRow {
.init(title ?? "", text: text ?? .constant(""))
.activatesDefault(activatesDefault)
.enableEmojiCompletion(enableEmojiCompletion)
.showApplyButton(showApplyButton)
.titleSelectable(titleSelectable)
.useMarkup(useMarkup)
.useUnderline(useUnderline)
.apply(apply ?? { })
.entryActivated(entryActivated ?? { })
}
}

View File

@ -1,136 +0,0 @@
//
// EntryRow.swift
// Adwaita
//
// Created by david-swift on 04.01.24.
//
import Libadwaita
/// A form content row accepting text input.
public struct EntryRow: Widget {
/// The title.
var title: String
/// The text.
@Binding var text: String
/// The prefix.
var prefix: Body = []
/// The suffix.
var suffix: Body = []
/// The handler that gets executed when the user submits the content.
var onSubmit: (() -> Void)?
/// Whether the password entry row should be used.
var password = false
/// The identifier for the prefix content.
let prefixID = "prefix"
/// The identifier for the suffix content.
let suffixID = "suffix"
/// The identifier for the title.
let titleID = "title"
/// Initialize an entry row.
/// - Parameters:
/// - title: The row's title.
/// - text: The text.
public init(_ title: String, text: Binding<String>) {
self.title = title
self._text = text
}
/// Update a view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let row = storage.view as? Libadwaita.EntryRow {
update(row: row)
}
if let prefixStorage = storage.content[prefixID]?.first {
prefix.widget(modifiers: modifiers).update(prefixStorage, modifiers: modifiers)
}
if let suffixStorage = storage.content[suffixID]?.first {
suffix.widget(modifiers: modifiers).update(suffixStorage, modifiers: modifiers)
}
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let row: Libadwaita.EntryRow
if password {
row = PasswordEntryRow(title: title)
} else {
row = .init(title: title)
}
let prefixContent = prefix.widget(modifiers: modifiers).container(modifiers: modifiers)
let suffixContent = suffix.widget(modifiers: modifiers).container(modifiers: modifiers)
if !prefix.isEmpty {
_ = row.addPrefix(prefixContent.view)
}
if !suffix.isEmpty {
_ = row.addSuffix(suffixContent.view)
}
_ = row.changeHandler {
if row.contents() != text {
text = row.contents()
}
}
update(row: row)
return .init(row, content: [prefixID: [prefixContent], suffixID: [suffixContent]])
}
/// Update the entry row.
/// - Parameter row: The entry row.
func update(row: Libadwaita.EntryRow) {
if row.fields[titleID] as? String != title {
_ = row.title(title)
row.fields[titleID] = title
}
if row.contents() != text {
row.setContents(text)
}
if let onSubmit {
_ = row.submitHandler(onSubmit)
}
}
/// Set the entry row's subtitle.
/// - Parameter subtitle: The subtitle.
/// - Returns: The entry row.
public func onSubmit(_ onSubmit: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.onSubmit = onSubmit
return newSelf
}
/// Set the entry row's prefix view.
/// - Parameter prefix: The prefix.
/// - Returns: The entry row.
public func prefix(@ViewBuilder _ prefix: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.prefix = prefix()
return newSelf
}
/// Set the entry row's suffix view.
/// - Parameter suffix: The suffix.
/// - Returns: The entry row.
public func suffix(@ViewBuilder _ suffix: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.suffix = suffix()
return newSelf
}
/// Let the user securely enter private text.
/// - Returns: The entry row.
public func secure() -> Self {
var newSelf = self
newSelf.password = true
return newSelf
}
}

View File

@ -5,43 +5,24 @@
// Created by david-swift on 03.01.24.
//
import Libadwaita
import CAdw
/// A list with no dynamic content styled as a boxed list.
public struct Form: Widget {
public struct Form: View {
/// The content.
var content: () -> Body
var content: Body
/// The view's body.
public var view: Body {
List([Int](content.indices), selection: nil) { index in content[index] }
.style("boxed-list")
}
/// Initialize a `Form`.
/// - Parameter content: The view content, usually different kind of rows.
public init(@ViewBuilder content: @escaping () -> Body) {
self.content = content
}
/// Update a view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
content().update(storage.content[.mainContent] ?? [], modifiers: modifiers)
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let form: ListBox = .init()
_ = form
.noSelection()
.addStyle("boxed-list")
var content: [ViewStorage] = []
for element in self.content() {
let widget = element.storage(modifiers: modifiers)
_ = form.append(widget.view)
content.append(widget)
}
return .init(form, content: [.mainContent: content])
self.content = content()
}
}

View File

@ -0,0 +1,30 @@
//
// FormSection+.swift
// Adwaita
//
// Created by david-swift on 20.01.24.
//
/// A section usually groups forms.
public typealias FormSection = PreferencesGroup
extension FormSection {
/// Initialize a form section.
/// - Parameters:
/// - title: The title.
/// - content: The content, usually one or more forms.
public init(_ title: String, @ViewBuilder content: @escaping () -> Body) {
self.init()
self = self.title(title)
self = self.child(content)
}
/// Set the form section's suffix view.
/// - Parameter suffix: The suffix.
/// - Returns: The form section.
public func suffix(@ViewBuilder _ suffix: @escaping () -> Body) -> Self {
headerSuffix(suffix)
}
}

View File

@ -1,89 +0,0 @@
//
// FormSection.swift
// Adwaita
//
// Created by david-swift on 03.01.24.
//
import Libadwaita
/// A section usually groups forms.
public struct FormSection: Widget {
/// The title.
var title: String
/// The content.
var content: Body
/// The description.
var description = ""
/// The suffix.
var suffix: Body = []
/// The identifier for the suffix content.
let suffixID = "suffix"
/// Initialize a form section.
/// - Parameters:
/// - title: The title.
/// - content: The content, usually one or more forms.
public init(_ title: String, @ViewBuilder content: () -> Body) {
self.title = title
self.content = content()
}
/// Update a view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let group = storage.view as? Libadwaita.PreferencesGroup {
update(group: group)
}
if let storage = storage.content[.mainContent]?.first {
content.widget(modifiers: modifiers).update(storage, modifiers: modifiers)
}
if let suffixStorage = storage.content[suffixID]?.first {
suffix.widget(modifiers: modifiers).update(suffixStorage, modifiers: modifiers)
}
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let group: Libadwaita.PreferencesGroup = .init(name: title, description: description)
let content = content.widget(modifiers: modifiers).container(modifiers: modifiers)
let suffixContent = suffix.widget(modifiers: modifiers).container(modifiers: modifiers)
group.add(content.view)
if !suffix.isEmpty {
_ = group.headerSuffix(suffixContent.view)
}
return .init(group, content: [.mainContent: [content], suffixID: [suffixContent]])
}
/// Update the form section.
/// - Parameter group: The form section.
func update(group: Libadwaita.PreferencesGroup) {
_ = group.title(title)
_ = group.description(description)
}
/// Set the form section's description.
/// - Parameter description: The description.
/// - Returns: The form section.
public func description(_ description: String) -> Self {
var newSelf = self
newSelf.description = description
return newSelf
}
/// Set the form section's suffix view.
/// - Parameter suffix: The suffix.
/// - Returns: The form section.
public func suffix(@ViewBuilder _ suffix: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.suffix = suffix()
return newSelf
}
}

View File

@ -0,0 +1,43 @@
//
// PasswordEntryRow+.swift
// Adwaita
//
// Created by david-swift on 20.01.24.
//
import CAdw
extension PasswordEntryRow {
static var textField: String { "text" }
/// Initialize an entry row.
/// - Parameters:
/// - title: The row's title.
/// - text: The text.
public init(_ title: String, text: Binding<String>) {
self.init()
self = self.title(title)
appearFunctions.append { storage in
storage.fields[Self.textField] = text
storage.notify(name: "text") {
if let binding = storage.fields[Self.textField] as? Binding<String> {
binding.wrappedValue = .init(cString: gtk_editable_get_text(storage.pointer))
}
}
}
updateFunctions.append { storage in
if text.wrappedValue != .init(cString: gtk_editable_get_text(storage.pointer)) {
gtk_editable_set_text(storage.pointer, text.wrappedValue)
}
}
}
/// Set the entry row's subtitle.
/// - Parameter subtitle: The subtitle.
/// - Returns: The entry row.
public func onSubmit(_ onSubmit: @escaping () -> Void) -> Self {
apply(onSubmit)
}
}

View File

@ -0,0 +1,62 @@
//
// SpinRow+.swift
// Adwaita
//
// Created by david-swift on 20.01.24.
//
import CAdw
extension SpinRow {
/// Initialize a spin row.
/// - Parameters:
/// - title: The row's title.
/// - value: The selected value.
/// - min: The minimum value.
/// - max: The maximum value.
public init(_ title: String, value: Binding<Int>, min: Int, max: Int) {
self.init(
title,
value: .init { .init(value.wrappedValue) } set: { value.wrappedValue = .init($0) },
min: .init(min),
max: .init(max)
)
}
/// Initialize a spin row.
/// - Parameters:
/// - title: The row's title.
/// - value: The selected value.
/// - min: The minimum value.
/// - max: The maximum value.
public init(_ title: String, value: Binding<Double>, min: Double, max: Double) {
self.init(climbRate: 1, digits: 0)
self = self.title(title)
self = self.value(value)
self = self.step(1)
updateFunctions.append { storage in
adw_spin_row_set_range(storage.pointer, min, max)
}
}
/// Set the difference a single click on the increase/decrease buttons makes.
/// - Parameter step: The increase/decrease step.
/// - Returns: The spin row.
public func step(_ step: Int) -> Self {
self.step(.init(step))
}
/// Set the difference a single click on the increase/decrease buttons makes.
/// - Parameter step: The increase/decrease step.
/// - Returns: The spin row.
public func step(_ step: Double) -> Self {
var newSelf = self
newSelf.updateFunctions.append { storage in
let adjustment = adw_spin_row_get_adjustment(storage.pointer)
gtk_adjustment_set_step_increment(adjustment, step)
}
return newSelf
}
}

View File

@ -1,149 +0,0 @@
//
// SpinRow.swift
// Adwaita
//
// Created by david-swift on 04.01.24.
//
import Libadwaita
/// A spin row lets the user select an integer in a certain range.
public struct SpinRow: Widget {
/// The title.
var title: String
/// The selected value.
@Binding var value: Int
/// The minimum value.
var min: Int
/// The maximum value.
var max: Int
/// The increase/decrease step.
var step = 1
/// The subtitle.
var subtitle = ""
/// The prefix.
var prefix: Body = []
/// The suffix.
var suffix: Body = []
/// The identifier for the prefix content.
let prefixID = "prefix"
/// The identifier for the suffix content.
let suffixID = "suffix"
/// The identifier of the configuration field.
let configID = "config"
/// Initialize a spin row.
/// - Parameters:
/// - title: The row's title.
/// - value: The selected value.
/// - min: The minimum value.
/// - max: The maximum value.
public init(_ title: String, value: Binding<Int>, min: Int, max: Int) {
self.title = title
self._value = value
self.min = min
self.max = max
}
/// Update a view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let row = storage.view as? Libadwaita.SpinRow {
update(row: row)
}
if let prefixStorage = storage.content[prefixID]?.first {
prefix.widget(modifiers: modifiers).update(prefixStorage, modifiers: modifiers)
}
if let suffixStorage = storage.content[suffixID]?.first {
suffix.widget(modifiers: modifiers).update(suffixStorage, modifiers: modifiers)
}
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let row: Libadwaita.SpinRow = .init(
title: title,
subtitle: subtitle,
min: .init(min),
max: .init(max),
step: .init(step)
)
row.fields[configID] = (min, max, step)
let prefixContent = prefix.widget(modifiers: modifiers).container(modifiers: modifiers)
let suffixContent = suffix.widget(modifiers: modifiers).container(modifiers: modifiers)
if !prefix.isEmpty {
_ = row.addPrefix(prefixContent.view)
}
if !suffix.isEmpty {
_ = row.addSuffix(suffixContent.view)
}
_ = row.onChange {
let value = Int(row.getValue().rounded())
if self.value != value {
self.value = value
}
}
update(row: row)
return .init(row, content: [prefixID: [prefixContent], suffixID: [suffixContent]])
}
// swiftlint:disable large_tuple
/// Update the spin row.
/// - Parameter row: The spin row.
func update(row: Libadwaita.SpinRow) {
_ = row.title(title)
_ = row.subtitle(subtitle)
if row.fields[configID] as? (Int, Int, Int) ?? (0, 0, 0) != (min, max, step) {
_ = row.configuration(min: .init(min), max: .init(max), step: .init(step))
row.fields[configID] = (min, max, step)
}
if row.getValue() != .init(value) {
row.setValue(.init(value))
}
}
// swiftlint:enable large_tuple
/// Set the spin row's subtitle.
/// - Parameter subtitle: The subtitle.
/// - Returns: The spin row.
public func subtitle(_ subtitle: String) -> Self {
var newSelf = self
newSelf.subtitle = subtitle
return newSelf
}
/// Set the spin row's prefix view.
/// - Parameter prefix: The prefix.
/// - Returns: The spin row.
public func prefix(@ViewBuilder _ prefix: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.prefix = prefix()
return newSelf
}
/// Set the spin row's suffix view.
/// - Parameter suffix: The suffix.
/// - Returns: The spin row.
public func suffix(@ViewBuilder _ suffix: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.suffix = suffix()
return newSelf
}
/// Set the difference a single click on the increase/decrease buttons makes.
/// - Parameter step: The increase/decrease step.
/// - Returns: The spin row.
public func step(_ step: Int) -> Self {
var newSelf = self
newSelf.step = step
return newSelf
}
}

View File

@ -0,0 +1,21 @@
//
// SwitchRow+.swift
// Adwaita
//
// Created by david-swift on 20.01.24.
//
/// A row representing a boolean state.
extension SwitchRow {
/// Initialize a switch row.
/// - Parameters:
/// - title: The row's title.
/// - isOn: Whether the switch is on.
public init(_ title: String, isOn: Binding<Bool>) {
self.init()
self = self.title(title)
self = self.active(isOn)
}
}

View File

@ -1,113 +0,0 @@
//
// SwitchRow.swift
// Adwaita
//
// Created by david-swift on 04.01.24.
//
import Libadwaita
/// A row representing a boolean state.
public struct SwitchRow: Widget {
/// The title.
var title: String
/// Whether the switch is activated.
@Binding var isOn: Bool
/// The subtitle.
var subtitle = ""
/// The prefix.
var prefix: Body = []
/// The suffix.
var suffix: Body = []
/// The identifier for the prefix content.
let prefixID = "prefix"
/// The identifier for the suffix content.
let suffixID = "suffix"
/// Initialize a switch row.
/// - Parameters:
/// - title: The row's title.
/// - isOn: Whether the switch is on.
public init(_ title: String, isOn: Binding<Bool>) {
self.title = title
self._isOn = isOn
}
/// Update a view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let row = storage.view as? Libadwaita.SwitchRow {
update(row: row)
}
if let prefixStorage = storage.content[prefixID]?.first {
prefix.widget(modifiers: modifiers).update(prefixStorage, modifiers: modifiers)
}
if let suffixStorage = storage.content[suffixID]?.first {
suffix.widget(modifiers: modifiers).update(suffixStorage, modifiers: modifiers)
}
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let row: Libadwaita.SwitchRow = .init(title: title, subtitle: subtitle)
let prefixContent = prefix.widget(modifiers: modifiers).container(modifiers: modifiers)
let suffixContent = suffix.widget(modifiers: modifiers).container(modifiers: modifiers)
if !prefix.isEmpty {
_ = row.addPrefix(prefixContent.view)
}
if !suffix.isEmpty {
_ = row.addSuffix(suffixContent.view)
}
_ = row.onChange {
if row.getActive() != isOn {
isOn = row.getActive()
}
}
update(row: row)
return .init(row, content: [prefixID: [prefixContent], suffixID: [suffixContent]])
}
/// Update the switch row.
/// - Parameter row: The switch row.
func update(row: Libadwaita.SwitchRow) {
_ = row.title(title)
_ = row.subtitle(subtitle)
if row.getActive() != isOn {
row.setActive(isOn)
}
}
/// Set the switch row's subtitle.
/// - Parameter subtitle: The subtitle.
/// - Returns: The switch row.
public func subtitle(_ subtitle: String) -> Self {
var newSelf = self
newSelf.subtitle = subtitle
return newSelf
}
/// Set the switch row's prefix view.
/// - Parameter prefix: The prefix.
/// - Returns: The switch row.
public func prefix(@ViewBuilder _ prefix: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.prefix = prefix()
return newSelf
}
/// Set the switch row's suffix view.
/// - Parameter suffix: The suffix.
/// - Returns: The switch row.
public func suffix(@ViewBuilder _ suffix: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.suffix = suffix()
return newSelf
}
}

View File

@ -0,0 +1,334 @@
//
// ActionRow.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A [class@Gtk.ListBoxRow] used to present actions.
///
/// <picture><source srcset="action-row-dark.png" media="(prefers-color-scheme: dark)"><img src="action-row.png" alt="action-row"></picture>
///
/// The `AdwActionRow` widget can have a title, a subtitle and an icon. The row
/// can receive additional widgets at its end, or prefix widgets at its start.
///
/// It is convenient to present a preference and its related actions.
///
/// `AdwActionRow` is unactivatable by default, giving it an activatable widget
/// will automatically make it activatable, but unsetting it won't change the
/// row's activatability.
///
/// ## AdwActionRow as GtkBuildable
///
/// The `AdwActionRow` implementation of the [iface@Gtk.Buildable] interface
/// supports adding a child at its end by specifying suffix or omitting the
/// type attribute of a <child> element.
///
/// It also supports adding a child as a prefix widget by specifying prefix as
/// the type attribute of a <child> element.
///
/// ## CSS nodes
///
/// `AdwActionRow` has a main CSS node with name `row`.
///
/// It contains the subnode `box.header` for its main horizontal box, and
/// `box.title` for the vertical box containing the title and subtitle labels.
///
/// It contains subnodes `label.title` and `label.subtitle` representing
/// respectively the title label and subtitle label.
public struct ActionRow: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The widget to activate when the row is activated.
///
/// The row can be activated either by clicking on it, calling
/// [method@ActionRow.activate], or via mnemonics in the title.
/// See the [property@PreferencesRow:use-underline] property to enable
/// mnemonics.
///
/// The target widget will be activated by emitting the
/// [signal@Gtk.Widget::mnemonic-activate] signal on it.
var activatableWidget: (() -> Body)?
/// The icon name for this row.
var iconName: String?
/// The subtitle for this row.
///
/// The subtitle is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var subtitle: String?
/// The number of lines at the end of which the subtitle label will be
/// ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
var subtitleLines: Int?
/// Whether the user can copy the subtitle from the label.
///
/// See also [property@Gtk.Label:selectable].
var subtitleSelectable: Bool?
/// The number of lines at the end of which the title label will be ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
var titleLines: Int?
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var title: String?
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
var titleSelectable: Bool?
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
var useMarkup: Bool?
/// Whether an embedded underline in the title indicates a mnemonic.
var useUnderline: Bool?
/// This signal is emitted after the row has been activated.
var activated: (() -> Void)?
/// The body for the widget "suffix".
var suffix: () -> Body = { [] }
/// The body for the widget "prefix".
var prefix: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `ActionRow`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_action_row_new()?.opaque())
update(storage, modifiers: modifiers)
if let activatableWidgetStorage = activatableWidget?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["activatableWidget"] = [activatableWidgetStorage]
adw_action_row_set_activatable_widget(storage.pointer?.cast(), activatableWidgetStorage.pointer?.cast())
}
var suffixStorage: [ViewStorage] = []
for view in suffix() {
suffixStorage.append(view.storage(modifiers: modifiers))
adw_action_row_add_suffix(storage.pointer?.cast(), suffixStorage.last?.pointer?.cast())
}
storage.content["suffix"] = suffixStorage
var prefixStorage: [ViewStorage] = []
for view in prefix() {
prefixStorage.append(view.storage(modifiers: modifiers))
adw_action_row_add_prefix(storage.pointer?.cast(), prefixStorage.last?.pointer?.cast())
}
storage.content["prefix"] = prefixStorage
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let activated {
storage.connectSignal(name: "activated") {
activated()
}
}
storage.modify { widget in
if let widget = storage.content["activatableWidget"]?.first {
activatableWidget?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let iconName {
adw_action_row_set_icon_name(widget?.cast(), iconName)
}
if let subtitle {
adw_action_row_set_subtitle(widget?.cast(), subtitle)
}
if let subtitleLines {
adw_action_row_set_subtitle_lines(widget?.cast(), subtitleLines.cInt)
}
if let subtitleSelectable {
adw_action_row_set_subtitle_selectable(widget?.cast(), subtitleSelectable.cBool)
}
if let titleLines {
adw_action_row_set_title_lines(widget?.cast(), titleLines.cInt)
}
if let title {
adw_preferences_row_set_title(widget?.cast(), title)
}
if let titleSelectable {
adw_preferences_row_set_title_selectable(widget?.cast(), titleSelectable.cBool)
}
if let useMarkup {
adw_preferences_row_set_use_markup(widget?.cast(), useMarkup.cBool)
}
if let useUnderline {
adw_preferences_row_set_use_underline(widget?.cast(), useUnderline.cBool)
}
if let suffixStorage = storage.content["suffix"] {
for (index, view) in suffix().enumerated() {
if let storage = suffixStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
if let prefixStorage = storage.content["prefix"] {
for (index, view) in prefix().enumerated() {
if let storage = prefixStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
}
for function in updateFunctions {
function(storage)
}
}
/// The widget to activate when the row is activated.
///
/// The row can be activated either by clicking on it, calling
/// [method@ActionRow.activate], or via mnemonics in the title.
/// See the [property@PreferencesRow:use-underline] property to enable
/// mnemonics.
///
/// The target widget will be activated by emitting the
/// [signal@Gtk.Widget::mnemonic-activate] signal on it.
public func activatableWidget(@ViewBuilder _ activatableWidget: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.activatableWidget = activatableWidget
return newSelf
}
/// The icon name for this row.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// The subtitle for this row.
///
/// The subtitle is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func subtitle(_ subtitle: String?) -> Self {
var newSelf = self
newSelf.subtitle = subtitle
return newSelf
}
/// The number of lines at the end of which the subtitle label will be
/// ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
public func subtitleLines(_ subtitleLines: Int?) -> Self {
var newSelf = self
newSelf.subtitleLines = subtitleLines
return newSelf
}
/// Whether the user can copy the subtitle from the label.
///
/// See also [property@Gtk.Label:selectable].
public func subtitleSelectable(_ subtitleSelectable: Bool? = true) -> Self {
var newSelf = self
newSelf.subtitleSelectable = subtitleSelectable
return newSelf
}
/// The number of lines at the end of which the title label will be ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
public func titleLines(_ titleLines: Int?) -> Self {
var newSelf = self
newSelf.titleLines = titleLines
return newSelf
}
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func title(_ title: String?) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
public func titleSelectable(_ titleSelectable: Bool? = true) -> Self {
var newSelf = self
newSelf.titleSelectable = titleSelectable
return newSelf
}
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
public func useMarkup(_ useMarkup: Bool? = true) -> Self {
var newSelf = self
newSelf.useMarkup = useMarkup
return newSelf
}
/// Whether an embedded underline in the title indicates a mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// This signal is emitted after the row has been activated.
public func activated(_ activated: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.activated = activated
return newSelf
}
/// Set the body for "suffix".
/// - Parameter body: The body.
/// - Returns: The widget.
public func suffix(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.suffix = body
return newSelf
}
/// Set the body for "prefix".
/// - Parameter body: The body.
/// - Returns: The widget.
public func prefix(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.prefix = body
return newSelf
}
}

View File

@ -0,0 +1,139 @@
//
// Avatar.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A widget displaying an image, with a generated fallback.
///
/// <picture><source srcset="avatar-dark.png" media="(prefers-color-scheme: dark)"><img src="avatar.png" alt="avatar"></picture>
///
/// `AdwAvatar` is a widget that shows a round avatar.
///
/// `AdwAvatar` generates an avatar with the initials of the
/// [property@Avatar:text] on top of a colored background.
///
/// The color is picked based on the hash of the [property@Avatar:text].
///
/// If [property@Avatar:show-initials] is set to `FALSE`,
/// [property@Avatar:icon-name] or `avatar-default-symbolic` is shown instead of
/// the initials.
///
/// Use [property@Avatar:custom-image] to set a custom image.
///
/// ## CSS nodes
///
/// `AdwAvatar` has a single CSS node with name `avatar`.
public struct Avatar: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The name of an icon to use as a fallback.
///
/// If no name is set, `avatar-default-symbolic` will be used.
var iconName: String?
/// Whether initials are used instead of an icon on the fallback avatar.
///
/// See [property@Avatar:icon-name] for how to change the fallback icon.
var showInitials: Bool
/// The size of the avatar.
var size: Int
/// Sets the text used to generate the fallback initials and color.
///
/// It's only used to generate the color if [property@Avatar:show-initials] is
/// `FALSE`.
var text: String?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `Avatar`.
public init(showInitials: Bool, size: Int) {
self.showInitials = showInitials
self.size = size
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_avatar_new(size.cInt, text, showInitials.cBool)?.opaque())
update(storage, modifiers: modifiers)
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let iconName {
adw_avatar_set_icon_name(widget, iconName)
}
adw_avatar_set_show_initials(widget, showInitials.cBool)
adw_avatar_set_size(widget, size.cInt)
if let text {
adw_avatar_set_text(widget, text)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The name of an icon to use as a fallback.
///
/// If no name is set, `avatar-default-symbolic` will be used.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// Whether initials are used instead of an icon on the fallback avatar.
///
/// See [property@Avatar:icon-name] for how to change the fallback icon.
public func showInitials(_ showInitials: Bool) -> Self {
var newSelf = self
newSelf.showInitials = showInitials
return newSelf
}
/// The size of the avatar.
public func size(_ size: Int) -> Self {
var newSelf = self
newSelf.size = size
return newSelf
}
/// Sets the text used to generate the fallback initials and color.
///
/// It's only used to generate the color if [property@Avatar:show-initials] is
/// `FALSE`.
public func text(_ text: String?) -> Self {
var newSelf = self
newSelf.text = text
return newSelf
}
}

View File

@ -0,0 +1,161 @@
//
// Banner.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A bar with contextual information.
///
/// <picture><source srcset="banner-dark.png" media="(prefers-color-scheme: dark)"><img src="banner.png" alt="banner"></picture>
///
/// Banners are hidden by default, use [property@Banner:revealed] to show them.
///
/// Banners have a title, set with [property@Banner:title]. Titles can be marked
/// up with Pango markup, use [property@Banner:use-markup] to enable it.
///
/// The title will be shown centered or left-aligned depending on available
/// space.
///
/// Banners can optionally have a button with text on it, set through
/// [property@Banner:button-label]. The button can be used with a `GAction`,
/// or with the [signal@Banner::button-clicked] signal.
///
/// ## CSS nodes
///
/// `AdwBanner` has a main CSS node with the name `banner`.
public struct Banner: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The label to show on the button.
///
/// If set to `""` or `NULL`, the button won't be shown.
///
/// The button can be used with a `GAction`, or with the
/// [signal@Banner::button-clicked] signal.
var buttonLabel: String?
/// Whether the banner is currently revealed.
var revealed: Bool?
/// The title for this banner.
///
/// See also: [property@Banner:use-markup].
var title: String
/// Whether to use Pango markup for the banner title.
///
/// See also [func@Pango.parse_markup].
var useMarkup: Bool?
/// This signal is emitted after the action button has been clicked.
///
/// It can be used as an alternative to setting an action.
var buttonClicked: (() -> Void)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `Banner`.
public init(title: String) {
self.title = title
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_banner_new(title)?.opaque())
update(storage, modifiers: modifiers)
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let buttonClicked {
storage.connectSignal(name: "button-clicked") {
buttonClicked()
}
}
storage.modify { widget in
if let buttonLabel {
adw_banner_set_button_label(widget, buttonLabel)
}
if let revealed {
adw_banner_set_revealed(widget, revealed.cBool)
}
adw_banner_set_title(widget, title)
if let useMarkup {
adw_banner_set_use_markup(widget, useMarkup.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The label to show on the button.
///
/// If set to `""` or `NULL`, the button won't be shown.
///
/// The button can be used with a `GAction`, or with the
/// [signal@Banner::button-clicked] signal.
public func buttonLabel(_ buttonLabel: String?) -> Self {
var newSelf = self
newSelf.buttonLabel = buttonLabel
return newSelf
}
/// Whether the banner is currently revealed.
public func revealed(_ revealed: Bool? = true) -> Self {
var newSelf = self
newSelf.revealed = revealed
return newSelf
}
/// The title for this banner.
///
/// See also: [property@Banner:use-markup].
public func title(_ title: String) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
/// Whether to use Pango markup for the banner title.
///
/// See also [func@Pango.parse_markup].
public func useMarkup(_ useMarkup: Bool? = true) -> Self {
var newSelf = self
newSelf.useMarkup = useMarkup
return newSelf
}
/// This signal is emitted after the action button has been clicked.
///
/// It can be used as an alternative to setting an action.
public func buttonClicked(_ buttonClicked: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.buttonClicked = buttonClicked
return newSelf
}
}

View File

@ -0,0 +1,81 @@
//
// Bin.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A widget with one child.
///
/// <picture><source srcset="bin-dark.png" media="(prefers-color-scheme: dark)"><img src="bin.png" alt="bin"></picture>
///
/// The `AdwBin` widget has only one child, set with the [property@Bin:child]
/// property.
///
/// It is useful for deriving subclasses, since it provides common code needed
/// for handling a single child widget.
public struct Bin: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The child widget of the `AdwBin`.
var child: (() -> Body)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `Bin`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_bin_new()?.opaque())
update(storage, modifiers: modifiers)
if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["child"] = [childStorage]
adw_bin_set_child(storage.pointer?.cast(), childStorage.pointer?.cast())
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let widget = storage.content["child"]?.first {
child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The child widget of the `AdwBin`.
public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.child = child
return newSelf
}
}

View File

@ -0,0 +1,173 @@
//
// Box.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// The `GtkBox` widget arranges child widgets into a single row or column.
///
/// ![An example GtkBox](box.png)
///
/// Whether it is a row or column depends on the value of its
/// [property@Gtk.Orientable:orientation] property. Within the other
/// dimension, all children are allocated the same size. Of course, the
/// [property@Gtk.Widget:halign] and [property@Gtk.Widget:valign] properties
/// can be used on the children to influence their allocation.
///
/// Use repeated calls to [method@Gtk.Box.append] to pack widgets into a
/// `GtkBox` from start to end. Use [method@Gtk.Box.remove] to remove widgets
/// from the `GtkBox`. [method@Gtk.Box.insert_child_after] can be used to add
/// a child at a particular position.
///
/// Use [method@Gtk.Box.set_homogeneous] to specify whether or not all children
/// of the `GtkBox` are forced to get the same amount of space.
///
/// Use [method@Gtk.Box.set_spacing] to determine how much space will be minimally
/// placed between all children in the `GtkBox`. Note that spacing is added
/// *between* the children.
///
/// Use [method@Gtk.Box.reorder_child_after] to move a child to a different
/// place in the box.
///
/// # CSS nodes
///
/// `GtkBox` uses a single CSS node with name box.
///
/// # Accessibility
///
/// Until GTK 4.10, `GtkBox` used the `GTK_ACCESSIBLE_ROLE_GROUP` role.
///
/// Starting from GTK 4.12, `GtkBox` uses the `GTK_ACCESSIBLE_ROLE_GENERIC` role.
public struct Box: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The child that determines the baseline, in vertical orientation.
var baselineChild: Int?
/// Whether the children should all be the same size.
var homogeneous: Bool?
/// The amount of space between children.
var spacing: Int
/// The body for the widget "append".
var append: () -> Body = { [] }
/// The body for the widget "prepend".
var prepend: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `Box`.
public init(spacing: Int) {
self.spacing = spacing
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_box_new(GTK_ORIENTATION_VERTICAL, spacing.cInt)?.opaque())
update(storage, modifiers: modifiers)
var appendStorage: [ViewStorage] = []
for view in append() {
appendStorage.append(view.storage(modifiers: modifiers))
gtk_box_append(storage.pointer?.cast(), appendStorage.last?.pointer?.cast())
}
storage.content["append"] = appendStorage
var prependStorage: [ViewStorage] = []
for view in prepend() {
prependStorage.append(view.storage(modifiers: modifiers))
gtk_box_prepend(storage.pointer?.cast(), prependStorage.last?.pointer?.cast())
}
storage.content["prepend"] = prependStorage
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let baselineChild {
gtk_box_set_baseline_child(widget?.cast(), baselineChild.cInt)
}
if let homogeneous {
gtk_box_set_homogeneous(widget?.cast(), homogeneous.cBool)
}
gtk_box_set_spacing(widget?.cast(), spacing.cInt)
if let appendStorage = storage.content["append"] {
for (index, view) in append().enumerated() {
if let storage = appendStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
if let prependStorage = storage.content["prepend"] {
for (index, view) in prepend().enumerated() {
if let storage = prependStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
}
for function in updateFunctions {
function(storage)
}
}
/// The child that determines the baseline, in vertical orientation.
public func baselineChild(_ baselineChild: Int?) -> Self {
var newSelf = self
newSelf.baselineChild = baselineChild
return newSelf
}
/// Whether the children should all be the same size.
public func homogeneous(_ homogeneous: Bool? = true) -> Self {
var newSelf = self
newSelf.homogeneous = homogeneous
return newSelf
}
/// The amount of space between children.
public func spacing(_ spacing: Int) -> Self {
var newSelf = self
newSelf.spacing = spacing
return newSelf
}
/// Set the body for "append".
/// - Parameter body: The body.
/// - Returns: The widget.
public func append(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.append = body
return newSelf
}
/// Set the body for "prepend".
/// - Parameter body: The body.
/// - Returns: The widget.
public func prepend(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.prepend = body
return newSelf
}
}

View File

@ -0,0 +1,221 @@
//
// Button.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// The `GtkButton` widget is generally used to trigger a callback function that is
/// called when the button is pressed.
///
/// ![An example GtkButton](button.png)
///
/// The `GtkButton` widget can hold any valid child widget. That is, it can hold
/// almost any other standard `GtkWidget`. The most commonly used child is the
/// `GtkLabel`.
///
/// # CSS nodes
///
/// `GtkButton` has a single CSS node with name button. The node will get the
/// style classes .image-button or .text-button, if the content is just an
/// image or label, respectively. It may also receive the .flat style class.
/// When activating a button via the keyboard, the button will temporarily
/// gain the .keyboard-activating style class.
///
/// Other style classes that are commonly used with `GtkButton` include
/// .suggested-action and .destructive-action. In special cases, buttons
/// can be made round by adding the .circular style class.
///
/// Button-like widgets like [class@Gtk.ToggleButton], [class@Gtk.MenuButton],
/// [class@Gtk.VolumeButton], [class@Gtk.LockButton], [class@Gtk.ColorButton]
/// or [class@Gtk.FontButton] use style classes such as .toggle, .popup, .scale,
/// .lock, .color on the button node to differentiate themselves from a plain
/// `GtkButton`.
///
/// # Accessibility
///
/// `GtkButton` uses the %GTK_ACCESSIBLE_ROLE_BUTTON role.
public struct Button: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether the size of the button can be made smaller than the natural
/// size of its contents.
///
/// For text buttons, setting this property will allow ellipsizing the label.
///
/// If the contents of a button are an icon or a custom widget, setting this
/// property has no effect.
var canShrink: Bool?
/// The child widget.
var child: (() -> Body)?
/// Whether the button has a frame.
var hasFrame: Bool?
/// The name of the icon used to automatically populate the button.
var iconName: String?
/// Text of the label inside the button, if the button contains a label widget.
var label: String?
/// If set, an underline in the text indicates that the following character is
/// to be used as mnemonic.
var useUnderline: Bool?
/// Emitted to animate press then release.
///
/// This is an action signal. Applications should never connect
/// to this signal, but use the [signal@Gtk.Button::clicked] signal.
///
/// The default bindings for this signal are all forms of the
/// <kbd></kbd> and <kbd>Enter</kbd> keys.
var activate: (() -> Void)?
/// Emitted when the button has been activated (pressed and released).
var clicked: (() -> Void)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `Button`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_button_new()?.opaque())
update(storage, modifiers: modifiers)
if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["child"] = [childStorage]
gtk_button_set_child(storage.pointer?.cast(), childStorage.pointer?.cast())
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let activate {
storage.connectSignal(name: "activate") {
activate()
}
}
if let clicked {
storage.connectSignal(name: "clicked") {
clicked()
}
}
storage.modify { widget in
if let canShrink {
gtk_button_set_can_shrink(widget?.cast(), canShrink.cBool)
}
if let widget = storage.content["child"]?.first {
child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let hasFrame {
gtk_button_set_has_frame(widget?.cast(), hasFrame.cBool)
}
if let iconName {
gtk_button_set_icon_name(widget?.cast(), iconName)
}
if let label, storage.content["child"] == nil {
gtk_button_set_label(widget?.cast(), label)
}
if let useUnderline {
gtk_button_set_use_underline(widget?.cast(), useUnderline.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether the size of the button can be made smaller than the natural
/// size of its contents.
///
/// For text buttons, setting this property will allow ellipsizing the label.
///
/// If the contents of a button are an icon or a custom widget, setting this
/// property has no effect.
public func canShrink(_ canShrink: Bool? = true) -> Self {
var newSelf = self
newSelf.canShrink = canShrink
return newSelf
}
/// The child widget.
public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.child = child
return newSelf
}
/// Whether the button has a frame.
public func hasFrame(_ hasFrame: Bool? = true) -> Self {
var newSelf = self
newSelf.hasFrame = hasFrame
return newSelf
}
/// The name of the icon used to automatically populate the button.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// Text of the label inside the button, if the button contains a label widget.
public func label(_ label: String?) -> Self {
var newSelf = self
newSelf.label = label
return newSelf
}
/// If set, an underline in the text indicates that the following character is
/// to be used as mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// Emitted to animate press then release.
///
/// This is an action signal. Applications should never connect
/// to this signal, but use the [signal@Gtk.Button::clicked] signal.
///
/// The default bindings for this signal are all forms of the
/// <kbd></kbd> and <kbd>Enter</kbd> keys.
public func activate(_ activate: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.activate = activate
return newSelf
}
/// Emitted when the button has been activated (pressed and released).
public func clicked(_ clicked: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.clicked = clicked
return newSelf
}
}

View File

@ -0,0 +1,162 @@
//
// ButtonContent.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A helper widget for creating buttons.
///
/// <picture><source srcset="button-content-dark.png" media="(prefers-color-scheme: dark)"><img src="button-content.png" alt="button-content"></picture>
///
/// `AdwButtonContent` is a box-like widget with an icon and a label.
///
/// It's intended to be used as a direct child of [class@Gtk.Button],
/// [class@Gtk.MenuButton] or [class@SplitButton], when they need to have both an
/// icon and a label, as follows:
///
/// ```xml
/// <object class="GtkButton"><property name="child"><object class="AdwButtonContent"><property name="icon-name">document-open-symbolic</property><property name="label" translatable="yes">_Open</property><property name="use-underline">True</property></object></property></object>
/// ```
///
/// `AdwButtonContent` handles style classes and connecting the mnemonic to the
/// button automatically.
///
/// ## CSS nodes
///
/// ```
/// buttoncontent
/// image
/// label
/// ```
///
/// `AdwButtonContent`'s CSS node is called `buttoncontent`. It contains the
/// subnodes `image` and `label`.
///
/// When inside a `GtkButton` or `AdwSplitButton`, the button will receive the
/// `.image-text-button` style class. When inside a `GtkMenuButton`, the
/// internal `GtkButton` will receive it instead.
///
/// ## Accessibility
///
/// `AdwButtonContent` uses the `GTK_ACCESSIBLE_ROLE_GROUP` role.
public struct ButtonContent: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether the button can be smaller than the natural size of its contents.
///
/// If set to `TRUE`, the label will ellipsize.
///
/// See [property@Gtk.Button:can-shrink].
var canShrink: Bool?
/// The name of the displayed icon.
///
/// If empty, the icon is not shown.
var iconName: String?
/// The displayed label.
var label: String?
/// Whether an underline in the text indicates a mnemonic.
///
/// The mnemonic can be used to activate the parent button.
///
/// See [property@ButtonContent:label].
var useUnderline: Bool?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `ButtonContent`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_button_content_new()?.opaque())
update(storage, modifiers: modifiers)
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let canShrink {
adw_button_content_set_can_shrink(widget, canShrink.cBool)
}
if let iconName {
adw_button_content_set_icon_name(widget, iconName)
}
if let label {
adw_button_content_set_label(widget, label)
}
if let useUnderline {
adw_button_content_set_use_underline(widget, useUnderline.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether the button can be smaller than the natural size of its contents.
///
/// If set to `TRUE`, the label will ellipsize.
///
/// See [property@Gtk.Button:can-shrink].
public func canShrink(_ canShrink: Bool? = true) -> Self {
var newSelf = self
newSelf.canShrink = canShrink
return newSelf
}
/// The name of the displayed icon.
///
/// If empty, the icon is not shown.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// The displayed label.
public func label(_ label: String?) -> Self {
var newSelf = self
newSelf.label = label
return newSelf
}
/// Whether an underline in the text indicates a mnemonic.
///
/// The mnemonic can be used to activate the parent button.
///
/// See [property@ButtonContent:label].
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
}

View File

@ -0,0 +1,229 @@
//
// Carousel.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A paginated scrolling widget.
///
/// <picture><source srcset="carousel-dark.png" media="(prefers-color-scheme: dark)"><img src="carousel.png" alt="carousel"></picture>
///
/// The `AdwCarousel` widget can be used to display a set of pages with
/// swipe-based navigation between them.
///
/// [class@CarouselIndicatorDots] and [class@CarouselIndicatorLines] can be used
/// to provide page indicators for `AdwCarousel`.
///
/// ## CSS nodes
///
/// `AdwCarousel` has a single CSS node with name `carousel`.
public struct Carousel<Element>: Widget where Element: Identifiable {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether to allow swiping for more than one page at a time.
///
/// If the value is `FALSE`, each swipe can only move to the adjacent pages.
var allowLongSwipes: Bool?
/// Sets whether the `AdwCarousel` can be dragged with mouse pointer.
///
/// If the value is `FALSE`, dragging is only available on touch.
var allowMouseDrag: Bool?
/// Whether the widget will respond to scroll wheel events.
///
/// If the value is `FALSE`, wheel events will be ignored.
var allowScrollWheel: Bool?
/// Whether the carousel can be navigated.
///
/// This can be used to temporarily disable the carousel to only allow
/// navigating it in a certain state.
var interactive: Bool?
/// The number of pages in a `AdwCarousel`.
var nPages: UInt?
/// Page reveal duration, in milliseconds.
///
/// Reveal duration is used when animating adding or removing pages.
var revealDuration: UInt?
/// Spacing between pages in pixels.
var spacing: UInt?
/// This signal is emitted after a page has been changed.
///
/// It can be used to implement "infinite scrolling" by amending the pages
/// after every scroll. Note that an empty carousel is indicated by
/// `(int)index == -1`.
var pageChanged: (() -> Void)?
/// The dynamic widget elements.
var elements: [Element]
/// The dynamic widget content.
var content: (Element) -> Body
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `Carousel`.
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
self.elements = elements
self.content = content
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_carousel_new()?.opaque())
update(storage, modifiers: modifiers)
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let pageChanged {
storage.connectSignal(name: "page-changed") {
pageChanged()
}
}
storage.modify { widget in
if let allowLongSwipes {
adw_carousel_set_allow_long_swipes(widget, allowLongSwipes.cBool)
}
if let allowMouseDrag {
adw_carousel_set_allow_mouse_drag(widget, allowMouseDrag.cBool)
}
if let allowScrollWheel {
adw_carousel_set_allow_scroll_wheel(widget, allowScrollWheel.cBool)
}
if let interactive {
adw_carousel_set_interactive(widget, interactive.cBool)
}
if let revealDuration {
adw_carousel_set_reveal_duration(widget, revealDuration.cInt)
}
if let spacing {
adw_carousel_set_spacing(widget, spacing.cInt)
}
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
let old = storage.fields["element"] as? [Element] ?? []
old.identifiableTransform(
to: elements,
functions: .init { index, element in
let child = content(element).widget(modifiers: modifiers).container(modifiers: modifiers)
adw_carousel_remove(widget, adw_carousel_get_nth_page(widget, UInt(index).cInt))
adw_carousel_insert(widget, child.pointer?.cast(), index.cInt)
contentStorage.remove(at: index)
contentStorage.insert(child, at: index)
} delete: { index in
adw_carousel_remove(widget, adw_carousel_get_nth_page(widget, UInt(index).cInt))
contentStorage.remove(at: index)
} insert: { index, element in
let child = content(element).widget(modifiers: modifiers).container(modifiers: modifiers)
adw_carousel_insert(widget, child.pointer?.cast(), index.cInt)
contentStorage.insert(child, at: index)
}
)
storage.fields["element"] = elements
storage.content[.mainContent] = contentStorage
for (index, element) in elements.enumerated() {
content(element).widget(modifiers: modifiers).update(contentStorage[index], modifiers: modifiers)
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether to allow swiping for more than one page at a time.
///
/// If the value is `FALSE`, each swipe can only move to the adjacent pages.
public func allowLongSwipes(_ allowLongSwipes: Bool? = true) -> Self {
var newSelf = self
newSelf.allowLongSwipes = allowLongSwipes
return newSelf
}
/// Sets whether the `AdwCarousel` can be dragged with mouse pointer.
///
/// If the value is `FALSE`, dragging is only available on touch.
public func allowMouseDrag(_ allowMouseDrag: Bool? = true) -> Self {
var newSelf = self
newSelf.allowMouseDrag = allowMouseDrag
return newSelf
}
/// Whether the widget will respond to scroll wheel events.
///
/// If the value is `FALSE`, wheel events will be ignored.
public func allowScrollWheel(_ allowScrollWheel: Bool? = true) -> Self {
var newSelf = self
newSelf.allowScrollWheel = allowScrollWheel
return newSelf
}
/// Whether the carousel can be navigated.
///
/// This can be used to temporarily disable the carousel to only allow
/// navigating it in a certain state.
public func interactive(_ interactive: Bool? = true) -> Self {
var newSelf = self
newSelf.interactive = interactive
return newSelf
}
/// The number of pages in a `AdwCarousel`.
public func nPages(_ nPages: UInt?) -> Self {
var newSelf = self
newSelf.nPages = nPages
return newSelf
}
/// Page reveal duration, in milliseconds.
///
/// Reveal duration is used when animating adding or removing pages.
public func revealDuration(_ revealDuration: UInt?) -> Self {
var newSelf = self
newSelf.revealDuration = revealDuration
return newSelf
}
/// Spacing between pages in pixels.
public func spacing(_ spacing: UInt?) -> Self {
var newSelf = self
newSelf.spacing = spacing
return newSelf
}
/// This signal is emitted after a page has been changed.
///
/// It can be used to implement "infinite scrolling" by amending the pages
/// after every scroll. Note that an empty carousel is indicated by
/// `(int)index == -1`.
public func pageChanged(_ pageChanged: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.pageChanged = pageChanged
return newSelf
}
}

View File

@ -0,0 +1,183 @@
//
// CenterBox.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// `GtkCenterBox` arranges three children in a row, keeping the middle child
/// centered as well as possible.
///
/// ![An example GtkCenterBox](centerbox.png)
///
/// To add children to `GtkCenterBox`, use [method@Gtk.CenterBox.set_start_widget],
/// [method@Gtk.CenterBox.set_center_widget] and
/// [method@Gtk.CenterBox.set_end_widget].
///
/// The sizing and positioning of children can be influenced with the
/// align and expand properties of the children.
///
/// # GtkCenterBox as GtkBuildable
///
/// The `GtkCenterBox` implementation of the `GtkBuildable` interface
/// supports placing children in the 3 positions by specifying start, center
/// or end as the type attribute of a `<child>` element.
///
/// # CSS nodes
///
/// `GtkCenterBox` uses a single CSS node with the name box,
///
/// The first child of the `GtkCenterBox` will be allocated depending on the
/// text direction, i.e. in left-to-right layouts it will be allocated on the
/// left and in right-to-left layouts on the right.
///
/// In vertical orientation, the nodes of the children are arranged from top to
/// bottom.
///
/// # Accessibility
///
/// Until GTK 4.10, `GtkCenterBox` used the `GTK_ACCESSIBLE_ROLE_GROUP` role.
///
/// Starting from GTK 4.12, `GtkCenterBox` uses the `GTK_ACCESSIBLE_ROLE_GENERIC` role.
public struct CenterBox: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The widget that is placed at the center position.
var centerWidget: (() -> Body)?
/// The widget that is placed at the end position.
///
/// In vertical orientation, the end position is at the bottom.
/// In horizontal orientation, the end position is at the trailing
/// edge wrt. to the text direction.
var endWidget: (() -> Body)?
/// Whether to shrink the center widget after other children.
///
/// By default, when there's no space to give all three children their
/// natural widths, the start and end widgets start shrinking and the
/// center child keeps natural width until they reach minimum width.
///
/// If set to `FALSE`, start and end widgets keep natural width and the
/// center widget starts shrinking instead.
var shrinkCenterLast: Bool?
/// The widget that is placed at the start position.
///
/// In vertical orientation, the start position is at the top.
/// In horizontal orientation, the start position is at the leading
/// edge wrt. to the text direction.
var startWidget: (() -> Body)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `CenterBox`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_center_box_new()?.opaque())
update(storage, modifiers: modifiers)
if let centerWidgetStorage = centerWidget?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["centerWidget"] = [centerWidgetStorage]
gtk_center_box_set_center_widget(storage.pointer, centerWidgetStorage.pointer?.cast())
}
if let endWidgetStorage = endWidget?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["endWidget"] = [endWidgetStorage]
gtk_center_box_set_end_widget(storage.pointer, endWidgetStorage.pointer?.cast())
}
if let startWidgetStorage = startWidget?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["startWidget"] = [startWidgetStorage]
gtk_center_box_set_start_widget(storage.pointer, startWidgetStorage.pointer?.cast())
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let widget = storage.content["centerWidget"]?.first {
centerWidget?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let widget = storage.content["endWidget"]?.first {
endWidget?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let shrinkCenterLast {
gtk_center_box_set_shrink_center_last(widget, shrinkCenterLast.cBool)
}
if let widget = storage.content["startWidget"]?.first {
startWidget?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The widget that is placed at the center position.
public func centerWidget(@ViewBuilder _ centerWidget: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.centerWidget = centerWidget
return newSelf
}
/// The widget that is placed at the end position.
///
/// In vertical orientation, the end position is at the bottom.
/// In horizontal orientation, the end position is at the trailing
/// edge wrt. to the text direction.
public func endWidget(@ViewBuilder _ endWidget: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.endWidget = endWidget
return newSelf
}
/// Whether to shrink the center widget after other children.
///
/// By default, when there's no space to give all three children their
/// natural widths, the start and end widgets start shrinking and the
/// center child keeps natural width until they reach minimum width.
///
/// If set to `FALSE`, start and end widgets keep natural width and the
/// center widget starts shrinking instead.
public func shrinkCenterLast(_ shrinkCenterLast: Bool? = true) -> Self {
var newSelf = self
newSelf.shrinkCenterLast = shrinkCenterLast
return newSelf
}
/// The widget that is placed at the start position.
///
/// In vertical orientation, the start position is at the top.
/// In horizontal orientation, the start position is at the leading
/// edge wrt. to the text direction.
public func startWidget(@ViewBuilder _ startWidget: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.startWidget = startWidget
return newSelf
}
}

View File

@ -0,0 +1,246 @@
//
// CheckButton.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A `GtkCheckButton` places a label next to an indicator.
///
/// ![Example GtkCheckButtons](check-button.png)
///
/// A `GtkCheckButton` is created by calling either [ctor@Gtk.CheckButton.new]
/// or [ctor@Gtk.CheckButton.new_with_label].
///
/// The state of a `GtkCheckButton` can be set specifically using
/// [method@Gtk.CheckButton.set_active], and retrieved using
/// [method@Gtk.CheckButton.get_active].
///
/// # Inconsistent state
///
/// In addition to "on" and "off", check buttons can be an
/// "in between" state that is neither on nor off. This can be used
/// e.g. when the user has selected a range of elements (such as some
/// text or spreadsheet cells) that are affected by a check button,
/// and the current values in that range are inconsistent.
///
/// To set a `GtkCheckButton` to inconsistent state, use
/// [method@Gtk.CheckButton.set_inconsistent].
///
/// # Grouping
///
/// Check buttons can be grouped together, to form mutually exclusive
/// groups - only one of the buttons can be toggled at a time, and toggling
/// another one will switch the currently toggled one off.
///
/// Grouped check buttons use a different indicator, and are commonly referred
/// to as *radio buttons*.
///
/// ![Example GtkCheckButtons](radio-button.png)
///
/// To add a `GtkCheckButton` to a group, use [method@Gtk.CheckButton.set_group].
///
/// When the code must keep track of the state of a group of radio buttons, it
/// is recommended to keep track of such state through a stateful
/// `GAction` with a target for each button. Using the `toggled` signals to keep
/// track of the group changes and state is discouraged.
///
/// # CSS nodes
///
/// ```
/// checkbutton[.text-button]
/// check
/// [label]
/// ```
///
/// A `GtkCheckButton` has a main node with name checkbutton. If the
/// [property@Gtk.CheckButton:label] or [property@Gtk.CheckButton:child]
/// properties are set, it contains a child widget. The indicator node
/// is named check when no group is set, and radio if the checkbutton
/// is grouped together with other checkbuttons.
///
/// # Accessibility
///
/// `GtkCheckButton` uses the %GTK_ACCESSIBLE_ROLE_CHECKBOX role.
public struct CheckButton: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// If the check button is active.
///
/// Setting `active` to %TRUE will add the `:checked:` state to both
/// the check button and the indicator CSS node.
var active: Binding<Bool>?
/// The child widget.
var child: (() -> Body)?
/// If the check button is in an in between state.
///
/// The inconsistent state only affects visual appearance,
/// not the semantics of the button.
var inconsistent: Bool?
/// Text of the label inside the check button, if it contains a label widget.
var label: String?
/// If set, an underline in the text indicates that the following
/// character is to be used as mnemonic.
var useUnderline: Bool?
/// Emitted to when the check button is activated.
///
/// The `::activate` signal on `GtkCheckButton` is an action signal and
/// emitting it causes the button to animate press then release.
///
/// Applications should never connect to this signal, but use the
/// [signal@Gtk.CheckButton::toggled] signal.
///
/// The default bindings for this signal are all forms of the
/// <kbd></kbd> and <kbd>Enter</kbd> keys.
var activate: (() -> Void)?
/// Emitted when the buttons's [property@Gtk.CheckButton:active]
/// property changes.
var toggled: (() -> Void)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `CheckButton`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_check_button_new()?.opaque())
update(storage, modifiers: modifiers)
if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["child"] = [childStorage]
gtk_check_button_set_child(storage.pointer?.cast(), childStorage.pointer?.cast())
}
storage.notify(name: "active") {
active?.wrappedValue = gtk_check_button_get_active(storage.pointer?.cast()) != 0
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let activate {
storage.connectSignal(name: "activate") {
activate()
}
}
if let toggled {
storage.connectSignal(name: "toggled") {
toggled()
}
}
storage.modify { widget in
if let active {
gtk_check_button_set_active(widget?.cast(), active.wrappedValue.cBool)
}
if let widget = storage.content["child"]?.first {
child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let inconsistent {
gtk_check_button_set_inconsistent(widget?.cast(), inconsistent.cBool)
}
if let label, storage.content["child"] == nil {
gtk_check_button_set_label(widget?.cast(), label)
}
if let useUnderline {
gtk_check_button_set_use_underline(widget?.cast(), useUnderline.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// If the check button is active.
///
/// Setting `active` to %TRUE will add the `:checked:` state to both
/// the check button and the indicator CSS node.
public func active(_ active: Binding<Bool>?) -> Self {
var newSelf = self
newSelf.active = active
return newSelf
}
/// The child widget.
public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.child = child
return newSelf
}
/// If the check button is in an in between state.
///
/// The inconsistent state only affects visual appearance,
/// not the semantics of the button.
public func inconsistent(_ inconsistent: Bool? = true) -> Self {
var newSelf = self
newSelf.inconsistent = inconsistent
return newSelf
}
/// Text of the label inside the check button, if it contains a label widget.
public func label(_ label: String?) -> Self {
var newSelf = self
newSelf.label = label
return newSelf
}
/// If set, an underline in the text indicates that the following
/// character is to be used as mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// Emitted to when the check button is activated.
///
/// The `::activate` signal on `GtkCheckButton` is an action signal and
/// emitting it causes the button to animate press then release.
///
/// Applications should never connect to this signal, but use the
/// [signal@Gtk.CheckButton::toggled] signal.
///
/// The default bindings for this signal are all forms of the
/// <kbd></kbd> and <kbd>Enter</kbd> keys.
public func activate(_ activate: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.activate = activate
return newSelf
}
/// Emitted when the buttons's [property@Gtk.CheckButton:active]
/// property changes.
public func toggled(_ toggled: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.toggled = toggled
return newSelf
}
}

View File

@ -0,0 +1,146 @@
//
// Clamp.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A widget constraining its child to a given size.
///
/// <picture><source srcset="clamp-wide-dark.png" media="(prefers-color-scheme: dark)"><img src="clamp-wide.png" alt="clamp-wide"></picture><picture><source srcset="clamp-narrow-dark.png" media="(prefers-color-scheme: dark)"><img src="clamp-narrow.png" alt="clamp-narrow"></picture>
///
/// The `AdwClamp` widget constrains the size of the widget it contains to a
/// given maximum size. It will constrain the width if it is horizontal, or the
/// height if it is vertical. The expansion of the child from its minimum to its
/// maximum size is eased out for a smooth transition.
///
/// If the child requires more than the requested maximum size, it will be
/// allocated the minimum size it can fit in instead.
///
/// `AdwClamp` can scale with the text scale factor, use the
/// [property@ClampLayout:unit] property to enable that behavior.
///
/// ## CSS nodes
///
/// `AdwClamp` has a single CSS node with name `clamp`.
public struct Clamp: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The child widget of the `AdwClamp`.
var child: (() -> Body)?
/// The maximum size allocated to the child.
///
/// It is the width if the clamp is horizontal, or the height if it is vertical.
var maximumSize: Int?
/// The size above which the child is clamped.
///
/// Starting from this size, the clamp will tighten its grip on the child,
/// slowly allocating less and less of the available size up to the maximum
/// allocated size. Below that threshold and below the maximum size, the child
/// will be allocated all the available size.
///
/// If the threshold is greater than the maximum size to allocate to the child,
/// the child will be allocated all the size up to the maximum.
/// If the threshold is lower than the minimum size to allocate to the child,
/// that size will be used as the tightening threshold.
///
/// Effectively, tightening the grip on the child before it reaches its maximum
/// size makes transitions to and from the maximum size smoother when resizing.
var tighteningThreshold: Int?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `Clamp`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_clamp_new()?.opaque())
update(storage, modifiers: modifiers)
if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["child"] = [childStorage]
adw_clamp_set_child(storage.pointer, childStorage.pointer?.cast())
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let widget = storage.content["child"]?.first {
child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let maximumSize {
adw_clamp_set_maximum_size(widget, maximumSize.cInt)
}
if let tighteningThreshold {
adw_clamp_set_tightening_threshold(widget, tighteningThreshold.cInt)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The child widget of the `AdwClamp`.
public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.child = child
return newSelf
}
/// The maximum size allocated to the child.
///
/// It is the width if the clamp is horizontal, or the height if it is vertical.
public func maximumSize(_ maximumSize: Int?) -> Self {
var newSelf = self
newSelf.maximumSize = maximumSize
return newSelf
}
/// The size above which the child is clamped.
///
/// Starting from this size, the clamp will tighten its grip on the child,
/// slowly allocating less and less of the available size up to the maximum
/// allocated size. Below that threshold and below the maximum size, the child
/// will be allocated all the available size.
///
/// If the threshold is greater than the maximum size to allocate to the child,
/// the child will be allocated all the size up to the maximum.
/// If the threshold is lower than the minimum size to allocate to the child,
/// that size will be used as the tightening threshold.
///
/// Effectively, tightening the grip on the child before it reaches its maximum
/// size makes transitions to and from the maximum size smoother when resizing.
public func tighteningThreshold(_ tighteningThreshold: Int?) -> Self {
var newSelf = self
newSelf.tighteningThreshold = tighteningThreshold
return newSelf
}
}

View File

@ -0,0 +1,380 @@
//
// ComboRow.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A [class@Gtk.ListBoxRow] used to choose from a list of items.
///
/// <picture><source srcset="combo-row-dark.png" media="(prefers-color-scheme: dark)"><img src="combo-row.png" alt="combo-row"></picture>
///
/// The `AdwComboRow` widget allows the user to choose from a list of valid
/// choices. The row displays the selected choice. When activated, the row
/// displays a popover which allows the user to make a new choice.
///
/// Example of an `AdwComboRow` UI definition:
/// ```xml
/// <object class="AdwComboRow"><property name="title" translatable="yes">Combo Row</property><property name="model"><object class="GtkStringList"><items><item translatable="yes">Foo</item><item translatable="yes">Bar</item><item translatable="yes">Baz</item></items></object></property></object>
/// ```
///
/// The [property@ComboRow:selected] and [property@ComboRow:selected-item]
/// properties can be used to keep track of the selected item and react to their
/// changes.
///
/// `AdwComboRow` mirrors [class@Gtk.DropDown], see that widget for details.
///
/// `AdwComboRow` is [property@Gtk.ListBoxRow:activatable] if a model is set.
///
/// ## CSS nodes
///
/// `AdwComboRow` has a main CSS node with name `row` and the `.combo` style
/// class.
///
/// Its popover has the node named `popover` with the `.menu` style class, it
/// contains a [class@Gtk.ScrolledWindow], which in turn contains a
/// [class@Gtk.ListView], both are accessible via their regular nodes.
///
/// ## Accessibility
///
/// `AdwComboRow` uses the `GTK_ACCESSIBLE_ROLE_COMBO_BOX` role.
public struct ComboRow: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether to show a search entry in the popup.
///
/// If set to `TRUE`, a search entry will be shown in the popup that
/// allows to search for items in the list.
///
/// Search requires [property@ComboRow:expression] to be set.
var enableSearch: Bool?
/// The position of the selected item.
///
/// If no item is selected, the property has the value
/// [const@Gtk.INVALID_LIST_POSITION]
var selected: Binding<UInt>?
/// Whether to use the current value as the subtitle.
///
/// If you use a custom list item factory, you will need to give the row a
/// name conversion expression with [property@ComboRow:expression].
///
/// If set to `TRUE`, you should not access [property@ActionRow:subtitle].
///
/// The subtitle is interpreted as Pango markup if
/// [property@PreferencesRow:use-markup] is set to `TRUE`.
var useSubtitle: Bool?
/// The widget to activate when the row is activated.
///
/// The row can be activated either by clicking on it, calling
/// [method@ActionRow.activate], or via mnemonics in the title.
/// See the [property@PreferencesRow:use-underline] property to enable
/// mnemonics.
///
/// The target widget will be activated by emitting the
/// [signal@Gtk.Widget::mnemonic-activate] signal on it.
var activatableWidget: (() -> Body)?
/// The icon name for this row.
var iconName: String?
/// The subtitle for this row.
///
/// The subtitle is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var subtitle: String?
/// The number of lines at the end of which the subtitle label will be
/// ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
var subtitleLines: Int?
/// Whether the user can copy the subtitle from the label.
///
/// See also [property@Gtk.Label:selectable].
var subtitleSelectable: Bool?
/// The number of lines at the end of which the title label will be ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
var titleLines: Int?
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var title: String?
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
var titleSelectable: Bool?
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
var useMarkup: Bool?
/// Whether an embedded underline in the title indicates a mnemonic.
var useUnderline: Bool?
/// This signal is emitted after the row has been activated.
var activated: (() -> Void)?
/// The body for the widget "suffix".
var suffix: () -> Body = { [] }
/// The body for the widget "prefix".
var prefix: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `ComboRow`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_combo_row_new()?.opaque())
update(storage, modifiers: modifiers)
if let activatableWidgetStorage = activatableWidget?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["activatableWidget"] = [activatableWidgetStorage]
adw_action_row_set_activatable_widget(storage.pointer?.cast(), activatableWidgetStorage.pointer?.cast())
}
var suffixStorage: [ViewStorage] = []
for view in suffix() {
suffixStorage.append(view.storage(modifiers: modifiers))
adw_action_row_add_suffix(storage.pointer?.cast(), suffixStorage.last?.pointer?.cast())
}
storage.content["suffix"] = suffixStorage
var prefixStorage: [ViewStorage] = []
for view in prefix() {
prefixStorage.append(view.storage(modifiers: modifiers))
adw_action_row_add_prefix(storage.pointer?.cast(), prefixStorage.last?.pointer?.cast())
}
storage.content["prefix"] = prefixStorage
storage.notify(name: "selected") {
selected?.wrappedValue = .init(adw_combo_row_get_selected(storage.pointer?.cast()))
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let activated {
storage.connectSignal(name: "activated") {
activated()
}
}
storage.modify { widget in
if let enableSearch {
adw_combo_row_set_enable_search(widget?.cast(), enableSearch.cBool)
}
if let selected {
adw_combo_row_set_selected(widget?.cast(), selected.wrappedValue.cInt)
}
if let useSubtitle {
adw_combo_row_set_use_subtitle(widget?.cast(), useSubtitle.cBool)
}
if let widget = storage.content["activatableWidget"]?.first {
activatableWidget?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let iconName {
adw_action_row_set_icon_name(widget?.cast(), iconName)
}
if let subtitle {
adw_action_row_set_subtitle(widget?.cast(), subtitle)
}
if let subtitleLines {
adw_action_row_set_subtitle_lines(widget?.cast(), subtitleLines.cInt)
}
if let subtitleSelectable {
adw_action_row_set_subtitle_selectable(widget?.cast(), subtitleSelectable.cBool)
}
if let titleLines {
adw_action_row_set_title_lines(widget?.cast(), titleLines.cInt)
}
if let title {
adw_preferences_row_set_title(widget?.cast(), title)
}
if let titleSelectable {
adw_preferences_row_set_title_selectable(widget?.cast(), titleSelectable.cBool)
}
if let useMarkup {
adw_preferences_row_set_use_markup(widget?.cast(), useMarkup.cBool)
}
if let useUnderline {
adw_preferences_row_set_use_underline(widget?.cast(), useUnderline.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether to show a search entry in the popup.
///
/// If set to `TRUE`, a search entry will be shown in the popup that
/// allows to search for items in the list.
///
/// Search requires [property@ComboRow:expression] to be set.
public func enableSearch(_ enableSearch: Bool? = true) -> Self {
var newSelf = self
newSelf.enableSearch = enableSearch
return newSelf
}
/// The position of the selected item.
///
/// If no item is selected, the property has the value
/// [const@Gtk.INVALID_LIST_POSITION]
public func selected(_ selected: Binding<UInt>?) -> Self {
var newSelf = self
newSelf.selected = selected
return newSelf
}
/// Whether to use the current value as the subtitle.
///
/// If you use a custom list item factory, you will need to give the row a
/// name conversion expression with [property@ComboRow:expression].
///
/// If set to `TRUE`, you should not access [property@ActionRow:subtitle].
///
/// The subtitle is interpreted as Pango markup if
/// [property@PreferencesRow:use-markup] is set to `TRUE`.
public func useSubtitle(_ useSubtitle: Bool? = true) -> Self {
var newSelf = self
newSelf.useSubtitle = useSubtitle
return newSelf
}
/// The widget to activate when the row is activated.
///
/// The row can be activated either by clicking on it, calling
/// [method@ActionRow.activate], or via mnemonics in the title.
/// See the [property@PreferencesRow:use-underline] property to enable
/// mnemonics.
///
/// The target widget will be activated by emitting the
/// [signal@Gtk.Widget::mnemonic-activate] signal on it.
public func activatableWidget(@ViewBuilder _ activatableWidget: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.activatableWidget = activatableWidget
return newSelf
}
/// The icon name for this row.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// The subtitle for this row.
///
/// The subtitle is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func subtitle(_ subtitle: String?) -> Self {
var newSelf = self
newSelf.subtitle = subtitle
return newSelf
}
/// The number of lines at the end of which the subtitle label will be
/// ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
public func subtitleLines(_ subtitleLines: Int?) -> Self {
var newSelf = self
newSelf.subtitleLines = subtitleLines
return newSelf
}
/// Whether the user can copy the subtitle from the label.
///
/// See also [property@Gtk.Label:selectable].
public func subtitleSelectable(_ subtitleSelectable: Bool? = true) -> Self {
var newSelf = self
newSelf.subtitleSelectable = subtitleSelectable
return newSelf
}
/// The number of lines at the end of which the title label will be ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
public func titleLines(_ titleLines: Int?) -> Self {
var newSelf = self
newSelf.titleLines = titleLines
return newSelf
}
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func title(_ title: String?) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
public func titleSelectable(_ titleSelectable: Bool? = true) -> Self {
var newSelf = self
newSelf.titleSelectable = titleSelectable
return newSelf
}
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
public func useMarkup(_ useMarkup: Bool? = true) -> Self {
var newSelf = self
newSelf.useMarkup = useMarkup
return newSelf
}
/// Whether an embedded underline in the title indicates a mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// This signal is emitted after the row has been activated.
public func activated(_ activated: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.activated = activated
return newSelf
}
}

View File

@ -0,0 +1,293 @@
//
// EntryRow.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A [class@Gtk.ListBoxRow] with an embedded text entry.
///
/// <picture><source srcset="entry-row-dark.png" media="(prefers-color-scheme: dark)"><img src="entry-row.png" alt="entry-row"></picture>
///
/// `AdwEntryRow` has a title that doubles as placeholder text. It shows an icon
/// indicating that it's editable and can receive additional widgets before or
/// after the editable part.
///
/// If [property@EntryRow:show-apply-button] is set to `TRUE`, `AdwEntryRow` can
/// show an apply button when editing its contents. This can be useful if
/// changing its contents can result in an expensive operation, such as network
/// activity.
///
/// `AdwEntryRow` provides only minimal API and should be used with the
/// [iface@Gtk.Editable] API.
///
/// See also [class@PasswordEntryRow].
///
/// ## AdwEntryRow as GtkBuildable
///
/// The `AdwEntryRow` implementation of the [iface@Gtk.Buildable] interface
/// supports adding a child at its end by specifying suffix or omitting the
/// type attribute of a <child> element.
///
/// It also supports adding a child as a prefix widget by specifying prefix as
/// the type attribute of a <child> element.
///
/// ## CSS nodes
///
/// `AdwEntryRow` has a single CSS node with name `row` and the `.entry` style
/// class.
public struct EntryRow: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether activating the embedded entry can activate the default widget.
var activatesDefault: Bool?
/// Whether to suggest emoji replacements on the entry row.
///
/// Emoji replacement is done with :-delimited names, like `:heart:`.
var enableEmojiCompletion: Bool?
/// Whether to show the apply button.
///
/// When set to `TRUE`, typing text in the entry will reveal an apply button.
/// Clicking it or pressing the <kbd>Enter</kbd> key will hide the button and
/// emit the [signal@EntryRow::apply] signal.
///
/// This is useful if changing the entry contents can trigger an expensive
/// operation, e.g. network activity, to avoid triggering it after typing every
/// character.
var showApplyButton: Bool?
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var title: String?
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
var titleSelectable: Bool?
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
var useMarkup: Bool?
/// Whether an embedded underline in the title indicates a mnemonic.
var useUnderline: Bool?
/// Emitted when the apply button is pressed.
///
/// See [property@EntryRow:show-apply-button].
var apply: (() -> Void)?
/// Emitted when the embedded entry is activated.
var entryActivated: (() -> Void)?
/// The body for the widget "suffix".
var suffix: () -> Body = { [] }
/// The body for the widget "prefix".
var prefix: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `EntryRow`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_entry_row_new()?.opaque())
update(storage, modifiers: modifiers)
var suffixStorage: [ViewStorage] = []
for view in suffix() {
suffixStorage.append(view.storage(modifiers: modifiers))
adw_entry_row_add_suffix(storage.pointer?.cast(), suffixStorage.last?.pointer?.cast())
}
storage.content["suffix"] = suffixStorage
var prefixStorage: [ViewStorage] = []
for view in prefix() {
prefixStorage.append(view.storage(modifiers: modifiers))
adw_entry_row_add_prefix(storage.pointer?.cast(), prefixStorage.last?.pointer?.cast())
}
storage.content["prefix"] = prefixStorage
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let apply {
storage.connectSignal(name: "apply") {
apply()
}
}
if let entryActivated {
storage.connectSignal(name: "entry-activated") {
entryActivated()
}
}
storage.modify { widget in
if let activatesDefault {
adw_entry_row_set_activates_default(widget?.cast(), activatesDefault.cBool)
}
if let enableEmojiCompletion {
adw_entry_row_set_enable_emoji_completion(widget?.cast(), enableEmojiCompletion.cBool)
}
if let showApplyButton {
adw_entry_row_set_show_apply_button(widget?.cast(), showApplyButton.cBool)
}
if let title {
adw_preferences_row_set_title(widget?.cast(), title)
}
if let titleSelectable {
adw_preferences_row_set_title_selectable(widget?.cast(), titleSelectable.cBool)
}
if let useMarkup {
adw_preferences_row_set_use_markup(widget?.cast(), useMarkup.cBool)
}
if let useUnderline {
adw_preferences_row_set_use_underline(widget?.cast(), useUnderline.cBool)
}
if let suffixStorage = storage.content["suffix"] {
for (index, view) in suffix().enumerated() {
if let storage = suffixStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
if let prefixStorage = storage.content["prefix"] {
for (index, view) in prefix().enumerated() {
if let storage = prefixStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether activating the embedded entry can activate the default widget.
public func activatesDefault(_ activatesDefault: Bool? = true) -> Self {
var newSelf = self
newSelf.activatesDefault = activatesDefault
return newSelf
}
/// Whether to suggest emoji replacements on the entry row.
///
/// Emoji replacement is done with :-delimited names, like `:heart:`.
public func enableEmojiCompletion(_ enableEmojiCompletion: Bool? = true) -> Self {
var newSelf = self
newSelf.enableEmojiCompletion = enableEmojiCompletion
return newSelf
}
/// Whether to show the apply button.
///
/// When set to `TRUE`, typing text in the entry will reveal an apply button.
/// Clicking it or pressing the <kbd>Enter</kbd> key will hide the button and
/// emit the [signal@EntryRow::apply] signal.
///
/// This is useful if changing the entry contents can trigger an expensive
/// operation, e.g. network activity, to avoid triggering it after typing every
/// character.
public func showApplyButton(_ showApplyButton: Bool? = true) -> Self {
var newSelf = self
newSelf.showApplyButton = showApplyButton
return newSelf
}
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func title(_ title: String?) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
public func titleSelectable(_ titleSelectable: Bool? = true) -> Self {
var newSelf = self
newSelf.titleSelectable = titleSelectable
return newSelf
}
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
public func useMarkup(_ useMarkup: Bool? = true) -> Self {
var newSelf = self
newSelf.useMarkup = useMarkup
return newSelf
}
/// Whether an embedded underline in the title indicates a mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// Emitted when the apply button is pressed.
///
/// See [property@EntryRow:show-apply-button].
public func apply(_ apply: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.apply = apply
return newSelf
}
/// Emitted when the embedded entry is activated.
public func entryActivated(_ entryActivated: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.entryActivated = entryActivated
return newSelf
}
/// Set the body for "suffix".
/// - Parameter body: The body.
/// - Returns: The widget.
public func suffix(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.suffix = body
return newSelf
}
/// Set the body for "prefix".
/// - Parameter body: The body.
/// - Returns: The widget.
public func prefix(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.prefix = body
return newSelf
}
}

View File

@ -0,0 +1,332 @@
//
// ExpanderRow.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A [class@Gtk.ListBoxRow] used to reveal widgets.
///
/// <picture><source srcset="expander-row-dark.png" media="(prefers-color-scheme: dark)"><img src="expander-row.png" alt="expander-row"></picture>
///
/// The `AdwExpanderRow` widget allows the user to reveal or hide widgets below
/// it. It also allows the user to enable the expansion of the row, allowing to
/// disable all that the row contains.
///
/// ## AdwExpanderRow as GtkBuildable
///
/// The `AdwExpanderRow` implementation of the [iface@Gtk.Buildable] interface
/// supports adding a child as an suffix widget by specifying suffix as the
/// type attribute of a <child> element.
///
/// It also supports adding it as a prefix widget by specifying prefix as the
/// type attribute of a <child> element.
///
/// ## CSS nodes
///
/// `AdwExpanderRow` has a main CSS node with name `row` and the `.expander`
/// style class. It has the `.empty` style class when it contains no children.
///
/// It contains the subnodes `row.header` for its main embedded row,
/// `list.nested` for the list it can expand, and `image.expander-row-arrow` for
/// its arrow.
public struct ExpanderRow: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether expansion is enabled.
var enableExpansion: Binding<Bool>?
/// Whether the row is expanded.
var expanded: Binding<Bool>?
/// The icon name for this row.
var iconName: String?
/// Whether the switch enabling the expansion is visible.
var showEnableSwitch: Bool?
/// The subtitle for this row.
///
/// The subtitle is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var subtitle: String?
/// The number of lines at the end of which the subtitle label will be
/// ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
var subtitleLines: Int?
/// The number of lines at the end of which the title label will be ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
var titleLines: Int?
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var title: String?
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
var titleSelectable: Bool?
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
var useMarkup: Bool?
/// Whether an embedded underline in the title indicates a mnemonic.
var useUnderline: Bool?
/// The body for the widget "rows".
var rows: () -> Body = { [] }
/// The body for the widget "suffix".
var suffix: () -> Body = { [] }
/// The body for the widget "prefix".
var prefix: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `ExpanderRow`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_expander_row_new()?.opaque())
update(storage, modifiers: modifiers)
var rowsStorage: [ViewStorage] = []
for view in rows() {
rowsStorage.append(view.storage(modifiers: modifiers))
adw_expander_row_add_row(storage.pointer?.cast(), rowsStorage.last?.pointer?.cast())
}
storage.content["rows"] = rowsStorage
var suffixStorage: [ViewStorage] = []
for view in suffix() {
suffixStorage.append(view.storage(modifiers: modifiers))
adw_expander_row_add_suffix(storage.pointer?.cast(), suffixStorage.last?.pointer?.cast())
}
storage.content["suffix"] = suffixStorage
var prefixStorage: [ViewStorage] = []
for view in prefix() {
prefixStorage.append(view.storage(modifiers: modifiers))
adw_expander_row_add_prefix(storage.pointer?.cast(), prefixStorage.last?.pointer?.cast())
}
storage.content["prefix"] = prefixStorage
storage.notify(name: "enable-expansion") {
enableExpansion?.wrappedValue = adw_expander_row_get_enable_expansion(storage.pointer?.cast()) != 0
}
storage.notify(name: "expanded") {
expanded?.wrappedValue = adw_expander_row_get_expanded(storage.pointer?.cast()) != 0
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let enableExpansion {
adw_expander_row_set_enable_expansion(widget?.cast(), enableExpansion.wrappedValue.cBool)
}
if let expanded {
adw_expander_row_set_expanded(widget?.cast(), expanded.wrappedValue.cBool)
}
if let iconName {
adw_expander_row_set_icon_name(widget?.cast(), iconName)
}
if let showEnableSwitch {
adw_expander_row_set_show_enable_switch(widget?.cast(), showEnableSwitch.cBool)
}
if let subtitle {
adw_expander_row_set_subtitle(widget?.cast(), subtitle)
}
if let subtitleLines {
adw_expander_row_set_subtitle_lines(widget?.cast(), subtitleLines.cInt)
}
if let titleLines {
adw_expander_row_set_title_lines(widget?.cast(), titleLines.cInt)
}
if let title {
adw_preferences_row_set_title(widget?.cast(), title)
}
if let titleSelectable {
adw_preferences_row_set_title_selectable(widget?.cast(), titleSelectable.cBool)
}
if let useMarkup {
adw_preferences_row_set_use_markup(widget?.cast(), useMarkup.cBool)
}
if let useUnderline {
adw_preferences_row_set_use_underline(widget?.cast(), useUnderline.cBool)
}
if let rowsStorage = storage.content["rows"] {
for (index, view) in rows().enumerated() {
if let storage = rowsStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
if let suffixStorage = storage.content["suffix"] {
for (index, view) in suffix().enumerated() {
if let storage = suffixStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
if let prefixStorage = storage.content["prefix"] {
for (index, view) in prefix().enumerated() {
if let storage = prefixStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether expansion is enabled.
public func enableExpansion(_ enableExpansion: Binding<Bool>?) -> Self {
var newSelf = self
newSelf.enableExpansion = enableExpansion
return newSelf
}
/// Whether the row is expanded.
public func expanded(_ expanded: Binding<Bool>?) -> Self {
var newSelf = self
newSelf.expanded = expanded
return newSelf
}
/// The icon name for this row.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// Whether the switch enabling the expansion is visible.
public func showEnableSwitch(_ showEnableSwitch: Bool? = true) -> Self {
var newSelf = self
newSelf.showEnableSwitch = showEnableSwitch
return newSelf
}
/// The subtitle for this row.
///
/// The subtitle is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func subtitle(_ subtitle: String?) -> Self {
var newSelf = self
newSelf.subtitle = subtitle
return newSelf
}
/// The number of lines at the end of which the subtitle label will be
/// ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
public func subtitleLines(_ subtitleLines: Int?) -> Self {
var newSelf = self
newSelf.subtitleLines = subtitleLines
return newSelf
}
/// The number of lines at the end of which the title label will be ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
public func titleLines(_ titleLines: Int?) -> Self {
var newSelf = self
newSelf.titleLines = titleLines
return newSelf
}
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func title(_ title: String?) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
public func titleSelectable(_ titleSelectable: Bool? = true) -> Self {
var newSelf = self
newSelf.titleSelectable = titleSelectable
return newSelf
}
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
public func useMarkup(_ useMarkup: Bool? = true) -> Self {
var newSelf = self
newSelf.useMarkup = useMarkup
return newSelf
}
/// Whether an embedded underline in the title indicates a mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// Set the body for "rows".
/// - Parameter body: The body.
/// - Returns: The widget.
public func rows(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.rows = body
return newSelf
}
/// Set the body for "suffix".
/// - Parameter body: The body.
/// - Returns: The widget.
public func suffix(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.suffix = body
return newSelf
}
/// Set the body for "prefix".
/// - Parameter body: The body.
/// - Returns: The widget.
public func prefix(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.prefix = body
return newSelf
}
}

View File

@ -0,0 +1,331 @@
//
// HeaderBar.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A title bar widget.
///
/// <picture><source srcset="header-bar-dark.png" media="(prefers-color-scheme: dark)"><img src="header-bar.png" alt="header-bar"></picture>
///
/// `AdwHeaderBar` is similar to [class@Gtk.HeaderBar], but provides additional
/// features compared to it. Refer to `GtkHeaderBar` for details. It is typically
/// used as a top bar within [class@ToolbarView].
///
/// ## Navigation View Integration
///
/// When placed inside an [class@NavigationPage], `AdwHeaderBar` will display the
/// page title instead of window title.
///
/// When used together with [class@NavigationView] or [class@NavigationSplitView],
/// it will also display a back button that can be used to go back to the previous
/// page. The button also has a context menu, allowing to pop multiple pages at
/// once, potentially across multiple navigation views. In rare scenarios, set
/// [property@HeaderBar:show-back-button] to `FALSE` to disable the back button
/// if it's unwanted (e.g. in an extra header bar on the same page).
///
/// ## Split View Integration
///
/// When placed inside `AdwNavigationSplitView` or `AdwOverlaySplitView`,
/// `AdwHeaderBar` will automatically hide the title buttons other than at the
/// edges of the window.
///
/// ## Centering Policy
///
/// [property@HeaderBar:centering-policy] allows to enforce strict centering of
/// the title widget. This can be useful for entries inside [class@Clamp].
///
/// ## Title Buttons
///
/// Unlike `GtkHeaderBar`, `AdwHeaderBar` allows to toggle title button
/// visibility for each side individually, using the
/// [property@HeaderBar:show-start-title-buttons] and
/// [property@HeaderBar:show-end-title-buttons] properties.
///
/// ## CSS nodes
///
/// ```
/// headerbar
/// windowhandle
/// box
/// widget
/// box.start
/// windowcontrols.start
/// widget
/// [button.back]
/// [other children]
/// widget
/// [Title Widget]
/// widget
/// box.end
/// [other children]
/// windowcontrols.end
/// ```
///
/// `AdwHeaderBar`'s CSS node is called `headerbar`. It contains a `windowhandle`
/// subnode, which contains a `box` subnode, which contains three `widget`
/// subnodes at the start, center and end of the header bar. The start and end
/// subnotes contain a `box` subnode with the `.start` and `.end` style classes
/// respectively, and the center node contains a node that represents the title.
///
/// Each of the boxes contains a `windowcontrols` subnode, see
/// [class@Gtk.WindowControls] for details, as well as other children.
///
/// When [property@HeaderBar:show-back-button] is `TRUE`, the start box also
/// contains a node with the name `widget` that contains a node with the name
/// `button` and `.back` style class.
///
/// ## Accessibility
///
/// `AdwHeaderBar` uses the `GTK_ACCESSIBLE_ROLE_GROUP` role.
public struct HeaderBar: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The decoration layout for buttons.
///
/// If this property is not set, the
/// [property@Gtk.Settings:gtk-decoration-layout] setting is used.
///
/// The format of the string is button names, separated by commas. A colon
/// separates the buttons that should appear at the start from those at the
/// end. Recognized button names are minimize, maximize, close and icon (the
/// window icon).
///
/// For example, icon:minimize,maximize,close specifies an icon at the start,
/// and minimize, maximize and close buttons at the end.
var decorationLayout: String?
/// Whether the header bar can show the back button.
///
/// The back button will never be shown unless the header bar is placed inside an
/// [class@NavigationView]. Usually, there is no reason to set this to `FALSE`.
var showBackButton: Bool?
/// Whether to show title buttons at the end of the header bar.
///
/// See [property@HeaderBar:show-start-title-buttons] for the other side.
///
/// Which buttons are actually shown and where is determined by the
/// [property@HeaderBar:decoration-layout] property, and by the state of the
/// window (e.g. a close button will not be shown if the window can't be
/// closed).
var showEndTitleButtons: Bool?
/// Whether to show title buttons at the start of the header bar.
///
/// See [property@HeaderBar:show-end-title-buttons] for the other side.
///
/// Which buttons are actually shown and where is determined by the
/// [property@HeaderBar:decoration-layout] property, and by the state of the
/// window (e.g. a close button will not be shown if the window can't be
/// closed).
var showStartTitleButtons: Bool?
/// Whether the title widget should be shown.
var showTitle: Bool?
/// The title widget to display.
///
/// When set to `NULL`, the header bar will display the title of the window it
/// is contained in.
///
/// To use a different title, use [class@WindowTitle]:
///
/// ```xml
/// <object class="AdwHeaderBar"><property name="title-widget"><object class="AdwWindowTitle"><property name="title" translatable="yes">Title</property></object></property></object>
/// ```
var titleWidget: (() -> Body)?
/// The body for the widget "start".
var start: () -> Body = { [] }
/// The body for the widget "end".
var end: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `HeaderBar`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_header_bar_new()?.opaque())
update(storage, modifiers: modifiers)
if let titleWidgetStorage = titleWidget?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["titleWidget"] = [titleWidgetStorage]
adw_header_bar_set_title_widget(storage.pointer, titleWidgetStorage.pointer?.cast())
}
var startStorage: [ViewStorage] = []
for view in start() {
startStorage.append(view.storage(modifiers: modifiers))
adw_header_bar_pack_start(storage.pointer, startStorage.last?.pointer?.cast())
}
storage.content["start"] = startStorage
var endStorage: [ViewStorage] = []
for view in end() {
endStorage.append(view.storage(modifiers: modifiers))
adw_header_bar_pack_end(storage.pointer, endStorage.last?.pointer?.cast())
}
storage.content["end"] = endStorage
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let decorationLayout {
adw_header_bar_set_decoration_layout(widget, decorationLayout)
}
if let showBackButton {
adw_header_bar_set_show_back_button(widget, showBackButton.cBool)
}
if let showEndTitleButtons {
adw_header_bar_set_show_end_title_buttons(widget, showEndTitleButtons.cBool)
}
if let showStartTitleButtons {
adw_header_bar_set_show_start_title_buttons(widget, showStartTitleButtons.cBool)
}
if let showTitle {
adw_header_bar_set_show_title(widget, showTitle.cBool)
}
if let widget = storage.content["titleWidget"]?.first {
titleWidget?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let startStorage = storage.content["start"] {
for (index, view) in start().enumerated() {
if let storage = startStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
if let endStorage = storage.content["end"] {
for (index, view) in end().enumerated() {
if let storage = endStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
}
for function in updateFunctions {
function(storage)
}
}
/// The decoration layout for buttons.
///
/// If this property is not set, the
/// [property@Gtk.Settings:gtk-decoration-layout] setting is used.
///
/// The format of the string is button names, separated by commas. A colon
/// separates the buttons that should appear at the start from those at the
/// end. Recognized button names are minimize, maximize, close and icon (the
/// window icon).
///
/// For example, icon:minimize,maximize,close specifies an icon at the start,
/// and minimize, maximize and close buttons at the end.
public func decorationLayout(_ decorationLayout: String?) -> Self {
var newSelf = self
newSelf.decorationLayout = decorationLayout
return newSelf
}
/// Whether the header bar can show the back button.
///
/// The back button will never be shown unless the header bar is placed inside an
/// [class@NavigationView]. Usually, there is no reason to set this to `FALSE`.
public func showBackButton(_ showBackButton: Bool? = true) -> Self {
var newSelf = self
newSelf.showBackButton = showBackButton
return newSelf
}
/// Whether to show title buttons at the end of the header bar.
///
/// See [property@HeaderBar:show-start-title-buttons] for the other side.
///
/// Which buttons are actually shown and where is determined by the
/// [property@HeaderBar:decoration-layout] property, and by the state of the
/// window (e.g. a close button will not be shown if the window can't be
/// closed).
public func showEndTitleButtons(_ showEndTitleButtons: Bool? = true) -> Self {
var newSelf = self
newSelf.showEndTitleButtons = showEndTitleButtons
return newSelf
}
/// Whether to show title buttons at the start of the header bar.
///
/// See [property@HeaderBar:show-end-title-buttons] for the other side.
///
/// Which buttons are actually shown and where is determined by the
/// [property@HeaderBar:decoration-layout] property, and by the state of the
/// window (e.g. a close button will not be shown if the window can't be
/// closed).
public func showStartTitleButtons(_ showStartTitleButtons: Bool? = true) -> Self {
var newSelf = self
newSelf.showStartTitleButtons = showStartTitleButtons
return newSelf
}
/// Whether the title widget should be shown.
public func showTitle(_ showTitle: Bool? = true) -> Self {
var newSelf = self
newSelf.showTitle = showTitle
return newSelf
}
/// The title widget to display.
///
/// When set to `NULL`, the header bar will display the title of the window it
/// is contained in.
///
/// To use a different title, use [class@WindowTitle]:
///
/// ```xml
/// <object class="AdwHeaderBar"><property name="title-widget"><object class="AdwWindowTitle"><property name="title" translatable="yes">Title</property></object></property></object>
/// ```
public func titleWidget(@ViewBuilder _ titleWidget: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.titleWidget = titleWidget
return newSelf
}
/// Set the body for "start".
/// - Parameter body: The body.
/// - Returns: The widget.
public func start(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.start = body
return newSelf
}
/// Set the body for "end".
/// - Parameter body: The body.
/// - Returns: The widget.
public func end(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.end = body
return newSelf
}
}

View File

@ -0,0 +1,502 @@
//
// Label.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// The `GtkLabel` widget displays a small amount of text.
///
/// As the name implies, most labels are used to label another widget
/// such as a [class@Button].
///
/// ![An example GtkLabel](label.png)
///
/// # CSS nodes
///
/// ```
/// label
/// [selection]
/// [link]
///
/// [link]
/// ```
///
/// `GtkLabel` has a single CSS node with the name label. A wide variety
/// of style classes may be applied to labels, such as .title, .subtitle,
/// .dim-label, etc. In the `GtkShortcutsWindow`, labels are used with the
/// .keycap style class.
///
/// If the label has a selection, it gets a subnode with name selection.
///
/// If the label has links, there is one subnode per link. These subnodes
/// carry the link or visited state depending on whether they have been
/// visited. In this case, label node also gets a .link style class.
///
/// # GtkLabel as GtkBuildable
///
/// The GtkLabel implementation of the GtkBuildable interface supports a
/// custom `<attributes>` element, which supports any number of `<attribute>`
/// elements. The <attribute> element has attributes named name, value,
/// start and end and allows you to specify [struct@Pango.Attribute]
/// values for this label.
///
/// An example of a UI definition fragment specifying Pango attributes:
/// ```xml
/// <object class="GtkLabel"><attributes><attribute name="weight" value="PANGO_WEIGHT_BOLD"/><attribute name="background" value="red" start="5" end="10"/></attributes></object>
/// ```
///
/// The start and end attributes specify the range of characters to which the
/// Pango attribute applies. If start and end are not specified, the attribute is
/// applied to the whole text. Note that specifying ranges does not make much
/// sense with translatable attributes. Use markup embedded in the translatable
/// content instead.
///
/// # Accessibility
///
/// `GtkLabel` uses the %GTK_ACCESSIBLE_ROLE_LABEL role.
///
/// # Mnemonics
///
/// Labels may contain mnemonics. Mnemonics are underlined characters in the
/// label, used for keyboard navigation. Mnemonics are created by providing a
/// string with an underscore before the mnemonic character, such as `"_File"`,
/// to the functions [ctor@Gtk.Label.new_with_mnemonic] or
/// [method@Gtk.Label.set_text_with_mnemonic].
///
/// Mnemonics automatically activate any activatable widget the label is
/// inside, such as a [class@Gtk.Button]; if the label is not inside the
/// mnemonics target widget, you have to tell the label about the target
/// using [class@Gtk.Label.set_mnemonic_widget]. Heres a simple example where
/// the label is inside a button:
///
/// ```c
/// // Pressing Alt+H will activate this button
/// GtkWidget *button = gtk_button_new ();
/// GtkWidget *label = gtk_label_new_with_mnemonic ("_Hello");
/// gtk_button_set_child (GTK_BUTTON (button), label);
/// ```
///
/// Theres a convenience function to create buttons with a mnemonic label
/// already inside:
///
/// ```c
/// // Pressing Alt+H will activate this button
/// GtkWidget *button = gtk_button_new_with_mnemonic ("_Hello");
/// ```
///
/// To create a mnemonic for a widget alongside the label, such as a
/// [class@Gtk.Entry], you have to point the label at the entry with
/// [method@Gtk.Label.set_mnemonic_widget]:
///
/// ```c
/// // Pressing Alt+H will focus the entry
/// GtkWidget *entry = gtk_entry_new ();
/// GtkWidget *label = gtk_label_new_with_mnemonic ("_Hello");
/// gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
/// ```
///
/// # Markup (styled text)
///
/// To make it easy to format text in a label (changing colors,
/// fonts, etc.), label text can be provided in a simple
/// markup format:
///
/// Heres how to create a label with a small font:
/// ```c
/// GtkWidget *label = gtk_label_new (NULL);
/// gtk_label_set_markup (GTK_LABEL (label), "<small>Small text</small>");
/// ```
///
/// (See the Pango manual for complete documentation] of available
/// tags, [func@Pango.parse_markup])
///
/// The markup passed to [method@Gtk.Label.set_markup] must be valid; for example,
/// literal `<`, `>` and `&` characters must be escaped as `&lt;`, `&gt;`, and `&amp;`.
/// If you pass text obtained from the user, file, or a network to
/// [method@Gtk.Label.set_markup], youll want to escape it with
/// [func@GLib.markup_escape_text] or [func@GLib.markup_printf_escaped].
///
/// Markup strings are just a convenient way to set the [struct@Pango.AttrList]
/// on a label; [method@Gtk.Label.set_attributes] may be a simpler way to set
/// attributes in some cases. Be careful though; [struct@Pango.AttrList] tends
/// to cause internationalization problems, unless youre applying attributes
/// to the entire string (i.e. unless you set the range of each attribute
/// to [0, %G_MAXINT)). The reason is that specifying the start_index and
/// end_index for a [struct@Pango.Attribute] requires knowledge of the exact
/// string being displayed, so translations will cause problems.
///
/// # Selectable labels
///
/// Labels can be made selectable with [method@Gtk.Label.set_selectable].
/// Selectable labels allow the user to copy the label contents to
/// the clipboard. Only labels that contain useful-to-copy information
/// such as error messages should be made selectable.
///
/// # Text layout
///
/// A label can contain any number of paragraphs, but will have
/// performance problems if it contains more than a small number.
/// Paragraphs are separated by newlines or other paragraph separators
/// understood by Pango.
///
/// Labels can automatically wrap text if you call [method@Gtk.Label.set_wrap].
///
/// [method@Gtk.Label.set_justify] sets how the lines in a label align
/// with one another. If you want to set how the label as a whole aligns
/// in its available space, see the [property@Gtk.Widget:halign] and
/// [property@Gtk.Widget:valign] properties.
///
/// The [property@Gtk.Label:width-chars] and [property@Gtk.Label:max-width-chars]
/// properties can be used to control the size allocation of ellipsized or
/// wrapped labels. For ellipsizing labels, if either is specified (and less
/// than the actual text size), it is used as the minimum width, and the actual
/// text size is used as the natural width of the label. For wrapping labels,
/// width-chars is used as the minimum width, if specified, and max-width-chars
/// is used as the natural width. Even if max-width-chars specified, wrapping
/// labels will be rewrapped to use all of the available width.
///
/// # Links
///
/// GTK supports markup for clickable hyperlinks in addition to regular Pango
/// markup. The markup for links is borrowed from HTML, using the `<a>` with
/// href, title and class attributes. GTK renders links similar to the
/// way they appear in web browsers, with colored, underlined text. The title
/// attribute is displayed as a tooltip on the link. The class attribute is
/// used as style class on the CSS node for the link.
///
/// An example looks like this:
///
/// ```c
/// const char *text =
/// "Go to the "
/// "<a href=\"https://www.gtk.org\" title=\"&lt;i&gt;Our&lt;/i&gt; website\">"
/// "GTK website</a> for more...";
/// GtkWidget *label = gtk_label_new (NULL);
/// gtk_label_set_markup (GTK_LABEL (label), text);
/// ```
///
/// It is possible to implement custom handling for links and their tooltips
/// with the [signal@Gtk.Label::activate-link] signal and the
/// [method@Gtk.Label.get_current_uri] function.
public struct Label: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The contents of the label.
///
/// If the string contains Pango markup (see [func@Pango.parse_markup]),
/// you will have to set the [property@Gtk.Label:use-markup] property to
/// %TRUE in order for the label to display the markup attributes. See also
/// [method@Gtk.Label.set_markup] for a convenience function that sets both
/// this property and the [property@Gtk.Label:use-markup] property at the
/// same time.
///
/// If the string contains underlines acting as mnemonics, you will have to
/// set the [property@Gtk.Label:use-underline] property to %TRUE in order
/// for the label to display them.
var label: String
/// The number of lines to which an ellipsized, wrapping label
/// should be limited.
///
/// This property has no effect if the label is not wrapping or ellipsized.
/// Set this property to -1 if you don't want to limit the number of lines.
var lines: Int?
/// The desired maximum width of the label, in characters.
///
/// If this property is set to -1, the width will be calculated automatically.
///
/// See the section on [text layout](class.Label.html#text-layout) for details of how
/// [property@Gtk.Label:width-chars] and [property@Gtk.Label:max-width-chars]
/// determine the width of ellipsized and wrapped labels.
var maxWidthChars: Int?
/// The mnemonic accelerator key for the label.
var mnemonicKeyval: UInt?
/// The widget to be activated when the labels mnemonic key is pressed.
var mnemonicWidget: (() -> Body)?
/// Whether the label text can be selected with the mouse.
var selectable: Bool?
/// Whether the label is in single line mode.
///
/// In single line mode, the height of the label does not depend on the
/// actual text, it is always set to ascent + descent of the font. This
/// can be an advantage in situations where resizing the label because
/// of text changes would be distracting, e.g. in a statusbar.
var singleLineMode: Bool?
/// %TRUE if the text of the label includes Pango markup.
///
/// See [func@Pango.parse_markup].
var useMarkup: Bool?
/// %TRUE if the text of the label indicates a mnemonic with an _
/// before the mnemonic character.
var useUnderline: Bool?
/// The desired width of the label, in characters.
///
/// If this property is set to -1, the width will be calculated automatically.
///
/// See the section on [text layout](class.Label.html#text-layout) for details of how
/// [property@Gtk.Label:width-chars] and [property@Gtk.Label:max-width-chars]
/// determine the width of ellipsized and wrapped labels.
var widthChars: Int?
/// %TRUE if the label text will wrap if it gets too wide.
var wrap: Bool?
/// The horizontal alignment of the label text inside its size allocation.
///
/// Compare this to [property@Gtk.Widget:halign], which determines how the
/// labels size allocation is positioned in the space available for the label.
var xalign: Float?
/// The vertical alignment of the label text inside its size allocation.
///
/// Compare this to [property@Gtk.Widget:valign], which determines how the
/// labels size allocation is positioned in the space available for the label.
var yalign: Float?
/// Gets emitted to copy the selection to the clipboard.
///
/// The ::copy-clipboard signal is a [keybinding signal](class.SignalAction.html).
///
/// The default binding for this signal is <kbd>Ctrl</kbd>+<kbd>c</kbd>.
var copyClipboard: (() -> Void)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `Label`.
public init(label: String) {
self.label = label
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_label_new(label)?.opaque())
update(storage, modifiers: modifiers)
if let mnemonicWidgetStorage = mnemonicWidget?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["mnemonicWidget"] = [mnemonicWidgetStorage]
gtk_label_set_mnemonic_widget(storage.pointer, mnemonicWidgetStorage.pointer?.cast())
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let copyClipboard {
storage.connectSignal(name: "copy-clipboard") {
copyClipboard()
}
}
storage.modify { widget in
gtk_label_set_label(widget, label)
if let lines {
gtk_label_set_lines(widget, lines.cInt)
}
if let maxWidthChars {
gtk_label_set_max_width_chars(widget, maxWidthChars.cInt)
}
if let widget = storage.content["mnemonicWidget"]?.first {
mnemonicWidget?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let selectable {
gtk_label_set_selectable(widget, selectable.cBool)
}
if let singleLineMode {
gtk_label_set_single_line_mode(widget, singleLineMode.cBool)
}
if let useMarkup {
gtk_label_set_use_markup(widget, useMarkup.cBool)
}
if let useUnderline {
gtk_label_set_use_underline(widget, useUnderline.cBool)
}
if let widthChars {
gtk_label_set_width_chars(widget, widthChars.cInt)
}
if let wrap {
gtk_label_set_wrap(widget, wrap.cBool)
}
if let xalign {
gtk_label_set_xalign(widget, xalign)
}
if let yalign {
gtk_label_set_yalign(widget, yalign)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The contents of the label.
///
/// If the string contains Pango markup (see [func@Pango.parse_markup]),
/// you will have to set the [property@Gtk.Label:use-markup] property to
/// %TRUE in order for the label to display the markup attributes. See also
/// [method@Gtk.Label.set_markup] for a convenience function that sets both
/// this property and the [property@Gtk.Label:use-markup] property at the
/// same time.
///
/// If the string contains underlines acting as mnemonics, you will have to
/// set the [property@Gtk.Label:use-underline] property to %TRUE in order
/// for the label to display them.
public func label(_ label: String) -> Self {
var newSelf = self
newSelf.label = label
return newSelf
}
/// The number of lines to which an ellipsized, wrapping label
/// should be limited.
///
/// This property has no effect if the label is not wrapping or ellipsized.
/// Set this property to -1 if you don't want to limit the number of lines.
public func lines(_ lines: Int?) -> Self {
var newSelf = self
newSelf.lines = lines
return newSelf
}
/// The desired maximum width of the label, in characters.
///
/// If this property is set to -1, the width will be calculated automatically.
///
/// See the section on [text layout](class.Label.html#text-layout) for details of how
/// [property@Gtk.Label:width-chars] and [property@Gtk.Label:max-width-chars]
/// determine the width of ellipsized and wrapped labels.
public func maxWidthChars(_ maxWidthChars: Int?) -> Self {
var newSelf = self
newSelf.maxWidthChars = maxWidthChars
return newSelf
}
/// The mnemonic accelerator key for the label.
public func mnemonicKeyval(_ mnemonicKeyval: UInt?) -> Self {
var newSelf = self
newSelf.mnemonicKeyval = mnemonicKeyval
return newSelf
}
/// The widget to be activated when the labels mnemonic key is pressed.
public func mnemonicWidget(@ViewBuilder _ mnemonicWidget: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.mnemonicWidget = mnemonicWidget
return newSelf
}
/// Whether the label text can be selected with the mouse.
public func selectable(_ selectable: Bool? = true) -> Self {
var newSelf = self
newSelf.selectable = selectable
return newSelf
}
/// Whether the label is in single line mode.
///
/// In single line mode, the height of the label does not depend on the
/// actual text, it is always set to ascent + descent of the font. This
/// can be an advantage in situations where resizing the label because
/// of text changes would be distracting, e.g. in a statusbar.
public func singleLineMode(_ singleLineMode: Bool? = true) -> Self {
var newSelf = self
newSelf.singleLineMode = singleLineMode
return newSelf
}
/// %TRUE if the text of the label includes Pango markup.
///
/// See [func@Pango.parse_markup].
public func useMarkup(_ useMarkup: Bool? = true) -> Self {
var newSelf = self
newSelf.useMarkup = useMarkup
return newSelf
}
/// %TRUE if the text of the label indicates a mnemonic with an _
/// before the mnemonic character.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// The desired width of the label, in characters.
///
/// If this property is set to -1, the width will be calculated automatically.
///
/// See the section on [text layout](class.Label.html#text-layout) for details of how
/// [property@Gtk.Label:width-chars] and [property@Gtk.Label:max-width-chars]
/// determine the width of ellipsized and wrapped labels.
public func widthChars(_ widthChars: Int?) -> Self {
var newSelf = self
newSelf.widthChars = widthChars
return newSelf
}
/// %TRUE if the label text will wrap if it gets too wide.
public func wrap(_ wrap: Bool? = true) -> Self {
var newSelf = self
newSelf.wrap = wrap
return newSelf
}
/// The horizontal alignment of the label text inside its size allocation.
///
/// Compare this to [property@Gtk.Widget:halign], which determines how the
/// labels size allocation is positioned in the space available for the label.
public func xalign(_ xalign: Float?) -> Self {
var newSelf = self
newSelf.xalign = xalign
return newSelf
}
/// The vertical alignment of the label text inside its size allocation.
///
/// Compare this to [property@Gtk.Widget:valign], which determines how the
/// labels size allocation is positioned in the space available for the label.
public func yalign(_ yalign: Float?) -> Self {
var newSelf = self
newSelf.yalign = yalign
return newSelf
}
/// Gets emitted to copy the selection to the clipboard.
///
/// The ::copy-clipboard signal is a [keybinding signal](class.SignalAction.html).
///
/// The default binding for this signal is <kbd>Ctrl</kbd>+<kbd>c</kbd>.
public func copyClipboard(_ copyClipboard: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.copyClipboard = copyClipboard
return newSelf
}
}

View File

@ -0,0 +1,238 @@
//
// LevelBar.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// `GtkLevelBar` is a widget that can be used as a level indicator.
///
/// Typical use cases are displaying the strength of a password, or
/// showing the charge level of a battery.
///
/// ![An example GtkLevelBar](levelbar.png)
///
/// Use [method@Gtk.LevelBar.set_value] to set the current value, and
/// [method@Gtk.LevelBar.add_offset_value] to set the value offsets at which
/// the bar will be considered in a different state. GTK will add a few
/// offsets by default on the level bar: %GTK_LEVEL_BAR_OFFSET_LOW,
/// %GTK_LEVEL_BAR_OFFSET_HIGH and %GTK_LEVEL_BAR_OFFSET_FULL, with
/// values 0.25, 0.75 and 1.0 respectively.
///
/// Note that it is your responsibility to update preexisting offsets
/// when changing the minimum or maximum value. GTK will simply clamp
/// them to the new range.
///
/// ## Adding a custom offset on the bar
///
/// ```c
/// static GtkWidget *
/// create_level_bar (void)
/// {
/// GtkWidget *widget;
/// GtkLevelBar *bar;
///
/// widget = gtk_level_bar_new ();
/// bar = GTK_LEVEL_BAR (widget);
///
/// // This changes the value of the default low offset
///
/// gtk_level_bar_add_offset_value (bar,
/// GTK_LEVEL_BAR_OFFSET_LOW,
/// 0.10);
///
/// // This adds a new offset to the bar; the application will
/// // be able to change its color CSS like this:
/// //
/// // levelbar block.my-offset {
/// // background-color: magenta;
/// // border-style: solid;
/// // border-color: black;
/// // border-width: 1px;
/// // }
///
/// gtk_level_bar_add_offset_value (bar, "my-offset", 0.60);
///
/// return widget;
/// }
/// ```
///
/// The default interval of values is between zero and one, but its possible
/// to modify the interval using [method@Gtk.LevelBar.set_min_value] and
/// [method@Gtk.LevelBar.set_max_value]. The value will be always drawn in
/// proportion to the admissible interval, i.e. a value of 15 with a specified
/// interval between 10 and 20 is equivalent to a value of 0.5 with an interval
/// between 0 and 1. When %GTK_LEVEL_BAR_MODE_DISCRETE is used, the bar level
/// is rendered as a finite number of separated blocks instead of a single one.
/// The number of blocks that will be rendered is equal to the number of units
/// specified by the admissible interval.
///
/// For instance, to build a bar rendered with five blocks, its sufficient to
/// set the minimum value to 0 and the maximum value to 5 after changing the
/// indicator mode to discrete.
///
/// # GtkLevelBar as GtkBuildable
///
/// The `GtkLevelBar` implementation of the `GtkBuildable` interface supports a
/// custom `<offsets>` element, which can contain any number of `<offset>` elements,
/// each of which must have "name" and "value" attributes.
///
/// # CSS nodes
///
/// ```
/// levelbar[.discrete]
/// trough
/// block.filled.level-name
///
/// block.empty
///
/// ```
///
/// `GtkLevelBar` has a main CSS node with name levelbar and one of the style
/// classes .discrete or .continuous and a subnode with name trough. Below the
/// trough node are a number of nodes with name block and style class .filled
/// or .empty. In continuous mode, there is exactly one node of each, in discrete
/// mode, the number of filled and unfilled nodes corresponds to blocks that are
/// drawn. The block.filled nodes also get a style class .level-name corresponding
/// to the level for the current value.
///
/// In horizontal orientation, the nodes are always arranged from left to right,
/// regardless of text direction.
///
/// # Accessibility
///
/// `GtkLevelBar` uses the %GTK_ACCESSIBLE_ROLE_METER role.
public struct LevelBar: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether the `GtkLeveBar` is inverted.
///
/// Level bars normally grow from top to bottom or left to right.
/// Inverted level bars grow in the opposite direction.
var inverted: Bool?
/// Determines the maximum value of the interval that can be displayed by the bar.
var maxValue: Double?
/// Determines the minimum value of the interval that can be displayed by the bar.
var minValue: Double?
/// Determines the currently filled value of the level bar.
var value: Double?
/// Emitted when an offset specified on the bar changes value.
///
/// This typically is the result of a [method@Gtk.LevelBar.add_offset_value]
/// call.
///
/// The signal supports detailed connections; you can connect to the
/// detailed signal "changed::x" in order to only receive callbacks when
/// the value of offset "x" changes.
var offsetChanged: (() -> Void)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `LevelBar`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_level_bar_new()?.opaque())
update(storage, modifiers: modifiers)
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let offsetChanged {
storage.connectSignal(name: "offset-changed") {
offsetChanged()
}
}
storage.modify { widget in
if let inverted {
gtk_level_bar_set_inverted(widget, inverted.cBool)
}
if let maxValue {
gtk_level_bar_set_max_value(widget, maxValue)
}
if let minValue {
gtk_level_bar_set_min_value(widget, minValue)
}
if let value {
gtk_level_bar_set_value(widget, value)
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether the `GtkLeveBar` is inverted.
///
/// Level bars normally grow from top to bottom or left to right.
/// Inverted level bars grow in the opposite direction.
public func inverted(_ inverted: Bool? = true) -> Self {
var newSelf = self
newSelf.inverted = inverted
return newSelf
}
/// Determines the maximum value of the interval that can be displayed by the bar.
public func maxValue(_ maxValue: Double?) -> Self {
var newSelf = self
newSelf.maxValue = maxValue
return newSelf
}
/// Determines the minimum value of the interval that can be displayed by the bar.
public func minValue(_ minValue: Double?) -> Self {
var newSelf = self
newSelf.minValue = minValue
return newSelf
}
/// Determines the currently filled value of the level bar.
public func value(_ value: Double?) -> Self {
var newSelf = self
newSelf.value = value
return newSelf
}
/// Emitted when an offset specified on the bar changes value.
///
/// This typically is the result of a [method@Gtk.LevelBar.add_offset_value]
/// call.
///
/// The signal supports detailed connections; you can connect to the
/// detailed signal "changed::x" in order to only receive callbacks when
/// the value of offset "x" changes.
public func offsetChanged(_ offsetChanged: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.offsetChanged = offsetChanged
return newSelf
}
}

View File

@ -0,0 +1,246 @@
//
// LinkButton.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A `GtkLinkButton` is a button with a hyperlink.
///
/// ![An example GtkLinkButton](link-button.png)
///
/// It is useful to show quick links to resources.
///
/// A link button is created by calling either [ctor@Gtk.LinkButton.new] or
/// [ctor@Gtk.LinkButton.new_with_label]. If using the former, the URI you
/// pass to the constructor is used as a label for the widget.
///
/// The URI bound to a `GtkLinkButton` can be set specifically using
/// [method@Gtk.LinkButton.set_uri].
///
/// By default, `GtkLinkButton` calls [method@Gtk.FileLauncher.launch] when the button
/// is clicked. This behaviour can be overridden by connecting to the
/// [signal@Gtk.LinkButton::activate-link] signal and returning %TRUE from
/// the signal handler.
///
/// # CSS nodes
///
/// `GtkLinkButton` has a single CSS node with name button. To differentiate
/// it from a plain `GtkButton`, it gets the .link style class.
///
/// # Accessibility
///
/// `GtkLinkButton` uses the %GTK_ACCESSIBLE_ROLE_LINK role.
public struct LinkButton: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The URI bound to this button.
var uri: String
/// The 'visited' state of this button.
///
/// A visited link is drawn in a different color.
var visited: Bool?
/// Whether the size of the button can be made smaller than the natural
/// size of its contents.
///
/// For text buttons, setting this property will allow ellipsizing the label.
///
/// If the contents of a button are an icon or a custom widget, setting this
/// property has no effect.
var canShrink: Bool?
/// The child widget.
var child: (() -> Body)?
/// Whether the button has a frame.
var hasFrame: Bool?
/// The name of the icon used to automatically populate the button.
var iconName: String?
/// Text of the label inside the button, if the button contains a label widget.
var label: String?
/// If set, an underline in the text indicates that the following character is
/// to be used as mnemonic.
var useUnderline: Bool?
/// Emitted to animate press then release.
///
/// This is an action signal. Applications should never connect
/// to this signal, but use the [signal@Gtk.Button::clicked] signal.
///
/// The default bindings for this signal are all forms of the
/// <kbd></kbd> and <kbd>Enter</kbd> keys.
var activate: (() -> Void)?
/// Emitted when the button has been activated (pressed and released).
var clicked: (() -> Void)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `LinkButton`.
public init(uri: String) {
self.uri = uri
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_link_button_new(uri)?.opaque())
update(storage, modifiers: modifiers)
if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["child"] = [childStorage]
gtk_button_set_child(storage.pointer?.cast(), childStorage.pointer?.cast())
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let activate {
storage.connectSignal(name: "activate") {
activate()
}
}
if let clicked {
storage.connectSignal(name: "clicked") {
clicked()
}
}
storage.modify { widget in
gtk_link_button_set_uri(widget, uri)
if let visited {
gtk_link_button_set_visited(widget, visited.cBool)
}
if let canShrink {
gtk_button_set_can_shrink(widget?.cast(), canShrink.cBool)
}
if let widget = storage.content["child"]?.first {
child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let hasFrame {
gtk_button_set_has_frame(widget?.cast(), hasFrame.cBool)
}
if let iconName {
gtk_button_set_icon_name(widget?.cast(), iconName)
}
if let label, storage.content["child"] == nil {
gtk_button_set_label(widget?.cast(), label)
}
if let useUnderline {
gtk_button_set_use_underline(widget?.cast(), useUnderline.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The URI bound to this button.
public func uri(_ uri: String) -> Self {
var newSelf = self
newSelf.uri = uri
return newSelf
}
/// The 'visited' state of this button.
///
/// A visited link is drawn in a different color.
public func visited(_ visited: Bool? = true) -> Self {
var newSelf = self
newSelf.visited = visited
return newSelf
}
/// Whether the size of the button can be made smaller than the natural
/// size of its contents.
///
/// For text buttons, setting this property will allow ellipsizing the label.
///
/// If the contents of a button are an icon or a custom widget, setting this
/// property has no effect.
public func canShrink(_ canShrink: Bool? = true) -> Self {
var newSelf = self
newSelf.canShrink = canShrink
return newSelf
}
/// The child widget.
public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.child = child
return newSelf
}
/// Whether the button has a frame.
public func hasFrame(_ hasFrame: Bool? = true) -> Self {
var newSelf = self
newSelf.hasFrame = hasFrame
return newSelf
}
/// The name of the icon used to automatically populate the button.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// Text of the label inside the button, if the button contains a label widget.
public func label(_ label: String?) -> Self {
var newSelf = self
newSelf.label = label
return newSelf
}
/// If set, an underline in the text indicates that the following character is
/// to be used as mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// Emitted to animate press then release.
///
/// This is an action signal. Applications should never connect
/// to this signal, but use the [signal@Gtk.Button::clicked] signal.
///
/// The default bindings for this signal are all forms of the
/// <kbd></kbd> and <kbd>Enter</kbd> keys.
public func activate(_ activate: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.activate = activate
return newSelf
}
/// Emitted when the button has been activated (pressed and released).
public func clicked(_ clicked: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.clicked = clicked
return newSelf
}
}

View File

@ -0,0 +1,319 @@
//
// ListBox.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// `GtkListBox` is a vertical list.
///
/// A `GtkListBox` only contains `GtkListBoxRow` children. These rows can
/// by dynamically sorted and filtered, and headers can be added dynamically
/// depending on the row content. It also allows keyboard and mouse navigation
/// and selection like a typical list.
///
/// Using `GtkListBox` is often an alternative to `GtkTreeView`, especially
/// when the list contents has a more complicated layout than what is allowed
/// by a `GtkCellRenderer`, or when the contents is interactive (i.e. has a
/// button in it).
///
/// Although a `GtkListBox` must have only `GtkListBoxRow` children, you can
/// add any kind of widget to it via [method@Gtk.ListBox.prepend],
/// [method@Gtk.ListBox.append] and [method@Gtk.ListBox.insert] and a
/// `GtkListBoxRow` widget will automatically be inserted between the list
/// and the widget.
///
/// `GtkListBoxRows` can be marked as activatable or selectable. If a row is
/// activatable, [signal@Gtk.ListBox::row-activated] will be emitted for it when
/// the user tries to activate it. If it is selectable, the row will be marked
/// as selected when the user tries to select it.
///
/// # GtkListBox as GtkBuildable
///
/// The `GtkListBox` implementation of the `GtkBuildable` interface supports
/// setting a child as the placeholder by specifying placeholder as the type
/// attribute of a `<child>` element. See [method@Gtk.ListBox.set_placeholder]
/// for info.
///
/// # CSS nodes
///
/// |[<!-- language="plain" -->
/// list[.separators][.rich-list][.navigation-sidebar][.boxed-list]
/// row[.activatable]
/// ]|
///
/// `GtkListBox` uses a single CSS node named list. It may carry the .separators
/// style class, when the [property@Gtk.ListBox:show-separators] property is set.
/// Each `GtkListBoxRow` uses a single CSS node named row. The row nodes get the
/// .activatable style class added when appropriate.
///
/// It may also carry the .boxed-list style class. In this case, the list will be
/// automatically surrounded by a frame and have separators.
///
/// The main list node may also carry style classes to select
/// the style of [list presentation](section-list-widget.html#list-styles):
/// .rich-list, .navigation-sidebar or .data-table.
///
/// # Accessibility
///
/// `GtkListBox` uses the %GTK_ACCESSIBLE_ROLE_LIST role and `GtkListBoxRow` uses
/// the %GTK_ACCESSIBLE_ROLE_LIST_ITEM role.
public struct ListBox<Element>: Widget where Element: Identifiable {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether to accept unpaired release events.
var acceptUnpairedRelease: Bool?
/// Determines whether children can be activated with a single
/// click, or require a double-click.
var activateOnSingleClick: Bool?
/// Whether to show separators between rows.
var showSeparators: Bool?
/// activateCursorRow
var activateCursorRow: (() -> Void)?
/// moveCursor
var moveCursor: (() -> Void)?
/// Emitted when a row has been activated by the user.
var rowActivated: (() -> Void)?
/// Emitted when a new row is selected, or (with a %NULL @row)
/// when the selection is cleared.
///
/// When the @box is using %GTK_SELECTION_MULTIPLE, this signal will not
/// give you the full picture of selection changes, and you should use
/// the [signal@Gtk.ListBox::selected-rows-changed] signal instead.
var rowSelected: (() -> Void)?
/// Emitted to select all children of the box, if the selection
/// mode permits it.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The default binding for this signal is <kbd>Ctrl</kbd>-<kbd>a</kbd>.
var selectAll: (() -> Void)?
/// Emitted when the set of selected rows changes.
var selectedRowsChanged: (() -> Void)?
/// toggleCursorRow
var toggleCursorRow: (() -> Void)?
/// Emitted to unselect all children of the box, if the selection
/// mode permits it.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The default binding for this signal is
/// <kbd>Ctrl</kbd>-<kbd>Shift</kbd>-<kbd>a</kbd>.
var unselectAll: (() -> Void)?
/// The dynamic widget elements.
var elements: [Element]
/// The dynamic widget content.
var content: (Element) -> Body
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `ListBox`.
public init(_ elements: [Element], @ViewBuilder content: @escaping (Element) -> Body) {
self.elements = elements
self.content = content
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_list_box_new()?.opaque())
update(storage, modifiers: modifiers)
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let activateCursorRow {
storage.connectSignal(name: "activate-cursor-row") {
activateCursorRow()
}
}
if let moveCursor {
storage.connectSignal(name: "move-cursor") {
moveCursor()
}
}
if let rowActivated {
storage.connectSignal(name: "row-activated") {
rowActivated()
}
}
if let rowSelected {
storage.connectSignal(name: "row-selected") {
rowSelected()
}
}
if let selectAll {
storage.connectSignal(name: "select-all") {
selectAll()
}
}
if let selectedRowsChanged {
storage.connectSignal(name: "selected-rows-changed") {
selectedRowsChanged()
}
}
if let toggleCursorRow {
storage.connectSignal(name: "toggle-cursor-row") {
toggleCursorRow()
}
}
if let unselectAll {
storage.connectSignal(name: "unselect-all") {
unselectAll()
}
}
storage.modify { widget in
if let activateOnSingleClick {
gtk_list_box_set_activate_on_single_click(widget, activateOnSingleClick.cBool)
}
if let showSeparators {
gtk_list_box_set_show_separators(widget, showSeparators.cBool)
}
var contentStorage: [ViewStorage] = storage.content[.mainContent] ?? []
let old = storage.fields["element"] as? [Element] ?? []
old.identifiableTransform(
to: elements,
functions: .init { index, element in
let child = content(element).widget(modifiers: modifiers).container(modifiers: modifiers)
gtk_list_box_remove(widget, gtk_list_box_get_row_at_index(widget, index.cInt)?.cast())
gtk_list_box_insert(widget, child.pointer?.cast(), index.cInt)
contentStorage.remove(at: index)
contentStorage.insert(child, at: index)
} delete: { index in
gtk_list_box_remove(widget, gtk_list_box_get_row_at_index(widget, index.cInt)?.cast())
contentStorage.remove(at: index)
} insert: { index, element in
let child = content(element).widget(modifiers: modifiers).container(modifiers: modifiers)
gtk_list_box_insert(widget, child.pointer?.cast(), index.cInt)
contentStorage.insert(child, at: index)
}
)
storage.fields["element"] = elements
storage.content[.mainContent] = contentStorage
for (index, element) in elements.enumerated() {
content(element).widget(modifiers: modifiers).update(contentStorage[index], modifiers: modifiers)
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether to accept unpaired release events.
public func acceptUnpairedRelease(_ acceptUnpairedRelease: Bool? = true) -> Self {
var newSelf = self
newSelf.acceptUnpairedRelease = acceptUnpairedRelease
return newSelf
}
/// Determines whether children can be activated with a single
/// click, or require a double-click.
public func activateOnSingleClick(_ activateOnSingleClick: Bool? = true) -> Self {
var newSelf = self
newSelf.activateOnSingleClick = activateOnSingleClick
return newSelf
}
/// Whether to show separators between rows.
public func showSeparators(_ showSeparators: Bool? = true) -> Self {
var newSelf = self
newSelf.showSeparators = showSeparators
return newSelf
}
/// activateCursorRow
public func activateCursorRow(_ activateCursorRow: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.activateCursorRow = activateCursorRow
return newSelf
}
/// moveCursor
public func moveCursor(_ moveCursor: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.moveCursor = moveCursor
return newSelf
}
/// Emitted when a row has been activated by the user.
public func rowActivated(_ rowActivated: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.rowActivated = rowActivated
return newSelf
}
/// Emitted when a new row is selected, or (with a %NULL @row)
/// when the selection is cleared.
///
/// When the @box is using %GTK_SELECTION_MULTIPLE, this signal will not
/// give you the full picture of selection changes, and you should use
/// the [signal@Gtk.ListBox::selected-rows-changed] signal instead.
public func rowSelected(_ rowSelected: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.rowSelected = rowSelected
return newSelf
}
/// Emitted to select all children of the box, if the selection
/// mode permits it.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The default binding for this signal is <kbd>Ctrl</kbd>-<kbd>a</kbd>.
public func selectAll(_ selectAll: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.selectAll = selectAll
return newSelf
}
/// Emitted when the set of selected rows changes.
public func selectedRowsChanged(_ selectedRowsChanged: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.selectedRowsChanged = selectedRowsChanged
return newSelf
}
/// toggleCursorRow
public func toggleCursorRow(_ toggleCursorRow: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.toggleCursorRow = toggleCursorRow
return newSelf
}
/// Emitted to unselect all children of the box, if the selection
/// mode permits it.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The default binding for this signal is
/// <kbd>Ctrl</kbd>-<kbd>Shift</kbd>-<kbd>a</kbd>.
public func unselectAll(_ unselectAll: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.unselectAll = unselectAll
return newSelf
}
}

View File

@ -0,0 +1,289 @@
//
// Menu.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// The `GtkMenuButton` widget is used to display a popup when clicked.
///
/// ![An example GtkMenuButton](menu-button.png)
///
/// This popup can be provided either as a `GtkPopover` or as an abstract
/// `GMenuModel`.
///
/// The `GtkMenuButton` widget can show either an icon (set with the
/// [property@Gtk.MenuButton:icon-name] property) or a label (set with the
/// [property@Gtk.MenuButton:label] property). If neither is explicitly set,
/// a [class@Gtk.Image] is automatically created, using an arrow image oriented
/// according to [property@Gtk.MenuButton:direction] or the generic
/// open-menu-symbolic icon if the direction is not set.
///
/// The positioning of the popup is determined by the
/// [property@Gtk.MenuButton:direction] property of the menu button.
///
/// For menus, the [property@Gtk.Widget:halign] and [property@Gtk.Widget:valign]
/// properties of the menu are also taken into account. For example, when the
/// direction is %GTK_ARROW_DOWN and the horizontal alignment is %GTK_ALIGN_START,
/// the menu will be positioned below the button, with the starting edge
/// (depending on the text direction) of the menu aligned with the starting
/// edge of the button. If there is not enough space below the button, the
/// menu is popped up above the button instead. If the alignment would move
/// part of the menu offscreen, it is pushed in.
///
/// | | start | center | end |
/// | - | --- | --- | --- |
/// | **down** | ![](down-start.png) | ![](down-center.png) | ![](down-end.png) |
/// | **up** | ![](up-start.png) | ![](up-center.png) | ![](up-end.png) |
/// | **left** | ![](left-start.png) | ![](left-center.png) | ![](left-end.png) |
/// | **right** | ![](right-start.png) | ![](right-center.png) | ![](right-end.png) |
///
/// # CSS nodes
///
/// ```
/// menubutton
/// button.toggle
/// <content> [arrow]
/// ```
///
/// `GtkMenuButton` has a single CSS node with name `menubutton`
/// which contains a `button` node with a `.toggle` style class.
///
/// If the button contains an icon, it will have the `.image-button` style class,
/// if it contains text, it will have `.text-button` style class. If an arrow is
/// visible in addition to an icon, text or a custom child, it will also have
/// `.arrow-button` style class.
///
/// Inside the toggle button content, there is an `arrow` node for
/// the indicator, which will carry one of the `.none`, `.up`, `.down`,
/// `.left` or `.right` style classes to indicate the direction that
/// the menu will appear in. The CSS is expected to provide a suitable
/// image for each of these cases using the `-gtk-icon-source` property.
///
/// Optionally, the `menubutton` node can carry the `.circular` style class
/// to request a round appearance.
///
/// # Accessibility
///
/// `GtkMenuButton` uses the %GTK_ACCESSIBLE_ROLE_BUTTON role.
public struct Menu: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether the menu button is active.
var active: Binding<Bool>?
/// Whether to show a dropdown arrow even when using an icon or a custom child.
var alwaysShowArrow: Bool?
/// Whether the size of the button can be made smaller than the natural
/// size of its contents.
var canShrink: Bool?
/// The child widget.
var child: (() -> Body)?
/// Whether the button has a frame.
var hasFrame: Bool?
/// The name of the icon used to automatically populate the button.
var iconName: String?
/// The label for the button.
var label: String?
/// The `GMenuModel` from which the popup will be created.
///
/// See [method@Gtk.MenuButton.set_menu_model] for the interaction
/// with the [property@Gtk.MenuButton:popover] property.
var menuModel: (() -> MenuContent)?
/// Whether the menu button acts as a primary menu.
///
/// Primary menus can be opened using the <kbd>F10</kbd> key
var primary: Bool?
/// If set an underscore in the text indicates a mnemonic.
var useUnderline: Bool?
/// Emitted to when the menu button is activated.
///
/// The `::activate` signal on `GtkMenuButton` is an action signal and
/// emitting it causes the button to pop up its menu.
var activate: (() -> Void)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `Menu`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_menu_button_new()?.opaque())
update(storage, modifiers: modifiers)
if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["child"] = [childStorage]
gtk_menu_button_set_child(storage.pointer, childStorage.pointer?.cast())
}
if let declarative = menuModel?(), let app {
let menu = g_menu_new()
gtk_menu_button_set_menu_model(storage.pointer, menu?.cast())
for item in declarative {
item.addMenuItems(menu: menu, app: app, window: window)
}
}
storage.notify(name: "active") {
active?.wrappedValue = gtk_menu_button_get_active(storage.pointer) != 0
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let activate {
storage.connectSignal(name: "activate") {
activate()
}
}
storage.modify { widget in
if let active {
gtk_menu_button_set_active(widget, active.wrappedValue.cBool)
}
if let alwaysShowArrow {
gtk_menu_button_set_always_show_arrow(widget, alwaysShowArrow.cBool)
}
if let canShrink {
gtk_menu_button_set_can_shrink(widget, canShrink.cBool)
}
if let widget = storage.content["child"]?.first {
child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let hasFrame {
gtk_menu_button_set_has_frame(widget, hasFrame.cBool)
}
if let iconName {
gtk_menu_button_set_icon_name(widget, iconName)
}
if let label, storage.content["child"] == nil {
gtk_menu_button_set_label(widget, label)
}
if let primary {
gtk_menu_button_set_primary(widget, primary.cBool)
}
if let useUnderline {
gtk_menu_button_set_use_underline(widget, useUnderline.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether the menu button is active.
public func active(_ active: Binding<Bool>?) -> Self {
var newSelf = self
newSelf.active = active
return newSelf
}
/// Whether to show a dropdown arrow even when using an icon or a custom child.
public func alwaysShowArrow(_ alwaysShowArrow: Bool? = true) -> Self {
var newSelf = self
newSelf.alwaysShowArrow = alwaysShowArrow
return newSelf
}
/// Whether the size of the button can be made smaller than the natural
/// size of its contents.
public func canShrink(_ canShrink: Bool? = true) -> Self {
var newSelf = self
newSelf.canShrink = canShrink
return newSelf
}
/// The child widget.
public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.child = child
return newSelf
}
/// Whether the button has a frame.
public func hasFrame(_ hasFrame: Bool? = true) -> Self {
var newSelf = self
newSelf.hasFrame = hasFrame
return newSelf
}
/// The name of the icon used to automatically populate the button.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// The label for the button.
public func label(_ label: String?) -> Self {
var newSelf = self
newSelf.label = label
return newSelf
}
/// The `GMenuModel` from which the popup will be created.
///
/// See [method@Gtk.MenuButton.set_menu_model] for the interaction
/// with the [property@Gtk.MenuButton:popover] property.
public func menuModel(app: GTUIApp, window: GTUIApplicationWindow? = nil, @MenuBuilder _ menuModel: @escaping (() -> MenuContent)) -> Self {
var newSelf = self
newSelf.menuModel = menuModel
newSelf.app = app; newSelf.window = window
return newSelf
}
/// Whether the menu button acts as a primary menu.
///
/// Primary menus can be opened using the <kbd>F10</kbd> key
public func primary(_ primary: Bool? = true) -> Self {
var newSelf = self
newSelf.primary = primary
return newSelf
}
/// If set an underscore in the text indicates a mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// Emitted to when the menu button is activated.
///
/// The `::activate` signal on `GtkMenuButton` is an action signal and
/// emitting it causes the button to pop up its menu.
public func activate(_ activate: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.activate = activate
return newSelf
}
}

View File

@ -0,0 +1,167 @@
//
// Overlay.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// `GtkOverlay` is a container which contains a single main child, on top
/// of which it can place overlay widgets.
///
/// ![An example GtkOverlay](overlay.png)
///
/// The position of each overlay widget is determined by its
/// [property@Gtk.Widget:halign] and [property@Gtk.Widget:valign]
/// properties. E.g. a widget with both alignments set to %GTK_ALIGN_START
/// will be placed at the top left corner of the `GtkOverlay` container,
/// whereas an overlay with halign set to %GTK_ALIGN_CENTER and valign set
/// to %GTK_ALIGN_END will be placed a the bottom edge of the `GtkOverlay`,
/// horizontally centered. The position can be adjusted by setting the margin
/// properties of the child to non-zero values.
///
/// More complicated placement of overlays is possible by connecting
/// to the [signal@Gtk.Overlay::get-child-position] signal.
///
/// An overlays minimum and natural sizes are those of its main child.
/// The sizes of overlay children are not considered when measuring these
/// preferred sizes.
///
/// # GtkOverlay as GtkBuildable
///
/// The `GtkOverlay` implementation of the `GtkBuildable` interface
/// supports placing a child as an overlay by specifying overlay as
/// the type attribute of a `<child>` element.
///
/// # CSS nodes
///
/// `GtkOverlay` has a single CSS node with the name overlay. Overlay children
/// whose alignments cause them to be positioned at an edge get the style classes
/// .left, .right, .top, and/or .bottom according to their position.
public struct Overlay: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The main child widget.
var child: (() -> Body)?
/// Emitted to determine the position and size of any overlay
/// child widgets.
///
/// A handler for this signal should fill @allocation with
/// the desired position and size for @widget, relative to
/// the 'main' child of @overlay.
///
/// The default handler for this signal uses the @widget's
/// halign and valign properties to determine the position
/// and gives the widget its natural size (except that an
/// alignment of %GTK_ALIGN_FILL will cause the overlay to
/// be full-width/height). If the main child is a
/// `GtkScrolledWindow`, the overlays are placed relative
/// to its contents.
var getChildPosition: (() -> Void)?
/// The body for the widget "overlay".
var overlay: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `Overlay`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_overlay_new()?.opaque())
update(storage, modifiers: modifiers)
if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["child"] = [childStorage]
gtk_overlay_set_child(storage.pointer, childStorage.pointer?.cast())
}
var overlayStorage: [ViewStorage] = []
for view in overlay() {
overlayStorage.append(view.storage(modifiers: modifiers))
gtk_overlay_add_overlay(storage.pointer, overlayStorage.last?.pointer?.cast())
}
storage.content["overlay"] = overlayStorage
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let getChildPosition {
storage.connectSignal(name: "get-child-position") {
getChildPosition()
}
}
storage.modify { widget in
if let widget = storage.content["child"]?.first {
child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let overlayStorage = storage.content["overlay"] {
for (index, view) in overlay().enumerated() {
if let storage = overlayStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
}
for function in updateFunctions {
function(storage)
}
}
/// The main child widget.
public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.child = child
return newSelf
}
/// Emitted to determine the position and size of any overlay
/// child widgets.
///
/// A handler for this signal should fill @allocation with
/// the desired position and size for @widget, relative to
/// the 'main' child of @overlay.
///
/// The default handler for this signal uses the @widget's
/// halign and valign properties to determine the position
/// and gives the widget its natural size (except that an
/// alignment of %GTK_ALIGN_FILL will cause the overlay to
/// be full-width/height). If the main child is a
/// `GtkScrolledWindow`, the overlays are placed relative
/// to its contents.
public func getChildPosition(_ getChildPosition: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.getChildPosition = getChildPosition
return newSelf
}
/// Set the body for "overlay".
/// - Parameter body: The body.
/// - Returns: The widget.
public func overlay(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.overlay = body
return newSelf
}
}

View File

@ -0,0 +1,361 @@
//
// OverlaySplitView.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A widget presenting sidebar and content side by side or as an overlay.
///
/// <picture><source srcset="overlay-split-view-dark.png" media="(prefers-color-scheme: dark)"><img src="overlay-split-view.png" alt="overlay-split-view"></picture><picture><source srcset="overlay-split-view-collapsed-dark.png" media="(prefers-color-scheme: dark)"><img src="overlay-split-view-collapsed.png" alt="overlay-split-view-collapsed"></picture>
///
/// `AdwOverlaySplitView` has two children: sidebar and content, and displays
/// them side by side.
///
/// When [property@OverlaySplitView:collapsed] is set to `TRUE`, the sidebar is
/// instead shown as an overlay above the content widget.
///
/// The sidebar can be hidden or shown using the
/// [property@OverlaySplitView:show-sidebar] property.
///
/// Sidebar can be displayed before or after the content, this can be controlled
/// with the [property@OverlaySplitView:sidebar-position] property.
///
/// Collapsing the split view automatically hides the sidebar widget, and
/// uncollapsing it shows the sidebar. If this behavior is not desired, the
/// [property@OverlaySplitView:pin-sidebar] property can be used to override it.
///
/// `AdwOverlaySplitView` supports an edge swipe gesture for showing the sidebar,
/// and a swipe from the sidebar for hiding it. Gestures are only supported on
/// touchscreen, but not touchpad. Gestures can be controlled with the
/// [property@OverlaySplitView:enable-show-gesture] and
/// [property@OverlaySplitView:enable-hide-gesture] properties.
///
/// See also [class@NavigationSplitView].
///
/// `AdwOverlaySplitView` is typically used together with an [class@Breakpoint]
/// setting the `collapsed` property to `TRUE` on small widths, as follows:
///
/// ```xml
/// <object class="AdwWindow"><property name="width-request">360</property><property name="height-request">200</property><property name="default-width">800</property><property name="default-height">800</property><child><object class="AdwBreakpoint"><condition>max-width: 400sp</condition><setter object="split_view" property="collapsed">True</setter></object></child><property name="content"><object class="AdwOverlaySplitView" id="split_view"><property name="sidebar"><!-- ... --></property><property name="content"><!-- ... --></property></object></property></object>
/// ```
///
/// `AdwOverlaySplitView` is often used for implementing the
/// [utility pane](https://developer.gnome.org/hig/patterns/containers/utility-panes.html)
/// pattern.
///
/// ## Sizing
///
/// When not collapsed, `AdwOverlaySplitView` changes the sidebar width
/// depending on its own width.
///
/// If possible, it tries to allocate a fraction of the total width, controlled
/// with the [property@OverlaySplitView:sidebar-width-fraction] property.
///
/// The sidebar also has minimum and maximum sizes, controlled with the
/// [property@OverlaySplitView:min-sidebar-width] and
/// [property@OverlaySplitView:max-sidebar-width] properties.
///
/// The minimum and maximum sizes are using the length unit specified with the
/// [property@OverlaySplitView:sidebar-width-unit].
///
/// By default, sidebar is using 25% of the total width, with 180sp as the
/// minimum size and 280sp as the maximum size.
///
/// When collapsed, the preferred width fraction is ignored and the sidebar uses
/// [property@OverlaySplitView:max-sidebar-width] when possible.
///
/// ## Header Bar Integration
///
/// When used inside `AdwOverlaySplitView`, [class@HeaderBar] will automatically
/// hide the window buttons in the middle.
///
/// ## `AdwOverlaySplitView` as `GtkBuildable`
///
/// The `AdwOverlaySplitView` implementation of the [iface@Gtk.Buildable]
/// interface supports setting the sidebar widget by specifying sidebar as the
/// type attribute of a `<child>` element, Specifying content child type or
/// omitting it results in setting the content widget.
///
/// ## CSS nodes
///
/// `AdwOverlaySplitView` has a single CSS node with the name
/// `overlay-split-view`.
///
/// It contains two nodes with the name `widget`, containing the sidebar and
/// content children.
///
/// When not collapsed, they have the `.sidebar-view` and `.content-view` style
/// classes respectively.
///
/// ```
/// overlay-split-view
/// widget.sidebar-pane
/// [sidebar child]
/// widget.content-pane
/// [content child]
/// ```
///
/// When collapsed, the one containing the sidebar child has the `.background`
/// style class and the other one has no style classes.
///
/// ```
/// overlay-split-view
/// widget.background
/// [sidebar child]
/// widget
/// [content child]
/// ```
///
/// ## Accessibility
///
/// `AdwOverlaySplitView` uses the `GTK_ACCESSIBLE_ROLE_GROUP` role.
public struct OverlaySplitView: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether the split view is collapsed.
///
/// When collapsed, the sidebar widget is presented as an overlay above the
/// content widget, otherwise they are displayed side by side.
var collapsed: Bool?
/// The content widget.
var content: (() -> Body)?
/// Whether the sidebar can be closed with a swipe gesture.
///
/// Only touchscreen swipes are supported.
var enableHideGesture: Bool?
/// Whether the sidebar can be opened with an edge swipe gesture.
///
/// Only touchscreen swipes are supported.
var enableShowGesture: Bool?
/// The maximum sidebar width.
///
/// Maximum width is affected by
/// [property@OverlaySplitView:sidebar-width-unit].
///
/// The sidebar widget can still be allocated with larger width if its own
/// minimum width exceeds it.
var maxSidebarWidth: Double?
/// The minimum sidebar width.
///
/// Minimum width is affected by
/// [property@OverlaySplitView:sidebar-width-unit].
///
/// The sidebar widget can still be allocated with larger width if its own
/// minimum width exceeds it.
var minSidebarWidth: Double?
/// Whether the sidebar widget is pinned.
///
/// By default, collapsing @self automatically hides the sidebar widget, and
/// uncollapsing it shows the sidebar. If set to `TRUE`, sidebar visibility
/// never changes on its own.
var pinSidebar: Bool?
/// Whether the sidebar widget is shown.
var showSidebar: Binding<Bool>?
/// The sidebar widget.
var sidebar: (() -> Body)?
/// The preferred sidebar width as a fraction of the total width.
///
/// The preferred width is additionally limited by
/// [property@OverlaySplitView:min-sidebar-width] and
/// [property@OverlaySplitView:max-sidebar-width].
///
/// The sidebar widget can be allocated with larger width if its own minimum
/// width exceeds the preferred width.
var sidebarWidthFraction: Double?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `OverlaySplitView`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_overlay_split_view_new()?.opaque())
update(storage, modifiers: modifiers)
if let contentStorage = content?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["content"] = [contentStorage]
adw_overlay_split_view_set_content(storage.pointer, contentStorage.pointer?.cast())
}
if let sidebarStorage = sidebar?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["sidebar"] = [sidebarStorage]
adw_overlay_split_view_set_sidebar(storage.pointer, sidebarStorage.pointer?.cast())
}
storage.notify(name: "show-sidebar") {
showSidebar?.wrappedValue = adw_overlay_split_view_get_show_sidebar(storage.pointer) != 0
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let collapsed {
adw_overlay_split_view_set_collapsed(widget, collapsed.cBool)
}
if let widget = storage.content["content"]?.first {
content?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let enableHideGesture {
adw_overlay_split_view_set_enable_hide_gesture(widget, enableHideGesture.cBool)
}
if let enableShowGesture {
adw_overlay_split_view_set_enable_show_gesture(widget, enableShowGesture.cBool)
}
if let maxSidebarWidth {
adw_overlay_split_view_set_max_sidebar_width(widget, maxSidebarWidth)
}
if let minSidebarWidth {
adw_overlay_split_view_set_min_sidebar_width(widget, minSidebarWidth)
}
if let pinSidebar {
adw_overlay_split_view_set_pin_sidebar(widget, pinSidebar.cBool)
}
if let showSidebar {
adw_overlay_split_view_set_show_sidebar(widget, showSidebar.wrappedValue.cBool)
}
if let widget = storage.content["sidebar"]?.first {
sidebar?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let sidebarWidthFraction {
adw_overlay_split_view_set_sidebar_width_fraction(widget, sidebarWidthFraction)
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether the split view is collapsed.
///
/// When collapsed, the sidebar widget is presented as an overlay above the
/// content widget, otherwise they are displayed side by side.
public func collapsed(_ collapsed: Bool? = true) -> Self {
var newSelf = self
newSelf.collapsed = collapsed
return newSelf
}
/// The content widget.
public func content(@ViewBuilder _ content: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.content = content
return newSelf
}
/// Whether the sidebar can be closed with a swipe gesture.
///
/// Only touchscreen swipes are supported.
public func enableHideGesture(_ enableHideGesture: Bool? = true) -> Self {
var newSelf = self
newSelf.enableHideGesture = enableHideGesture
return newSelf
}
/// Whether the sidebar can be opened with an edge swipe gesture.
///
/// Only touchscreen swipes are supported.
public func enableShowGesture(_ enableShowGesture: Bool? = true) -> Self {
var newSelf = self
newSelf.enableShowGesture = enableShowGesture
return newSelf
}
/// The maximum sidebar width.
///
/// Maximum width is affected by
/// [property@OverlaySplitView:sidebar-width-unit].
///
/// The sidebar widget can still be allocated with larger width if its own
/// minimum width exceeds it.
public func maxSidebarWidth(_ maxSidebarWidth: Double?) -> Self {
var newSelf = self
newSelf.maxSidebarWidth = maxSidebarWidth
return newSelf
}
/// The minimum sidebar width.
///
/// Minimum width is affected by
/// [property@OverlaySplitView:sidebar-width-unit].
///
/// The sidebar widget can still be allocated with larger width if its own
/// minimum width exceeds it.
public func minSidebarWidth(_ minSidebarWidth: Double?) -> Self {
var newSelf = self
newSelf.minSidebarWidth = minSidebarWidth
return newSelf
}
/// Whether the sidebar widget is pinned.
///
/// By default, collapsing @self automatically hides the sidebar widget, and
/// uncollapsing it shows the sidebar. If set to `TRUE`, sidebar visibility
/// never changes on its own.
public func pinSidebar(_ pinSidebar: Bool? = true) -> Self {
var newSelf = self
newSelf.pinSidebar = pinSidebar
return newSelf
}
/// Whether the sidebar widget is shown.
public func showSidebar(_ showSidebar: Binding<Bool>?) -> Self {
var newSelf = self
newSelf.showSidebar = showSidebar
return newSelf
}
/// The sidebar widget.
public func sidebar(@ViewBuilder _ sidebar: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.sidebar = sidebar
return newSelf
}
/// The preferred sidebar width as a fraction of the total width.
///
/// The preferred width is additionally limited by
/// [property@OverlaySplitView:min-sidebar-width] and
/// [property@OverlaySplitView:max-sidebar-width].
///
/// The sidebar widget can be allocated with larger width if its own minimum
/// width exceeds the preferred width.
public func sidebarWidthFraction(_ sidebarWidthFraction: Double?) -> Self {
var newSelf = self
newSelf.sidebarWidthFraction = sidebarWidthFraction
return newSelf
}
}

View File

@ -0,0 +1,248 @@
//
// PasswordEntryRow.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A [class@EntryRow] tailored for entering secrets.
///
/// <picture><source srcset="password-entry-row-dark.png" media="(prefers-color-scheme: dark)"><img src="password-entry-row.png" alt="password-entry-row"></picture>
///
/// It does not show its contents in clear text, does not allow to copy it to the
/// clipboard, and shows a warning when Caps Lock is engaged. If the underlying
/// platform allows it, `AdwPasswordEntryRow` will also place the text in a
/// non-pageable memory area, to avoid it being written out to disk by the
/// operating system.
///
/// It offer a way to reveal the contents in clear text.
///
/// ## CSS Nodes
///
/// `AdwPasswordEntryRow` has a single CSS node with name `row` that carries
/// `.entry` and `.password` style classes.
public struct PasswordEntryRow: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether activating the embedded entry can activate the default widget.
var activatesDefault: Bool?
/// Whether to suggest emoji replacements on the entry row.
///
/// Emoji replacement is done with :-delimited names, like `:heart:`.
var enableEmojiCompletion: Bool?
/// Whether to show the apply button.
///
/// When set to `TRUE`, typing text in the entry will reveal an apply button.
/// Clicking it or pressing the <kbd>Enter</kbd> key will hide the button and
/// emit the [signal@EntryRow::apply] signal.
///
/// This is useful if changing the entry contents can trigger an expensive
/// operation, e.g. network activity, to avoid triggering it after typing every
/// character.
var showApplyButton: Bool?
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var title: String?
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
var titleSelectable: Bool?
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
var useMarkup: Bool?
/// Whether an embedded underline in the title indicates a mnemonic.
var useUnderline: Bool?
/// Emitted when the apply button is pressed.
///
/// See [property@EntryRow:show-apply-button].
var apply: (() -> Void)?
/// Emitted when the embedded entry is activated.
var entryActivated: (() -> Void)?
/// The body for the widget "suffix".
var suffix: () -> Body = { [] }
/// The body for the widget "prefix".
var prefix: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `PasswordEntryRow`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_password_entry_row_new()?.opaque())
update(storage, modifiers: modifiers)
var suffixStorage: [ViewStorage] = []
for view in suffix() {
suffixStorage.append(view.storage(modifiers: modifiers))
adw_entry_row_add_suffix(storage.pointer?.cast(), suffixStorage.last?.pointer?.cast())
}
storage.content["suffix"] = suffixStorage
var prefixStorage: [ViewStorage] = []
for view in prefix() {
prefixStorage.append(view.storage(modifiers: modifiers))
adw_entry_row_add_prefix(storage.pointer?.cast(), prefixStorage.last?.pointer?.cast())
}
storage.content["prefix"] = prefixStorage
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let apply {
storage.connectSignal(name: "apply") {
apply()
}
}
if let entryActivated {
storage.connectSignal(name: "entry-activated") {
entryActivated()
}
}
storage.modify { widget in
if let activatesDefault {
adw_entry_row_set_activates_default(widget?.cast(), activatesDefault.cBool)
}
if let enableEmojiCompletion {
adw_entry_row_set_enable_emoji_completion(widget?.cast(), enableEmojiCompletion.cBool)
}
if let showApplyButton {
adw_entry_row_set_show_apply_button(widget?.cast(), showApplyButton.cBool)
}
if let title {
adw_preferences_row_set_title(widget?.cast(), title)
}
if let titleSelectable {
adw_preferences_row_set_title_selectable(widget?.cast(), titleSelectable.cBool)
}
if let useMarkup {
adw_preferences_row_set_use_markup(widget?.cast(), useMarkup.cBool)
}
if let useUnderline {
adw_preferences_row_set_use_underline(widget?.cast(), useUnderline.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether activating the embedded entry can activate the default widget.
public func activatesDefault(_ activatesDefault: Bool? = true) -> Self {
var newSelf = self
newSelf.activatesDefault = activatesDefault
return newSelf
}
/// Whether to suggest emoji replacements on the entry row.
///
/// Emoji replacement is done with :-delimited names, like `:heart:`.
public func enableEmojiCompletion(_ enableEmojiCompletion: Bool? = true) -> Self {
var newSelf = self
newSelf.enableEmojiCompletion = enableEmojiCompletion
return newSelf
}
/// Whether to show the apply button.
///
/// When set to `TRUE`, typing text in the entry will reveal an apply button.
/// Clicking it or pressing the <kbd>Enter</kbd> key will hide the button and
/// emit the [signal@EntryRow::apply] signal.
///
/// This is useful if changing the entry contents can trigger an expensive
/// operation, e.g. network activity, to avoid triggering it after typing every
/// character.
public func showApplyButton(_ showApplyButton: Bool? = true) -> Self {
var newSelf = self
newSelf.showApplyButton = showApplyButton
return newSelf
}
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func title(_ title: String?) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
public func titleSelectable(_ titleSelectable: Bool? = true) -> Self {
var newSelf = self
newSelf.titleSelectable = titleSelectable
return newSelf
}
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
public func useMarkup(_ useMarkup: Bool? = true) -> Self {
var newSelf = self
newSelf.useMarkup = useMarkup
return newSelf
}
/// Whether an embedded underline in the title indicates a mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// Emitted when the apply button is pressed.
///
/// See [property@EntryRow:show-apply-button].
public func apply(_ apply: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.apply = apply
return newSelf
}
/// Emitted when the embedded entry is activated.
public func entryActivated(_ entryActivated: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.entryActivated = entryActivated
return newSelf
}
}

View File

@ -0,0 +1,159 @@
//
// PreferencesGroup.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A group of preference rows.
///
/// <picture><source srcset="preferences-group-dark.png" media="(prefers-color-scheme: dark)"><img src="preferences-group.png" alt="preferences-group"></picture>
///
/// An `AdwPreferencesGroup` represents a group or tightly related preferences,
/// which in turn are represented by [class@PreferencesRow].
///
/// To summarize the role of the preferences it gathers, a group can have both a
/// title and a description. The title will be used by [class@PreferencesWindow]
/// to let the user look for a preference.
///
/// ## AdwPreferencesGroup as GtkBuildable
///
/// The `AdwPreferencesGroup` implementation of the [iface@Gtk.Buildable] interface
/// supports adding [class@PreferencesRow]s to the list by omitting "type". If "type"
/// is omitted and the widget isn't a [class@PreferencesRow] the child is added to
/// a box below the list.
///
/// When the "type" attribute of a child is `header-suffix`, the child
/// is set as the suffix on the end of the title and description.
///
/// ## CSS nodes
///
/// `AdwPreferencesGroup` has a single CSS node with name `preferencesgroup`.
///
/// ## Accessibility
///
/// `AdwPreferencesGroup` uses the `GTK_ACCESSIBLE_ROLE_GROUP` role.
public struct PreferencesGroup: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The description for this group of preferences.
var description: String?
/// The header suffix widget.
///
/// Displayed above the list, next to the title and description.
///
/// Suffixes are commonly used to show a button or a spinner for the whole
/// group.
var headerSuffix: (() -> Body)?
/// The title for this group of preferences.
var title: String?
/// The body for the widget "child".
var child: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `PreferencesGroup`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_preferences_group_new()?.opaque())
update(storage, modifiers: modifiers)
if let headerSuffixStorage = headerSuffix?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["headerSuffix"] = [headerSuffixStorage]
adw_preferences_group_set_header_suffix(storage.pointer?.cast(), headerSuffixStorage.pointer?.cast())
}
var childStorage: [ViewStorage] = []
for view in child() {
childStorage.append(view.storage(modifiers: modifiers))
adw_preferences_group_add(storage.pointer?.cast(), childStorage.last?.pointer?.cast())
}
storage.content["child"] = childStorage
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let description {
adw_preferences_group_set_description(widget?.cast(), description)
}
if let widget = storage.content["headerSuffix"]?.first {
headerSuffix?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let title {
adw_preferences_group_set_title(widget?.cast(), title)
}
if let childStorage = storage.content["child"] {
for (index, view) in child().enumerated() {
if let storage = childStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
}
for function in updateFunctions {
function(storage)
}
}
/// The description for this group of preferences.
public func description(_ description: String?) -> Self {
var newSelf = self
newSelf.description = description
return newSelf
}
/// The header suffix widget.
///
/// Displayed above the list, next to the title and description.
///
/// Suffixes are commonly used to show a button or a spinner for the whole
/// group.
public func headerSuffix(@ViewBuilder _ headerSuffix: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.headerSuffix = headerSuffix
return newSelf
}
/// The title for this group of preferences.
public func title(_ title: String?) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
/// Set the body for "child".
/// - Parameter body: The body.
/// - Returns: The widget.
public func child(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.child = body
return newSelf
}
}

View File

@ -0,0 +1,157 @@
//
// PreferencesPage.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A page from [class@PreferencesWindow].
///
/// <picture><source srcset="preferences-page-dark.png" media="(prefers-color-scheme: dark)"><img src="preferences-page.png" alt="preferences-page"></picture>
///
/// The `AdwPreferencesPage` widget gathers preferences groups into a single page
/// of a preferences window.
///
/// ## CSS nodes
///
/// `AdwPreferencesPage` has a single CSS node with name `preferencespage`.
///
/// ## Accessibility
///
/// `AdwPreferencesPage` uses the `GTK_ACCESSIBLE_ROLE_GROUP` role.
public struct PreferencesPage: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The description to be displayed at the top of the page.
var description: String?
/// The icon name for this page.
var iconName: String?
/// The name of this page.
var name: String?
/// The title for this page.
var title: String?
/// Whether an embedded underline in the title indicates a mnemonic.
var useUnderline: Bool?
/// The body for the widget "child".
var child: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `PreferencesPage`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_preferences_page_new()?.opaque())
update(storage, modifiers: modifiers)
var childStorage: [ViewStorage] = []
for view in child() {
childStorage.append(view.storage(modifiers: modifiers))
adw_preferences_group_add(storage.pointer?.cast(), childStorage.last?.pointer?.cast())
}
storage.content["child"] = childStorage
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let description {
adw_preferences_page_set_description(widget?.cast(), description)
}
if let iconName {
adw_preferences_page_set_icon_name(widget?.cast(), iconName)
}
if let name {
adw_preferences_page_set_name(widget?.cast(), name)
}
if let title {
adw_preferences_page_set_title(widget?.cast(), title)
}
if let useUnderline {
adw_preferences_page_set_use_underline(widget?.cast(), useUnderline.cBool)
}
if let childStorage = storage.content["child"] {
for (index, view) in child().enumerated() {
if let storage = childStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
}
for function in updateFunctions {
function(storage)
}
}
/// The description to be displayed at the top of the page.
public func description(_ description: String?) -> Self {
var newSelf = self
newSelf.description = description
return newSelf
}
/// The icon name for this page.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// The name of this page.
public func name(_ name: String?) -> Self {
var newSelf = self
newSelf.name = name
return newSelf
}
/// The title for this page.
public func title(_ title: String?) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
/// Whether an embedded underline in the title indicates a mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// Set the body for "child".
/// - Parameter body: The body.
/// - Returns: The widget.
public func child(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.child = body
return newSelf
}
}

View File

@ -0,0 +1,134 @@
//
// PreferencesRow.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A [class@Gtk.ListBoxRow] used to present preferences.
///
/// The `AdwPreferencesRow` widget has a title that [class@PreferencesWindow]
/// will use to let the user look for a preference. It doesn't present the title
/// in any way and lets you present the preference as you please.
///
/// [class@ActionRow] and its derivatives are convenient to use as preference
/// rows as they take care of presenting the preference's title while letting you
/// compose the inputs of the preference around it.
public struct PreferencesRow: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var title: String?
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
var titleSelectable: Bool?
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
var useMarkup: Bool?
/// Whether an embedded underline in the title indicates a mnemonic.
var useUnderline: Bool?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `PreferencesRow`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_preferences_row_new()?.opaque())
update(storage, modifiers: modifiers)
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let title {
adw_preferences_row_set_title(widget?.cast(), title)
}
if let titleSelectable {
adw_preferences_row_set_title_selectable(widget?.cast(), titleSelectable.cBool)
}
if let useMarkup {
adw_preferences_row_set_use_markup(widget?.cast(), useMarkup.cBool)
}
if let useUnderline {
adw_preferences_row_set_use_underline(widget?.cast(), useUnderline.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func title(_ title: String?) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
public func titleSelectable(_ titleSelectable: Bool? = true) -> Self {
var newSelf = self
newSelf.titleSelectable = titleSelectable
return newSelf
}
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
public func useMarkup(_ useMarkup: Bool? = true) -> Self {
var newSelf = self
newSelf.useMarkup = useMarkup
return newSelf
}
/// Whether an embedded underline in the title indicates a mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
}

View File

@ -0,0 +1,184 @@
//
// ProgressBar.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// `GtkProgressBar` is typically used to display the progress of a long
/// running operation.
///
/// It provides a visual clue that processing is underway. `GtkProgressBar`
/// can be used in two different modes: percentage mode and activity mode.
///
/// ![An example GtkProgressBar](progressbar.png)
///
/// When an application can determine how much work needs to take place
/// (e.g. read a fixed number of bytes from a file) and can monitor its
/// progress, it can use the `GtkProgressBar` in percentage mode and the
/// user sees a growing bar indicating the percentage of the work that
/// has been completed. In this mode, the application is required to call
/// [method@Gtk.ProgressBar.set_fraction] periodically to update the progress bar.
///
/// When an application has no accurate way of knowing the amount of work
/// to do, it can use the `GtkProgressBar` in activity mode, which shows
/// activity by a block moving back and forth within the progress area. In
/// this mode, the application is required to call [method@Gtk.ProgressBar.pulse]
/// periodically to update the progress bar.
///
/// There is quite a bit of flexibility provided to control the appearance
/// of the `GtkProgressBar`. Functions are provided to control the orientation
/// of the bar, optional text can be displayed along with the bar, and the
/// step size used in activity mode can be set.
///
/// # CSS nodes
///
/// ```
/// progressbar[.osd]
/// [text]
/// trough[.empty][.full]
/// progress[.pulse]
/// ```
///
/// `GtkProgressBar` has a main CSS node with name progressbar and subnodes with
/// names text and trough, of which the latter has a subnode named progress. The
/// text subnode is only present if text is shown. The progress subnode has the
/// style class .pulse when in activity mode. It gets the style classes .left,
/// .right, .top or .bottom added when the progress 'touches' the corresponding
/// end of the GtkProgressBar. The .osd class on the progressbar node is for use
/// in overlays like the one Epiphany has for page loading progress.
///
/// # Accessibility
///
/// `GtkProgressBar` uses the %GTK_ACCESSIBLE_ROLE_PROGRESS_BAR role.
public struct ProgressBar: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The fraction of total work that has been completed.
var fraction: Double?
/// Invert the direction in which the progress bar grows.
var inverted: Bool?
/// The fraction of total progress to move the bounding block when pulsed.
var pulseStep: Double?
/// Sets whether the progress bar will show a text in addition
/// to the bar itself.
///
/// The shown text is either the value of the [property@Gtk.ProgressBar:text]
/// property or, if that is %NULL, the [property@Gtk.ProgressBar:fraction]
/// value, as a percentage.
///
/// To make a progress bar that is styled and sized suitably for showing text
/// (even if the actual text is blank), set [property@Gtk.ProgressBar:show-text]
/// to %TRUE and [property@Gtk.ProgressBar:text] to the empty string (not %NULL).
var showText: Bool?
/// Text to be displayed in the progress bar.
var text: String?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `ProgressBar`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_progress_bar_new()?.opaque())
update(storage, modifiers: modifiers)
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let fraction {
gtk_progress_bar_set_fraction(widget, fraction)
}
if let inverted {
gtk_progress_bar_set_inverted(widget, inverted.cBool)
}
if let pulseStep {
gtk_progress_bar_set_pulse_step(widget, pulseStep)
}
if let showText {
gtk_progress_bar_set_show_text(widget, showText.cBool)
}
if let text {
gtk_progress_bar_set_text(widget, text)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The fraction of total work that has been completed.
public func fraction(_ fraction: Double?) -> Self {
var newSelf = self
newSelf.fraction = fraction
return newSelf
}
/// Invert the direction in which the progress bar grows.
public func inverted(_ inverted: Bool? = true) -> Self {
var newSelf = self
newSelf.inverted = inverted
return newSelf
}
/// The fraction of total progress to move the bounding block when pulsed.
public func pulseStep(_ pulseStep: Double?) -> Self {
var newSelf = self
newSelf.pulseStep = pulseStep
return newSelf
}
/// Sets whether the progress bar will show a text in addition
/// to the bar itself.
///
/// The shown text is either the value of the [property@Gtk.ProgressBar:text]
/// property or, if that is %NULL, the [property@Gtk.ProgressBar:fraction]
/// value, as a percentage.
///
/// To make a progress bar that is styled and sized suitably for showing text
/// (even if the actual text is blank), set [property@Gtk.ProgressBar:show-text]
/// to %TRUE and [property@Gtk.ProgressBar:text] to the empty string (not %NULL).
public func showText(_ showText: Bool? = true) -> Self {
var newSelf = self
newSelf.showText = showText
return newSelf
}
/// Text to be displayed in the progress bar.
public func text(_ text: String?) -> Self {
var newSelf = self
newSelf.text = text
return newSelf
}
}

View File

@ -0,0 +1,403 @@
//
// ScrolledWindow.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// `GtkScrolledWindow` is a container that makes its child scrollable.
///
/// It does so using either internally added scrollbars or externally
/// associated adjustments, and optionally draws a frame around the child.
///
/// Widgets with native scrolling support, i.e. those whose classes implement
/// the [iface@Gtk.Scrollable] interface, are added directly. For other types
/// of widget, the class [class@Gtk.Viewport] acts as an adaptor, giving
/// scrollability to other widgets. [method@Gtk.ScrolledWindow.set_child]
/// intelligently accounts for whether or not the added child is a `GtkScrollable`.
/// If it isnt, then it wraps the child in a `GtkViewport`. Therefore, you can
/// just add any child widget and not worry about the details.
///
/// If [method@Gtk.ScrolledWindow.set_child] has added a `GtkViewport` for you,
/// it will be automatically removed when you unset the child.
/// Unless [property@Gtk.ScrolledWindow:hscrollbar-policy] and
/// [property@Gtk.ScrolledWindow:vscrollbar-policy] are %GTK_POLICY_NEVER or
/// %GTK_POLICY_EXTERNAL, `GtkScrolledWindow` adds internal `GtkScrollbar` widgets
/// around its child. The scroll position of the child, and if applicable the
/// scrollbars, is controlled by the [property@Gtk.ScrolledWindow:hadjustment]
/// and [property@Gtk.ScrolledWindow:vadjustment] that are associated with the
/// `GtkScrolledWindow`. See the docs on [class@Gtk.Scrollbar] for the details,
/// but note that the step_increment and page_increment fields are only
/// effective if the policy causes scrollbars to be present.
///
/// If a `GtkScrolledWindow` doesnt behave quite as you would like, or
/// doesnt have exactly the right layout, its very possible to set up
/// your own scrolling with `GtkScrollbar` and for example a `GtkGrid`.
///
/// # Touch support
///
/// `GtkScrolledWindow` has built-in support for touch devices. When a
/// touchscreen is used, swiping will move the scrolled window, and will
/// expose 'kinetic' behavior. This can be turned off with the
/// [property@Gtk.ScrolledWindow:kinetic-scrolling] property if it is undesired.
///
/// `GtkScrolledWindow` also displays visual 'overshoot' indication when
/// the content is pulled beyond the end, and this situation can be
/// captured with the [signal@Gtk.ScrolledWindow::edge-overshot] signal.
///
/// If no mouse device is present, the scrollbars will overlaid as
/// narrow, auto-hiding indicators over the content. If traditional
/// scrollbars are desired although no mouse is present, this behaviour
/// can be turned off with the [property@Gtk.ScrolledWindow:overlay-scrolling]
/// property.
///
/// # CSS nodes
///
/// `GtkScrolledWindow` has a main CSS node with name scrolledwindow.
/// It gets a .frame style class added when [property@Gtk.ScrolledWindow:has-frame]
/// is %TRUE.
///
/// It uses subnodes with names overshoot and undershoot to draw the overflow
/// and underflow indications. These nodes get the .left, .right, .top or .bottom
/// style class added depending on where the indication is drawn.
///
/// `GtkScrolledWindow` also sets the positional style classes (.left, .right,
/// .top, .bottom) and style classes related to overlay scrolling
/// (.overlay-indicator, .dragging, .hovering) on its scrollbars.
///
/// If both scrollbars are visible, the area where they meet is drawn
/// with a subnode named junction.
///
/// # Accessibility
///
/// Until GTK 4.10, `GtkScrolledWindow` used the `GTK_ACCESSIBLE_ROLE_GROUP` role.
///
/// Starting from GTK 4.12, `GtkScrolledWindow` uses the `GTK_ACCESSIBLE_ROLE_GENERIC` role.
public struct ScrolledWindow: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The child widget.
var child: (() -> Body)?
/// Whether to draw a frame around the contents.
var hasFrame: Bool?
/// Whether kinetic scrolling is enabled or not.
///
/// Kinetic scrolling only applies to devices with source %GDK_SOURCE_TOUCHSCREEN.
var kineticScrolling: Bool?
/// The maximum content height of @scrolled_window.
var maxContentHeight: Int?
/// The maximum content width of @scrolled_window.
var maxContentWidth: Int?
/// The minimum content height of @scrolled_window.
var minContentHeight: Int?
/// The minimum content width of @scrolled_window.
var minContentWidth: Int?
/// Whether overlay scrolling is enabled or not.
///
/// If it is, the scrollbars are only added as traditional widgets
/// when a mouse is present. Otherwise, they are overlaid on top of
/// the content, as narrow indicators.
///
/// Note that overlay scrolling can also be globally disabled, with
/// the [property@Gtk.Settings:gtk-overlay-scrolling] setting.
var overlayScrolling: Bool?
/// Whether the natural height of the child should be calculated and propagated
/// through the scrolled windows requested natural height.
///
/// This is useful in cases where an attempt should be made to allocate exactly
/// enough space for the natural size of the child.
var propagateNaturalHeight: Bool?
/// Whether the natural width of the child should be calculated and propagated
/// through the scrolled windows requested natural width.
///
/// This is useful in cases where an attempt should be made to allocate exactly
/// enough space for the natural size of the child.
var propagateNaturalWidth: Bool?
/// Emitted whenever user initiated scrolling makes the scrolled
/// window firmly surpass the limits defined by the adjustment
/// in that orientation.
///
/// A similar behavior without edge resistance is provided by the
/// [signal@Gtk.ScrolledWindow::edge-reached] signal.
///
/// Note: The @pos argument is LTR/RTL aware, so callers should be
/// aware too if intending to provide behavior on horizontal edges.
var edgeOvershot: (() -> Void)?
/// Emitted whenever user-initiated scrolling makes the scrolled
/// window exactly reach the lower or upper limits defined by the
/// adjustment in that orientation.
///
/// A similar behavior with edge resistance is provided by the
/// [signal@Gtk.ScrolledWindow::edge-overshot] signal.
///
/// Note: The @pos argument is LTR/RTL aware, so callers should be
/// aware too if intending to provide behavior on horizontal edges.
var edgeReached: (() -> Void)?
/// Emitted when focus is moved away from the scrolled window by a
/// keybinding.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The default bindings for this signal are
/// `Ctrl + Tab` to move forward and `Ctrl + Shift + Tab` to
/// move backward.
var moveFocusOut: (() -> Void)?
/// Emitted when a keybinding that scrolls is pressed.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The horizontal or vertical adjustment is updated which triggers a
/// signal that the scrolled windows child may listen to and scroll itself.
var scrollChild: (() -> Void)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `ScrolledWindow`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_scrolled_window_new()?.opaque())
update(storage, modifiers: modifiers)
if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["child"] = [childStorage]
gtk_scrolled_window_set_child(storage.pointer, childStorage.pointer?.cast())
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let edgeOvershot {
storage.connectSignal(name: "edge-overshot") {
edgeOvershot()
}
}
if let edgeReached {
storage.connectSignal(name: "edge-reached") {
edgeReached()
}
}
if let moveFocusOut {
storage.connectSignal(name: "move-focus-out") {
moveFocusOut()
}
}
if let scrollChild {
storage.connectSignal(name: "scroll-child") {
scrollChild()
}
}
storage.modify { widget in
if let widget = storage.content["child"]?.first {
child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let hasFrame {
gtk_scrolled_window_set_has_frame(widget, hasFrame.cBool)
}
if let kineticScrolling {
gtk_scrolled_window_set_kinetic_scrolling(widget, kineticScrolling.cBool)
}
if let maxContentHeight {
gtk_scrolled_window_set_max_content_height(widget, maxContentHeight.cInt)
}
if let maxContentWidth {
gtk_scrolled_window_set_max_content_width(widget, maxContentWidth.cInt)
}
if let minContentHeight {
gtk_scrolled_window_set_min_content_height(widget, minContentHeight.cInt)
}
if let minContentWidth {
gtk_scrolled_window_set_min_content_width(widget, minContentWidth.cInt)
}
if let overlayScrolling {
gtk_scrolled_window_set_overlay_scrolling(widget, overlayScrolling.cBool)
}
if let propagateNaturalHeight {
gtk_scrolled_window_set_propagate_natural_height(widget, propagateNaturalHeight.cBool)
}
if let propagateNaturalWidth {
gtk_scrolled_window_set_propagate_natural_width(widget, propagateNaturalWidth.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The child widget.
public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.child = child
return newSelf
}
/// Whether to draw a frame around the contents.
public func hasFrame(_ hasFrame: Bool? = true) -> Self {
var newSelf = self
newSelf.hasFrame = hasFrame
return newSelf
}
/// Whether kinetic scrolling is enabled or not.
///
/// Kinetic scrolling only applies to devices with source %GDK_SOURCE_TOUCHSCREEN.
public func kineticScrolling(_ kineticScrolling: Bool? = true) -> Self {
var newSelf = self
newSelf.kineticScrolling = kineticScrolling
return newSelf
}
/// The maximum content height of @scrolled_window.
public func maxContentHeight(_ maxContentHeight: Int?) -> Self {
var newSelf = self
newSelf.maxContentHeight = maxContentHeight
return newSelf
}
/// The maximum content width of @scrolled_window.
public func maxContentWidth(_ maxContentWidth: Int?) -> Self {
var newSelf = self
newSelf.maxContentWidth = maxContentWidth
return newSelf
}
/// The minimum content height of @scrolled_window.
public func minContentHeight(_ minContentHeight: Int?) -> Self {
var newSelf = self
newSelf.minContentHeight = minContentHeight
return newSelf
}
/// The minimum content width of @scrolled_window.
public func minContentWidth(_ minContentWidth: Int?) -> Self {
var newSelf = self
newSelf.minContentWidth = minContentWidth
return newSelf
}
/// Whether overlay scrolling is enabled or not.
///
/// If it is, the scrollbars are only added as traditional widgets
/// when a mouse is present. Otherwise, they are overlaid on top of
/// the content, as narrow indicators.
///
/// Note that overlay scrolling can also be globally disabled, with
/// the [property@Gtk.Settings:gtk-overlay-scrolling] setting.
public func overlayScrolling(_ overlayScrolling: Bool? = true) -> Self {
var newSelf = self
newSelf.overlayScrolling = overlayScrolling
return newSelf
}
/// Whether the natural height of the child should be calculated and propagated
/// through the scrolled windows requested natural height.
///
/// This is useful in cases where an attempt should be made to allocate exactly
/// enough space for the natural size of the child.
public func propagateNaturalHeight(_ propagateNaturalHeight: Bool? = true) -> Self {
var newSelf = self
newSelf.propagateNaturalHeight = propagateNaturalHeight
return newSelf
}
/// Whether the natural width of the child should be calculated and propagated
/// through the scrolled windows requested natural width.
///
/// This is useful in cases where an attempt should be made to allocate exactly
/// enough space for the natural size of the child.
public func propagateNaturalWidth(_ propagateNaturalWidth: Bool? = true) -> Self {
var newSelf = self
newSelf.propagateNaturalWidth = propagateNaturalWidth
return newSelf
}
/// Emitted whenever user initiated scrolling makes the scrolled
/// window firmly surpass the limits defined by the adjustment
/// in that orientation.
///
/// A similar behavior without edge resistance is provided by the
/// [signal@Gtk.ScrolledWindow::edge-reached] signal.
///
/// Note: The @pos argument is LTR/RTL aware, so callers should be
/// aware too if intending to provide behavior on horizontal edges.
public func edgeOvershot(_ edgeOvershot: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.edgeOvershot = edgeOvershot
return newSelf
}
/// Emitted whenever user-initiated scrolling makes the scrolled
/// window exactly reach the lower or upper limits defined by the
/// adjustment in that orientation.
///
/// A similar behavior with edge resistance is provided by the
/// [signal@Gtk.ScrolledWindow::edge-overshot] signal.
///
/// Note: The @pos argument is LTR/RTL aware, so callers should be
/// aware too if intending to provide behavior on horizontal edges.
public func edgeReached(_ edgeReached: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.edgeReached = edgeReached
return newSelf
}
/// Emitted when focus is moved away from the scrolled window by a
/// keybinding.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The default bindings for this signal are
/// `Ctrl + Tab` to move forward and `Ctrl + Shift + Tab` to
/// move backward.
public func moveFocusOut(_ moveFocusOut: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.moveFocusOut = moveFocusOut
return newSelf
}
/// Emitted when a keybinding that scrolls is pressed.
///
/// This is a [keybinding signal](class.SignalAction.html).
///
/// The horizontal or vertical adjustment is updated which triggers a
/// signal that the scrolled windows child may listen to and scroll itself.
public func scrollChild(_ scrollChild: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.scrollChild = scrollChild
return newSelf
}
}

View File

@ -0,0 +1,432 @@
//
// SpinRow.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// An [class@ActionRow] with an embedded spin button.
///
/// <picture><source srcset="spin-row-dark.png" media="(prefers-color-scheme: dark)"><img src="spin-row.png" alt="spin-row"></picture>
///
/// Example of an `AdwSpinRow` UI definition:
///
/// ```xml
/// <object class="AdwSpinRow"><property name="title" translatable="yes">Spin Row</property><property name="adjustment"><object class="GtkAdjustment"><property name="lower">0</property><property name="upper">100</property><property name="value">50</property><property name="page-increment">10</property><property name="step-increment">1</property></object></property></object>
/// ```
///
/// See [class@Gtk.SpinButton] for details.
///
/// ## CSS nodes
///
/// `AdwSpinRow` has the same structure as [class@ActionRow], as well as the
/// `.spin` style class on the main node.
public struct SpinRow: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The acceleration rate when you hold down a button or key.
var climbRate: Double
/// The number of decimal places to display.
var digits: UInt
/// Whether non-numeric characters should be ignored.
var numeric: Bool?
/// Whether invalid values are snapped to the nearest step increment.
var snapToTicks: Bool?
/// The current value.
var value: Binding<Double>?
/// Whether the spin row should wrap upon reaching its limits.
var wrap: Bool?
/// The widget to activate when the row is activated.
///
/// The row can be activated either by clicking on it, calling
/// [method@ActionRow.activate], or via mnemonics in the title.
/// See the [property@PreferencesRow:use-underline] property to enable
/// mnemonics.
///
/// The target widget will be activated by emitting the
/// [signal@Gtk.Widget::mnemonic-activate] signal on it.
var activatableWidget: (() -> Body)?
/// The icon name for this row.
var iconName: String?
/// The subtitle for this row.
///
/// The subtitle is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var subtitle: String?
/// The number of lines at the end of which the subtitle label will be
/// ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
var subtitleLines: Int?
/// Whether the user can copy the subtitle from the label.
///
/// See also [property@Gtk.Label:selectable].
var subtitleSelectable: Bool?
/// The number of lines at the end of which the title label will be ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
var titleLines: Int?
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var title: String?
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
var titleSelectable: Bool?
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
var useMarkup: Bool?
/// Whether an embedded underline in the title indicates a mnemonic.
var useUnderline: Bool?
/// Emitted to convert the user's input into a double value.
///
/// The signal handler is expected to use [method@Gtk.Editable.get_text] to
/// retrieve the text of the spinbutton and set new_value to the new value.
///
/// The default conversion uses [func@GLib.strtod].
///
/// See [signal@Gtk.SpinButton::input].
var input: (() -> Void)?
/// Emitted to tweak the formatting of the value for display.
///
/// See [signal@Gtk.SpinButton::output].
var output: (() -> Void)?
/// Emitted right after the spinbutton wraps.
///
/// See [signal@Gtk.SpinButton::wrapped].
var wrapped: (() -> Void)?
/// This signal is emitted after the row has been activated.
var activated: (() -> Void)?
/// The body for the widget "suffix".
var suffix: () -> Body = { [] }
/// The body for the widget "prefix".
var prefix: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `SpinRow`.
public init(climbRate: Double, digits: UInt) {
self.climbRate = climbRate
self.digits = digits
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_spin_row_new(nil, climbRate, digits.cInt)?.opaque())
update(storage, modifiers: modifiers)
if let activatableWidgetStorage = activatableWidget?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["activatableWidget"] = [activatableWidgetStorage]
adw_action_row_set_activatable_widget(storage.pointer?.cast(), activatableWidgetStorage.pointer?.cast())
}
var suffixStorage: [ViewStorage] = []
for view in suffix() {
suffixStorage.append(view.storage(modifiers: modifiers))
adw_action_row_add_suffix(storage.pointer?.cast(), suffixStorage.last?.pointer?.cast())
}
storage.content["suffix"] = suffixStorage
var prefixStorage: [ViewStorage] = []
for view in prefix() {
prefixStorage.append(view.storage(modifiers: modifiers))
adw_action_row_add_prefix(storage.pointer?.cast(), prefixStorage.last?.pointer?.cast())
}
storage.content["prefix"] = prefixStorage
storage.notify(name: "value") {
value?.wrappedValue = adw_spin_row_get_value(storage.pointer)
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let input {
storage.connectSignal(name: "input") {
input()
}
}
if let output {
storage.connectSignal(name: "output") {
output()
}
}
if let wrapped {
storage.connectSignal(name: "wrapped") {
wrapped()
}
}
if let activated {
storage.connectSignal(name: "activated") {
activated()
}
}
storage.modify { widget in
adw_spin_row_set_climb_rate(widget, climbRate)
adw_spin_row_set_digits(widget, digits.cInt)
if let numeric {
adw_spin_row_set_numeric(widget, numeric.cBool)
}
if let snapToTicks {
adw_spin_row_set_snap_to_ticks(widget, snapToTicks.cBool)
}
if let value {
adw_spin_row_set_value(widget, value.wrappedValue)
}
if let wrap {
adw_spin_row_set_wrap(widget, wrap.cBool)
}
if let widget = storage.content["activatableWidget"]?.first {
activatableWidget?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let iconName {
adw_action_row_set_icon_name(widget?.cast(), iconName)
}
if let subtitle {
adw_action_row_set_subtitle(widget?.cast(), subtitle)
}
if let subtitleLines {
adw_action_row_set_subtitle_lines(widget?.cast(), subtitleLines.cInt)
}
if let subtitleSelectable {
adw_action_row_set_subtitle_selectable(widget?.cast(), subtitleSelectable.cBool)
}
if let titleLines {
adw_action_row_set_title_lines(widget?.cast(), titleLines.cInt)
}
if let title {
adw_preferences_row_set_title(widget?.cast(), title)
}
if let titleSelectable {
adw_preferences_row_set_title_selectable(widget?.cast(), titleSelectable.cBool)
}
if let useMarkup {
adw_preferences_row_set_use_markup(widget?.cast(), useMarkup.cBool)
}
if let useUnderline {
adw_preferences_row_set_use_underline(widget?.cast(), useUnderline.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The acceleration rate when you hold down a button or key.
public func climbRate(_ climbRate: Double) -> Self {
var newSelf = self
newSelf.climbRate = climbRate
return newSelf
}
/// The number of decimal places to display.
public func digits(_ digits: UInt) -> Self {
var newSelf = self
newSelf.digits = digits
return newSelf
}
/// Whether non-numeric characters should be ignored.
public func numeric(_ numeric: Bool? = true) -> Self {
var newSelf = self
newSelf.numeric = numeric
return newSelf
}
/// Whether invalid values are snapped to the nearest step increment.
public func snapToTicks(_ snapToTicks: Bool? = true) -> Self {
var newSelf = self
newSelf.snapToTicks = snapToTicks
return newSelf
}
/// The current value.
public func value(_ value: Binding<Double>?) -> Self {
var newSelf = self
newSelf.value = value
return newSelf
}
/// Whether the spin row should wrap upon reaching its limits.
public func wrap(_ wrap: Bool? = true) -> Self {
var newSelf = self
newSelf.wrap = wrap
return newSelf
}
/// The widget to activate when the row is activated.
///
/// The row can be activated either by clicking on it, calling
/// [method@ActionRow.activate], or via mnemonics in the title.
/// See the [property@PreferencesRow:use-underline] property to enable
/// mnemonics.
///
/// The target widget will be activated by emitting the
/// [signal@Gtk.Widget::mnemonic-activate] signal on it.
public func activatableWidget(@ViewBuilder _ activatableWidget: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.activatableWidget = activatableWidget
return newSelf
}
/// The icon name for this row.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// The subtitle for this row.
///
/// The subtitle is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func subtitle(_ subtitle: String?) -> Self {
var newSelf = self
newSelf.subtitle = subtitle
return newSelf
}
/// The number of lines at the end of which the subtitle label will be
/// ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
public func subtitleLines(_ subtitleLines: Int?) -> Self {
var newSelf = self
newSelf.subtitleLines = subtitleLines
return newSelf
}
/// Whether the user can copy the subtitle from the label.
///
/// See also [property@Gtk.Label:selectable].
public func subtitleSelectable(_ subtitleSelectable: Bool? = true) -> Self {
var newSelf = self
newSelf.subtitleSelectable = subtitleSelectable
return newSelf
}
/// The number of lines at the end of which the title label will be ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
public func titleLines(_ titleLines: Int?) -> Self {
var newSelf = self
newSelf.titleLines = titleLines
return newSelf
}
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func title(_ title: String?) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
public func titleSelectable(_ titleSelectable: Bool? = true) -> Self {
var newSelf = self
newSelf.titleSelectable = titleSelectable
return newSelf
}
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
public func useMarkup(_ useMarkup: Bool? = true) -> Self {
var newSelf = self
newSelf.useMarkup = useMarkup
return newSelf
}
/// Whether an embedded underline in the title indicates a mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// Emitted to convert the user's input into a double value.
///
/// The signal handler is expected to use [method@Gtk.Editable.get_text] to
/// retrieve the text of the spinbutton and set new_value to the new value.
///
/// The default conversion uses [func@GLib.strtod].
///
/// See [signal@Gtk.SpinButton::input].
public func input(_ input: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.input = input
return newSelf
}
/// Emitted to tweak the formatting of the value for display.
///
/// See [signal@Gtk.SpinButton::output].
public func output(_ output: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.output = output
return newSelf
}
/// Emitted right after the spinbutton wraps.
///
/// See [signal@Gtk.SpinButton::wrapped].
public func wrapped(_ wrapped: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.wrapped = wrapped
return newSelf
}
/// This signal is emitted after the row has been activated.
public func activated(_ activated: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.activated = activated
return newSelf
}
}

View File

@ -0,0 +1,83 @@
//
// Spinner.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A `GtkSpinner` widget displays an icon-size spinning animation.
///
/// It is often used as an alternative to a [class@Gtk.ProgressBar]
/// for displaying indefinite activity, instead of actual progress.
///
/// ![An example GtkSpinner](spinner.png)
///
/// To start the animation, use [method@Gtk.Spinner.start], to stop it
/// use [method@Gtk.Spinner.stop].
///
/// # CSS nodes
///
/// `GtkSpinner` has a single CSS node with the name spinner.
/// When the animation is active, the :checked pseudoclass is
/// added to this node.
public struct Spinner: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether the spinner is spinning
var spinning: Bool?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `Spinner`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_spinner_new()?.opaque())
update(storage, modifiers: modifiers)
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let spinning {
gtk_spinner_set_spinning(widget, spinning.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether the spinner is spinning
public func spinning(_ spinning: Bool? = true) -> Self {
var newSelf = self
newSelf.spinning = spinning
return newSelf
}
}

View File

@ -0,0 +1,274 @@
//
// SplitButton.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A combined button and dropdown widget.
///
/// <picture><source srcset="split-button-dark.png" media="(prefers-color-scheme: dark)"><img src="split-button.png" alt="split-button"></picture>
///
/// `AdwSplitButton` is typically used to present a set of actions in a menu,
/// but allow access to one of them with a single click.
///
/// The API is very similar to [class@Gtk.Button] and [class@Gtk.MenuButton], see
/// their documentation for details.
///
/// ## CSS nodes
///
/// ```
/// splitbutton[.image-button][.text-button]
/// button
/// <content> separator
/// menubutton
/// button.toggle
/// arrow
/// ```
///
/// `AdwSplitButton`'s CSS node is called `splitbutton`. It contains the css
/// nodes: `button`, `separator`, `menubutton`. See [class@Gtk.MenuButton]
/// documentation for the `menubutton` contents.
///
/// The main CSS node will contain the `.image-button` or `.text-button` style
/// classes matching the button contents. The nested button nodes will never
/// contain them.
///
/// ## Accessibility
///
/// `AdwSplitButton` uses the `GTK_ACCESSIBLE_ROLE_GROUP` role.
public struct SplitButton: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether the button can be smaller than the natural size of its contents.
///
/// If set to `TRUE`, the label will ellipsize.
///
/// See [property@Gtk.Button:can-shrink] and
/// [property@Gtk.MenuButton:can-shrink].
var canShrink: Bool?
/// The child widget.
///
/// Setting the child widget will set [property@SplitButton:label] and
/// [property@SplitButton:icon-name] to `NULL`.
var child: (() -> Body)?
/// The tooltip of the dropdown button.
///
/// The tooltip can be marked up with the Pango text markup language.
var dropdownTooltip: String?
/// The name of the icon used to automatically populate the button.
///
/// Setting the icon name will set [property@SplitButton:label] and
/// [property@SplitButton:child] to `NULL`.
var iconName: String?
/// The label for the button.
///
/// Setting the label will set [property@SplitButton:icon-name] and
/// [property@SplitButton:child] to `NULL`.
var label: String?
/// The `GMenuModel` from which the popup will be created.
///
/// If the menu model is `NULL`, the dropdown is disabled.
///
/// A [class@Gtk.Popover] will be created from the menu model with
/// [ctor@Gtk.PopoverMenu.new_from_model]. Actions will be connected as
/// documented for this function.
///
/// If [property@SplitButton:popover] is already set, it will be dissociated
/// from the button, and the property is set to `NULL`.
var menuModel: (() -> MenuContent)?
/// Whether an underline in the text indicates a mnemonic.
///
/// See [property@SplitButton:label].
var useUnderline: Bool?
/// Emitted to animate press then release.
///
/// This is an action signal. Applications should never connect to this signal,
/// but use the [signal@SplitButton::clicked] signal.
var activate: (() -> Void)?
/// Emitted when the button has been activated (pressed and released).
var clicked: (() -> Void)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `SplitButton`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_split_button_new()?.opaque())
update(storage, modifiers: modifiers)
if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["child"] = [childStorage]
adw_split_button_set_child(storage.pointer, childStorage.pointer?.cast())
}
if let declarative = menuModel?(), let app {
let menu = g_menu_new()
adw_split_button_set_menu_model(storage.pointer, menu?.cast())
for item in declarative {
item.addMenuItems(menu: menu, app: app, window: window)
}
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let activate {
storage.connectSignal(name: "activate") {
activate()
}
}
if let clicked {
storage.connectSignal(name: "clicked") {
clicked()
}
}
storage.modify { widget in
if let canShrink {
adw_split_button_set_can_shrink(widget, canShrink.cBool)
}
if let widget = storage.content["child"]?.first {
child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let dropdownTooltip {
adw_split_button_set_dropdown_tooltip(widget, dropdownTooltip)
}
if let iconName {
adw_split_button_set_icon_name(widget, iconName)
}
if let label, storage.content["child"] == nil {
adw_split_button_set_label(widget, label)
}
if let useUnderline {
adw_split_button_set_use_underline(widget, useUnderline.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether the button can be smaller than the natural size of its contents.
///
/// If set to `TRUE`, the label will ellipsize.
///
/// See [property@Gtk.Button:can-shrink] and
/// [property@Gtk.MenuButton:can-shrink].
public func canShrink(_ canShrink: Bool? = true) -> Self {
var newSelf = self
newSelf.canShrink = canShrink
return newSelf
}
/// The child widget.
///
/// Setting the child widget will set [property@SplitButton:label] and
/// [property@SplitButton:icon-name] to `NULL`.
public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.child = child
return newSelf
}
/// The tooltip of the dropdown button.
///
/// The tooltip can be marked up with the Pango text markup language.
public func dropdownTooltip(_ dropdownTooltip: String?) -> Self {
var newSelf = self
newSelf.dropdownTooltip = dropdownTooltip
return newSelf
}
/// The name of the icon used to automatically populate the button.
///
/// Setting the icon name will set [property@SplitButton:label] and
/// [property@SplitButton:child] to `NULL`.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// The label for the button.
///
/// Setting the label will set [property@SplitButton:icon-name] and
/// [property@SplitButton:child] to `NULL`.
public func label(_ label: String?) -> Self {
var newSelf = self
newSelf.label = label
return newSelf
}
/// The `GMenuModel` from which the popup will be created.
///
/// If the menu model is `NULL`, the dropdown is disabled.
///
/// A [class@Gtk.Popover] will be created from the menu model with
/// [ctor@Gtk.PopoverMenu.new_from_model]. Actions will be connected as
/// documented for this function.
///
/// If [property@SplitButton:popover] is already set, it will be dissociated
/// from the button, and the property is set to `NULL`.
public func menuModel(app: GTUIApp, window: GTUIApplicationWindow? = nil, @MenuBuilder _ menuModel: @escaping (() -> MenuContent)) -> Self {
var newSelf = self
newSelf.menuModel = menuModel
newSelf.app = app; newSelf.window = window
return newSelf
}
/// Whether an underline in the text indicates a mnemonic.
///
/// See [property@SplitButton:label].
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// Emitted to animate press then release.
///
/// This is an action signal. Applications should never connect to this signal,
/// but use the [signal@SplitButton::clicked] signal.
public func activate(_ activate: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.activate = activate
return newSelf
}
/// Emitted when the button has been activated (pressed and released).
public func clicked(_ clicked: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.clicked = clicked
return newSelf
}
}

View File

@ -0,0 +1,133 @@
//
// StatusPage.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A page used for empty/error states and similar use-cases.
///
/// <picture><source srcset="status-page-dark.png" media="(prefers-color-scheme: dark)"><img src="status-page.png" alt="status-page"></picture>
///
/// The `AdwStatusPage` widget can have an icon, a title, a description and a
/// custom widget which is displayed below them.
///
/// ## CSS nodes
///
/// `AdwStatusPage` has a main CSS node with name `statuspage`.
///
/// `AdwStatusPage` can use the
/// [`.compact`](style-classes.html#compact-status-page) style class for when it
/// needs to fit into a small space such a sidebar or a popover.
public struct StatusPage: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The child widget.
var child: (() -> Body)?
/// The description markup to be displayed below the title.
var description: String?
/// The name of the icon to be used.
///
/// Changing this will set [property@StatusPage:paintable] to `NULL`.
var iconName: String?
/// The title to be displayed below the icon.
///
/// It is not parsed as Pango markup.
var title: String?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `StatusPage`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_status_page_new()?.opaque())
update(storage, modifiers: modifiers)
if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["child"] = [childStorage]
adw_status_page_set_child(storage.pointer, childStorage.pointer?.cast())
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let widget = storage.content["child"]?.first {
child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let description {
adw_status_page_set_description(widget, description)
}
if let iconName {
adw_status_page_set_icon_name(widget, iconName)
}
if let title {
adw_status_page_set_title(widget, title)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The child widget.
public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.child = child
return newSelf
}
/// The description markup to be displayed below the title.
public func description(_ description: String?) -> Self {
var newSelf = self
newSelf.description = description
return newSelf
}
/// The name of the icon to be used.
///
/// Changing this will set [property@StatusPage:paintable] to `NULL`.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// The title to be displayed below the icon.
///
/// It is not parsed as Pango markup.
public func title(_ title: String?) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
}

View File

@ -0,0 +1,309 @@
//
// SwitchRow.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A [class@Gtk.ListBoxRow] used to represent two states.
///
/// <picture><source srcset="switch-row-dark.png" media="(prefers-color-scheme: dark)"><img src="switch-row.png" alt="switch-row"></picture>
///
/// The `AdwSwitchRow` widget contains a [class@Gtk.Switch] that allows the user
/// to select between two states: "on" or "off". When activated, the row will
/// invert its active state.
///
/// The user can control the switch by activating the row or by dragging on the
/// switch handle.
///
/// See [class@Gtk.Switch] for details.
///
/// Example of an `AdwSwitchRow` UI definition:
/// ```xml
/// <object class="AdwSwitchRow"><property name="title" translatable="yes">Switch Row</property><signal name="notify::active" handler="switch_row_notify_active_cb"/></object>
/// ```
///
/// The [property@SwitchRow:active] property should be connected to in order to
/// monitor changes to the active state.
public struct SwitchRow: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// Whether the switch row is in the "on" or "off" position.
var active: Binding<Bool>?
/// The widget to activate when the row is activated.
///
/// The row can be activated either by clicking on it, calling
/// [method@ActionRow.activate], or via mnemonics in the title.
/// See the [property@PreferencesRow:use-underline] property to enable
/// mnemonics.
///
/// The target widget will be activated by emitting the
/// [signal@Gtk.Widget::mnemonic-activate] signal on it.
var activatableWidget: (() -> Body)?
/// The icon name for this row.
var iconName: String?
/// The subtitle for this row.
///
/// The subtitle is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var subtitle: String?
/// The number of lines at the end of which the subtitle label will be
/// ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
var subtitleLines: Int?
/// Whether the user can copy the subtitle from the label.
///
/// See also [property@Gtk.Label:selectable].
var subtitleSelectable: Bool?
/// The number of lines at the end of which the title label will be ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
var titleLines: Int?
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
var title: String?
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
var titleSelectable: Bool?
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
var useMarkup: Bool?
/// Whether an embedded underline in the title indicates a mnemonic.
var useUnderline: Bool?
/// This signal is emitted after the row has been activated.
var activated: (() -> Void)?
/// The body for the widget "suffix".
var suffix: () -> Body = { [] }
/// The body for the widget "prefix".
var prefix: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `SwitchRow`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_switch_row_new()?.opaque())
update(storage, modifiers: modifiers)
if let activatableWidgetStorage = activatableWidget?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["activatableWidget"] = [activatableWidgetStorage]
adw_action_row_set_activatable_widget(storage.pointer?.cast(), activatableWidgetStorage.pointer?.cast())
}
var suffixStorage: [ViewStorage] = []
for view in suffix() {
suffixStorage.append(view.storage(modifiers: modifiers))
adw_action_row_add_suffix(storage.pointer?.cast(), suffixStorage.last?.pointer?.cast())
}
storage.content["suffix"] = suffixStorage
var prefixStorage: [ViewStorage] = []
for view in prefix() {
prefixStorage.append(view.storage(modifiers: modifiers))
adw_action_row_add_prefix(storage.pointer?.cast(), prefixStorage.last?.pointer?.cast())
}
storage.content["prefix"] = prefixStorage
storage.notify(name: "active") {
active?.wrappedValue = adw_switch_row_get_active(storage.pointer) != 0
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let activated {
storage.connectSignal(name: "activated") {
activated()
}
}
storage.modify { widget in
if let active {
adw_switch_row_set_active(widget, active.wrappedValue.cBool)
}
if let widget = storage.content["activatableWidget"]?.first {
activatableWidget?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let iconName {
adw_action_row_set_icon_name(widget?.cast(), iconName)
}
if let subtitle {
adw_action_row_set_subtitle(widget?.cast(), subtitle)
}
if let subtitleLines {
adw_action_row_set_subtitle_lines(widget?.cast(), subtitleLines.cInt)
}
if let subtitleSelectable {
adw_action_row_set_subtitle_selectable(widget?.cast(), subtitleSelectable.cBool)
}
if let titleLines {
adw_action_row_set_title_lines(widget?.cast(), titleLines.cInt)
}
if let title {
adw_preferences_row_set_title(widget?.cast(), title)
}
if let titleSelectable {
adw_preferences_row_set_title_selectable(widget?.cast(), titleSelectable.cBool)
}
if let useMarkup {
adw_preferences_row_set_use_markup(widget?.cast(), useMarkup.cBool)
}
if let useUnderline {
adw_preferences_row_set_use_underline(widget?.cast(), useUnderline.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// Whether the switch row is in the "on" or "off" position.
public func active(_ active: Binding<Bool>?) -> Self {
var newSelf = self
newSelf.active = active
return newSelf
}
/// The widget to activate when the row is activated.
///
/// The row can be activated either by clicking on it, calling
/// [method@ActionRow.activate], or via mnemonics in the title.
/// See the [property@PreferencesRow:use-underline] property to enable
/// mnemonics.
///
/// The target widget will be activated by emitting the
/// [signal@Gtk.Widget::mnemonic-activate] signal on it.
public func activatableWidget(@ViewBuilder _ activatableWidget: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.activatableWidget = activatableWidget
return newSelf
}
/// The icon name for this row.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// The subtitle for this row.
///
/// The subtitle is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func subtitle(_ subtitle: String?) -> Self {
var newSelf = self
newSelf.subtitle = subtitle
return newSelf
}
/// The number of lines at the end of which the subtitle label will be
/// ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
public func subtitleLines(_ subtitleLines: Int?) -> Self {
var newSelf = self
newSelf.subtitleLines = subtitleLines
return newSelf
}
/// Whether the user can copy the subtitle from the label.
///
/// See also [property@Gtk.Label:selectable].
public func subtitleSelectable(_ subtitleSelectable: Bool? = true) -> Self {
var newSelf = self
newSelf.subtitleSelectable = subtitleSelectable
return newSelf
}
/// The number of lines at the end of which the title label will be ellipsized.
///
/// If the value is 0, the number of lines won't be limited.
public func titleLines(_ titleLines: Int?) -> Self {
var newSelf = self
newSelf.titleLines = titleLines
return newSelf
}
/// The title of the preference represented by this row.
///
/// The title is interpreted as Pango markup unless
/// [property@PreferencesRow:use-markup] is set to `FALSE`.
public func title(_ title: String?) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
/// Whether the user can copy the title from the label.
///
/// See also [property@Gtk.Label:selectable].
public func titleSelectable(_ titleSelectable: Bool? = true) -> Self {
var newSelf = self
newSelf.titleSelectable = titleSelectable
return newSelf
}
/// Whether to use Pango markup for the title label.
///
/// Subclasses may also use it for other labels, such as subtitle.
///
/// See also [func@Pango.parse_markup].
public func useMarkup(_ useMarkup: Bool? = true) -> Self {
var newSelf = self
newSelf.useMarkup = useMarkup
return newSelf
}
/// Whether an embedded underline in the title indicates a mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// This signal is emitted after the row has been activated.
public func activated(_ activated: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.activated = activated
return newSelf
}
}

View File

@ -0,0 +1,108 @@
//
// ToastOverlay.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A widget showing toasts above its content.
///
/// <picture><source srcset="toast-overlay-dark.png" media="(prefers-color-scheme: dark)"><img src="toast-overlay.png" alt="toast-overlay"></picture>
///
/// Much like [class@Gtk.Overlay], `AdwToastOverlay` is a container with a single
/// main child, on top of which it can display a [class@Toast], overlaid.
/// Toasts can be shown with [method@ToastOverlay.add_toast].
///
/// See [class@Toast] for details.
///
/// ## CSS nodes
///
/// ```
/// toastoverlay
/// [child]
/// toast
/// widget
/// [label.heading]
/// [custom title]
/// [button]
/// button.circular.flat
/// ```
///
/// `AdwToastOverlay`'s CSS node is called `toastoverlay`. It contains the child,
/// as well as zero or more `toast` subnodes.
///
/// Each of the `toast` nodes contains a `widget` subnode, optionally a `button`
/// subnode, and another `button` subnode with `.circular` and `.flat` style
/// classes.
///
/// The `widget` subnode contains a `label` subnode with the `.heading` style
/// class, or a custom widget provided by the application.
///
/// ## Accessibility
///
/// `AdwToastOverlay` uses the `GTK_ACCESSIBLE_ROLE_TAB_GROUP` role.
public struct ToastOverlay: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The child widget.
var child: (() -> Body)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `ToastOverlay`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_toast_overlay_new()?.opaque())
update(storage, modifiers: modifiers)
if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["child"] = [childStorage]
adw_toast_overlay_set_child(storage.pointer, childStorage.pointer?.cast())
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let widget = storage.content["child"]?.first {
child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
}
for function in updateFunctions {
function(storage)
}
}
/// The child widget.
public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.child = child
return newSelf
}
}

View File

@ -0,0 +1,296 @@
//
// ToggleButton.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A `GtkToggleButton` is a button which remains pressed-in when
/// clicked.
///
/// Clicking again will cause the toggle button to return to its normal state.
///
/// A toggle button is created by calling either [ctor@Gtk.ToggleButton.new] or
/// [ctor@Gtk.ToggleButton.new_with_label]. If using the former, it is advisable
/// to pack a widget, (such as a `GtkLabel` and/or a `GtkImage`), into the toggle
/// buttons container. (See [class@Gtk.Button] for more information).
///
/// The state of a `GtkToggleButton` can be set specifically using
/// [method@Gtk.ToggleButton.set_active], and retrieved using
/// [method@Gtk.ToggleButton.get_active].
///
/// To simply switch the state of a toggle button, use
/// [method@Gtk.ToggleButton.toggled].
///
/// ## Grouping
///
/// Toggle buttons can be grouped together, to form mutually exclusive
/// groups - only one of the buttons can be toggled at a time, and toggling
/// another one will switch the currently toggled one off.
///
/// To add a `GtkToggleButton` to a group, use [method@Gtk.ToggleButton.set_group].
///
/// ## CSS nodes
///
/// `GtkToggleButton` has a single CSS node with name button. To differentiate
/// it from a plain `GtkButton`, it gets the `.toggle` style class.
///
/// ## Accessibility
///
/// `GtkToggleButton` uses the %GTK_ACCESSIBLE_ROLE_TOGGLE_BUTTON role.
///
/// ## Creating two `GtkToggleButton` widgets.
///
/// ```c
/// static void
/// output_state (GtkToggleButton *source,
/// gpointer user_data)
/// {
/// g_print ("Toggle button "%s" is active: %s",
/// gtk_button_get_label (GTK_BUTTON (source)),
/// gtk_toggle_button_get_active (source) ? "Yes" : "No");
/// }
///
/// static void
/// make_toggles (void)
/// {
/// GtkWidget *window, *toggle1, *toggle2;
/// GtkWidget *box;
/// const char *text;
///
/// window = gtk_window_new ();
/// box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
///
/// text = "Hi, Im toggle button one";
/// toggle1 = gtk_toggle_button_new_with_label (text);
///
/// g_signal_connect (toggle1, "toggled",
/// G_CALLBACK (output_state),
/// NULL);
/// gtk_box_append (GTK_BOX (box), toggle1);
///
/// text = "Hi, Im toggle button two";
/// toggle2 = gtk_toggle_button_new_with_label (text);
/// g_signal_connect (toggle2, "toggled",
/// G_CALLBACK (output_state),
/// NULL);
/// gtk_box_append (GTK_BOX (box), toggle2);
///
/// gtk_window_set_child (GTK_WINDOW (window), box);
/// gtk_window_present (GTK_WINDOW (window));
/// }
/// ```
public struct ToggleButton: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// If the toggle button should be pressed in.
var active: Binding<Bool>?
/// Whether the size of the button can be made smaller than the natural
/// size of its contents.
///
/// For text buttons, setting this property will allow ellipsizing the label.
///
/// If the contents of a button are an icon or a custom widget, setting this
/// property has no effect.
var canShrink: Bool?
/// The child widget.
var child: (() -> Body)?
/// Whether the button has a frame.
var hasFrame: Bool?
/// The name of the icon used to automatically populate the button.
var iconName: String?
/// Text of the label inside the button, if the button contains a label widget.
var label: String?
/// If set, an underline in the text indicates that the following character is
/// to be used as mnemonic.
var useUnderline: Bool?
/// Emitted whenever the `GtkToggleButton`'s state is changed.
var toggled: (() -> Void)?
/// Emitted to animate press then release.
///
/// This is an action signal. Applications should never connect
/// to this signal, but use the [signal@Gtk.Button::clicked] signal.
///
/// The default bindings for this signal are all forms of the
/// <kbd></kbd> and <kbd>Enter</kbd> keys.
var activate: (() -> Void)?
/// Emitted when the button has been activated (pressed and released).
var clicked: (() -> Void)?
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `ToggleButton`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(gtk_toggle_button_new()?.opaque())
update(storage, modifiers: modifiers)
if let childStorage = child?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["child"] = [childStorage]
gtk_button_set_child(storage.pointer?.cast(), childStorage.pointer?.cast())
}
storage.notify(name: "active") {
active?.wrappedValue = gtk_toggle_button_get_active(storage.pointer?.cast()) != 0
}
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
if let toggled {
storage.connectSignal(name: "toggled") {
toggled()
}
}
if let activate {
storage.connectSignal(name: "activate") {
activate()
}
}
if let clicked {
storage.connectSignal(name: "clicked") {
clicked()
}
}
storage.modify { widget in
if let active {
gtk_toggle_button_set_active(widget?.cast(), active.wrappedValue.cBool)
}
if let canShrink {
gtk_button_set_can_shrink(widget?.cast(), canShrink.cBool)
}
if let widget = storage.content["child"]?.first {
child?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let hasFrame {
gtk_button_set_has_frame(widget?.cast(), hasFrame.cBool)
}
if let iconName {
gtk_button_set_icon_name(widget?.cast(), iconName)
}
if let label, storage.content["child"] == nil {
gtk_button_set_label(widget?.cast(), label)
}
if let useUnderline {
gtk_button_set_use_underline(widget?.cast(), useUnderline.cBool)
}
}
for function in updateFunctions {
function(storage)
}
}
/// If the toggle button should be pressed in.
public func active(_ active: Binding<Bool>?) -> Self {
var newSelf = self
newSelf.active = active
return newSelf
}
/// Whether the size of the button can be made smaller than the natural
/// size of its contents.
///
/// For text buttons, setting this property will allow ellipsizing the label.
///
/// If the contents of a button are an icon or a custom widget, setting this
/// property has no effect.
public func canShrink(_ canShrink: Bool? = true) -> Self {
var newSelf = self
newSelf.canShrink = canShrink
return newSelf
}
/// The child widget.
public func child(@ViewBuilder _ child: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.child = child
return newSelf
}
/// Whether the button has a frame.
public func hasFrame(_ hasFrame: Bool? = true) -> Self {
var newSelf = self
newSelf.hasFrame = hasFrame
return newSelf
}
/// The name of the icon used to automatically populate the button.
public func iconName(_ iconName: String?) -> Self {
var newSelf = self
newSelf.iconName = iconName
return newSelf
}
/// Text of the label inside the button, if the button contains a label widget.
public func label(_ label: String?) -> Self {
var newSelf = self
newSelf.label = label
return newSelf
}
/// If set, an underline in the text indicates that the following character is
/// to be used as mnemonic.
public func useUnderline(_ useUnderline: Bool? = true) -> Self {
var newSelf = self
newSelf.useUnderline = useUnderline
return newSelf
}
/// Emitted whenever the `GtkToggleButton`'s state is changed.
public func toggled(_ toggled: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.toggled = toggled
return newSelf
}
/// Emitted to animate press then release.
///
/// This is an action signal. Applications should never connect
/// to this signal, but use the [signal@Gtk.Button::clicked] signal.
///
/// The default bindings for this signal are all forms of the
/// <kbd></kbd> and <kbd>Enter</kbd> keys.
public func activate(_ activate: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.activate = activate
return newSelf
}
/// Emitted when the button has been activated (pressed and released).
public func clicked(_ clicked: @escaping () -> Void) -> Self {
var newSelf = self
newSelf.clicked = clicked
return newSelf
}
}

View File

@ -0,0 +1,332 @@
//
// ToolbarView.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A widget containing a page, as well as top and/or bottom bars.
///
/// <picture><source srcset="toolbar-view-dark.png" media="(prefers-color-scheme: dark)"><img src="toolbar-view.png" alt="toolbar-view"></picture>
///
/// `AdwToolbarView` has a single content widget and one or multiple top and
/// bottom bars, shown at the top and bottom sides respectively.
///
/// Example of an `AdwToolbarView` UI definition:
/// ```xml
/// <object class="AdwToolbarView"><child type="top"><object class="AdwHeaderBar"/></child><property name="content"><object class="AdwPreferencesPage"><!-- ... --></object></property></object>
/// ```
///
/// The following kinds of top and bottom bars are supported:
///
/// - [class@HeaderBar]
/// - [class@TabBar]
/// - [class@ViewSwitcherBar]
/// - [class@Gtk.ActionBar]
/// - [class@Gtk.HeaderBar]
/// - [class@Gtk.PopoverMenuBar]
/// - [class@Gtk.SearchBar]
/// - Any [class@Gtk.Box] or a similar widget with the
/// [`.toolbar`](style-classes.html#toolbars) style class
///
/// By default, top and bottom bars are flat and scrolling content has a subtle
/// undershoot shadow, same as when using the
/// [`.undershoot-top`](style-classes.html#undershot-indicators) and
/// [`.undershoot-bottom`](style-classes.html#undershot-indicators) style
/// classes. This works well in most cases, e.g. with [class@StatusPage] or
/// [class@PreferencesPage], where the background at the top and bottom parts of
/// the page is uniform. Additionally, windows with sidebars should always use
/// this style.
///
/// [property@ToolbarView:top-bar-style] and
/// [property@ToolbarView:bottom-bar-style] properties can be used add an opaque
/// background and a persistent shadow to top and bottom bars, this can be useful
/// for content such as [utility panes](https://developer.gnome.org/hig/patterns/containers/utility-panes.html),
/// where some elements are adjacent to the top/bottom bars, or [class@TabView],
/// where each page can have a different background.
///
/// <picture style="min-width: 33%; display: inline-block;"><source srcset="toolbar-view-flat-1-dark.png" media="(prefers-color-scheme: dark)"><img src="toolbar-view-flat-1.png" alt="toolbar-view-flat-1"></picture><picture style="min-width: 33%; display: inline-block;"><source srcset="toolbar-view-flat-2-dark.png" media="(prefers-color-scheme: dark)"><img src="toolbar-view-flat-2.png" alt="toolbar-view-flat-2"></picture><picture style="min-width: 33%; display: inline-block;"><source srcset="toolbar-view-raised-dark.png" media="(prefers-color-scheme: dark)"><img src="toolbar-view-raised.png" alt="toolbar-view-raised"></picture>
///
/// `AdwToolbarView` ensures the top and bottom bars have consistent backdrop
/// styles and vertical spacing. For comparison:
///
/// <picture style="min-width: 40%; display: inline-block;"><source srcset="toolbar-view-spacing-dark.png" media="(prefers-color-scheme: dark)"><img src="toolbar-view-spacing.png" alt="toolbar-view-spacing"></picture><picture style="min-width: 40%; display: inline-block;"><source srcset="toolbar-view-spacing-box-dark.png" media="(prefers-color-scheme: dark)"><img src="toolbar-view-spacing-box.png" alt="toolbar-view-spacing-box"></picture>
///
/// Any top and bottom bars can also be dragged to move the window, equivalent
/// to putting them into a [class@Gtk.WindowHandle].
///
/// Content is typically place between top and bottom bars, but can also extend
/// behind them. This is controlled with the
/// [property@ToolbarView:extend-content-to-top-edge] and
/// [property@ToolbarView:extend-content-to-bottom-edge] properties.
///
/// Top and bottom bars can be hidden and revealed with an animation using the
/// [property@ToolbarView:reveal-top-bars] and
/// [property@ToolbarView:reveal-bottom-bars] properties.
///
/// ## `AdwToolbarView` as `GtkBuildable`
///
/// The `AdwToolbarView` implementation of the [iface@Gtk.Buildable] interface
/// supports adding a top bar by specifying top as the type attribute of a
/// `<child>` element, or adding a bottom bar by specifying bottom.
///
/// ## Accessibility
///
/// `AdwToolbarView` uses the `GTK_ACCESSIBLE_ROLE_GROUP` role.
public struct ToolbarView: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The current bottom bar height.
///
/// Bottom bar height does change depending on
/// [property@ToolbarView:reveal-bottom-bars], including during the transition.
///
/// See [property@ToolbarView:top-bar-height].
var bottomBarHeight: Int?
/// The content widget.
var content: (() -> Body)?
/// Whether the content widget can extend behind bottom bars.
///
/// This can be used in combination with
/// [property@ToolbarView:reveal-bottom-bars] to show and hide toolbars in
/// fullscreen.
///
/// See [property@ToolbarView:extend-content-to-top-edge].
var extendContentToBottomEdge: Bool?
/// Whether the content widget can extend behind top bars.
///
/// This can be used in combination with [property@ToolbarView:reveal-top-bars]
/// to show and hide toolbars in fullscreen.
///
/// See [property@ToolbarView:extend-content-to-bottom-edge].
var extendContentToTopEdge: Bool?
/// Whether bottom bars are visible.
///
/// The transition will be animated.
///
/// This can be used in combination with
/// [property@ToolbarView:extend-content-to-bottom-edge] to show and hide
/// toolbars in fullscreen.
///
/// See [property@ToolbarView:reveal-top-bars].
var revealBottomBars: Bool?
/// Whether top bars are revealed.
///
/// The transition will be animated.
///
/// This can be used in combination with
/// [property@ToolbarView:extend-content-to-top-edge] to show and hide toolbars
/// in fullscreen.
///
/// See [property@ToolbarView:reveal-bottom-bars].
var revealTopBars: Bool?
/// The current top bar height.
///
/// Top bar height does change depending [property@ToolbarView:reveal-top-bars],
/// including during the transition.
///
/// See [property@ToolbarView:bottom-bar-height].
var topBarHeight: Int?
/// The body for the widget "bottom".
var bottom: () -> Body = { [] }
/// The body for the widget "top".
var top: () -> Body = { [] }
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `ToolbarView`.
public init() {
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_toolbar_view_new()?.opaque())
update(storage, modifiers: modifiers)
if let contentStorage = content?().widget(modifiers: modifiers).storage(modifiers: modifiers) {
storage.content["content"] = [contentStorage]
adw_toolbar_view_set_content(storage.pointer, contentStorage.pointer?.cast())
}
var bottomStorage: [ViewStorage] = []
for view in bottom() {
bottomStorage.append(view.storage(modifiers: modifiers))
adw_toolbar_view_add_bottom_bar(storage.pointer, bottomStorage.last?.pointer?.cast())
}
storage.content["bottom"] = bottomStorage
var topStorage: [ViewStorage] = []
for view in top() {
topStorage.append(view.storage(modifiers: modifiers))
adw_toolbar_view_add_top_bar(storage.pointer, topStorage.last?.pointer?.cast())
}
storage.content["top"] = topStorage
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
if let widget = storage.content["content"]?.first {
content?().widget(modifiers: modifiers).update(widget, modifiers: modifiers)
}
if let extendContentToBottomEdge {
adw_toolbar_view_set_extend_content_to_bottom_edge(widget, extendContentToBottomEdge.cBool)
}
if let extendContentToTopEdge {
adw_toolbar_view_set_extend_content_to_top_edge(widget, extendContentToTopEdge.cBool)
}
if let revealBottomBars {
adw_toolbar_view_set_reveal_bottom_bars(widget, revealBottomBars.cBool)
}
if let revealTopBars {
adw_toolbar_view_set_reveal_top_bars(widget, revealTopBars.cBool)
}
if let bottomStorage = storage.content["bottom"] {
for (index, view) in bottom().enumerated() {
if let storage = bottomStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
if let topStorage = storage.content["top"] {
for (index, view) in top().enumerated() {
if let storage = topStorage[safe: index] {
view.updateStorage(storage, modifiers: modifiers)
}
}
}
}
for function in updateFunctions {
function(storage)
}
}
/// The current bottom bar height.
///
/// Bottom bar height does change depending on
/// [property@ToolbarView:reveal-bottom-bars], including during the transition.
///
/// See [property@ToolbarView:top-bar-height].
public func bottomBarHeight(_ bottomBarHeight: Int?) -> Self {
var newSelf = self
newSelf.bottomBarHeight = bottomBarHeight
return newSelf
}
/// The content widget.
public func content(@ViewBuilder _ content: @escaping (() -> Body)) -> Self {
var newSelf = self
newSelf.content = content
return newSelf
}
/// Whether the content widget can extend behind bottom bars.
///
/// This can be used in combination with
/// [property@ToolbarView:reveal-bottom-bars] to show and hide toolbars in
/// fullscreen.
///
/// See [property@ToolbarView:extend-content-to-top-edge].
public func extendContentToBottomEdge(_ extendContentToBottomEdge: Bool? = true) -> Self {
var newSelf = self
newSelf.extendContentToBottomEdge = extendContentToBottomEdge
return newSelf
}
/// Whether the content widget can extend behind top bars.
///
/// This can be used in combination with [property@ToolbarView:reveal-top-bars]
/// to show and hide toolbars in fullscreen.
///
/// See [property@ToolbarView:extend-content-to-bottom-edge].
public func extendContentToTopEdge(_ extendContentToTopEdge: Bool? = true) -> Self {
var newSelf = self
newSelf.extendContentToTopEdge = extendContentToTopEdge
return newSelf
}
/// Whether bottom bars are visible.
///
/// The transition will be animated.
///
/// This can be used in combination with
/// [property@ToolbarView:extend-content-to-bottom-edge] to show and hide
/// toolbars in fullscreen.
///
/// See [property@ToolbarView:reveal-top-bars].
public func revealBottomBars(_ revealBottomBars: Bool? = true) -> Self {
var newSelf = self
newSelf.revealBottomBars = revealBottomBars
return newSelf
}
/// Whether top bars are revealed.
///
/// The transition will be animated.
///
/// This can be used in combination with
/// [property@ToolbarView:extend-content-to-top-edge] to show and hide toolbars
/// in fullscreen.
///
/// See [property@ToolbarView:reveal-bottom-bars].
public func revealTopBars(_ revealTopBars: Bool? = true) -> Self {
var newSelf = self
newSelf.revealTopBars = revealTopBars
return newSelf
}
/// The current top bar height.
///
/// Top bar height does change depending [property@ToolbarView:reveal-top-bars],
/// including during the transition.
///
/// See [property@ToolbarView:bottom-bar-height].
public func topBarHeight(_ topBarHeight: Int?) -> Self {
var newSelf = self
newSelf.topBarHeight = topBarHeight
return newSelf
}
/// Set the body for "bottom".
/// - Parameter body: The body.
/// - Returns: The widget.
public func bottom(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.bottom = body
return newSelf
}
/// Set the body for "top".
/// - Parameter body: The body.
/// - Returns: The widget.
public func top(@ViewBuilder _ body: @escaping () -> Body) -> Self {
var newSelf = self
newSelf.top = body
return newSelf
}
}

View File

@ -0,0 +1,99 @@
//
// WindowTitle.swift
// Adwaita
//
// Created by auto-generation on 22.01.24.
//
import CAdw
import LevenshteinTransformations
/// A helper widget for setting a window's title and subtitle.
///
/// <picture><source srcset="window-title-dark.png" media="(prefers-color-scheme: dark)"><img src="window-title.png" alt="window-title"></picture>
///
/// `AdwWindowTitle` shows a title and subtitle. It's intended to be used as the
/// title child of [class@Gtk.HeaderBar] or [class@HeaderBar].
///
/// ## CSS nodes
///
/// `AdwWindowTitle` has a single CSS node with name `windowtitle`.
public struct WindowTitle: Widget {
/// Additional update functions for type extensions.
var updateFunctions: [(ViewStorage) -> Void] = []
/// Additional appear functions for type extensions.
var appearFunctions: [(ViewStorage) -> Void] = []
/// The subtitle to display.
///
/// The subtitle should give the user additional details.
var subtitle: String
/// The title to display.
///
/// The title typically identifies the current view or content item, and
/// generally does not use the application name.
var title: String
/// The application.
var app: GTUIApp?
/// The window.
var window: GTUIApplicationWindow?
/// Initialize `WindowTitle`.
public init(subtitle: String, title: String) {
self.subtitle = subtitle
self.title = title
}
/// Get the widget's view storage.
/// - Parameter modifiers: The view modifiers.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let storage = ViewStorage(adw_window_title_new(title, subtitle)?.opaque())
update(storage, modifiers: modifiers)
for function in appearFunctions {
function(storage)
}
return storage
}
/// Update the widget's view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: The view modifiers.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
storage.modify { widget in
adw_window_title_set_subtitle(widget, subtitle)
adw_window_title_set_title(widget, title)
}
for function in updateFunctions {
function(storage)
}
}
/// The subtitle to display.
///
/// The subtitle should give the user additional details.
public func subtitle(_ subtitle: String) -> Self {
var newSelf = self
newSelf.subtitle = subtitle
return newSelf
}
/// The title to display.
///
/// The title typically identifies the current view or content item, and
/// generally does not use the application name.
public func title(_ title: String) -> Self {
var newSelf = self
newSelf.title = title
return newSelf
}
}

View File

@ -5,40 +5,21 @@
// Created by david-swift on 26.09.23.
//
import Libadwaita
/// A horizontal GtkBox equivalent.
public struct HStack: Widget {
public struct HStack: View {
/// The content.
var content: () -> Body
/// The view's body.
public var view: Body {
VStack(horizontal: true, content: content)
}
/// Initialize a `HStack`.
/// - Parameter content: The view content.
public init(@ViewBuilder content: @escaping () -> Body) {
self.content = content
}
/// Update a view storage.
/// - Parameters:
/// - storage: The view storage.
/// - modifiers: Modify views before being updated.
public func update(_ storage: ViewStorage, modifiers: [(View) -> View]) {
content().update(storage.content[.mainContent] ?? [], modifiers: modifiers)
}
/// Get a view storage.
/// - Parameter modifiers: Modify views before being updated.
/// - Returns: The view storage.
public func container(modifiers: [(View) -> View]) -> ViewStorage {
let box: Box = .init(horizontal: true)
var content: [ViewStorage] = []
for element in self.content() {
let widget = element.storage(modifiers: modifiers)
_ = box.append(widget.view)
content.append(widget)
}
return .init(box, content: [.mainContent: content])
}
}

Some files were not shown because too many files have changed in this diff Show More