Compare commits

..

107 Commits

Author SHA1 Message Date
Matthias Clasen
a0a3e6ffaa constraint editor: Various minor fixes 2019-07-02 22:41:07 +00:00
Matthias Clasen
bc1f2ded84 constraint editor: Allow editing children
Just name and size, for now.
2019-07-02 22:21:07 +00:00
Matthias Clasen
a5a6e90105 constraint editor: Better guide visualization
Replace the frame with a custom widget to avoid
interference from the frames own min size.
2019-07-02 21:46:38 +00:00
Matthias Clasen
b5aee936a9 Merge branch 'constraint-list-model' into 'master'
Constraint list models

See merge request GNOME/gtk!975
2019-07-02 14:18:42 +00:00
Matthias Clasen
aa8687316f constraint editor: Implement loading
Allow to reread the ui builder files we write out.
Just barely.
2019-07-02 10:03:48 -04:00
Matthias Clasen
5a3cf5a194 constraints editor: Stop naming constraints
We don't have a field for the name in ui files,
so stop naming constraints.
2019-07-02 10:03:48 -04:00
Matthias Clasen
c5e1b00994 constraint editor: Implement saving
Save to a ui file.
2019-07-02 10:03:48 -04:00
Matthias Clasen
377f0c1a0a constraint editor: Use name properties 2019-07-02 10:03:48 -04:00
Matthias Clasen
a442e6e8de constraint editor: Use the list models
Instead of handrolling our own list models,
use the ones provided by GtkConstraintLayout.
2019-07-02 10:03:48 -04:00
Matthias Clasen
274c47e5ba constraint layout: Provide list models
Provide list models for the constraints and guides,
so we can show them in the inspector, and use them
in e.g. the constraints editor.
2019-07-02 10:03:48 -04:00
Matthias Clasen
b2f15a622d Merge branch 'wip/ebassi/constraint-layout' into 'master'
Add constraint-based layout manager

Closes #1090

See merge request GNOME/gtk!973
2019-07-02 14:01:01 +00:00
Emmanuele Bassi
04aaf02881 docs: Add more private headers to the list
The various GtkConstraint private API should not be scanned for
documentation.
2019-07-02 09:48:17 +01:00
Emmanuele Bassi
d5f8e1bf29 docs: Fix typo in function name 2019-07-02 09:44:48 +01:00
Daniel Boles
33bd7051f2 widget-factory: Use correct StyleProvider priority
We are an application, not a user.

cherry-pick of !974
2019-07-02 09:09:47 +01:00
Matthias Clasen
61345b3216 Merge branch 'option-names' into 'master'
meson: Rename documentation option to gtk_doc

See merge request GNOME/gtk!972
2019-07-02 01:28:43 +00:00
Benjamin Otte
129691f3a6 flattenlistmodeL: Compute items-changed position properly
The code previously forgot to include the left child of the model's
node. Which of course only happened if that child wasn't NULL, which is
a common case.

Found and test provided by Matthias Clasen.
2019-07-02 02:53:00 +02:00
Matthias Clasen
4eaf860e86 meson: Rename documentation option to gtk_doc
This name is what most of the stack is using.
Lets follow along, even though it is (imo)
uglier.
2019-07-01 20:16:37 -04:00
Christoph Reiter
72814c54a8 meson: cups: use cups-config for looking up cups
We were looking for the cups headers and the cups lib in the default locations
which for example breaks with OpenBSD where the cups headers are under /usr/local/include/

Instead just use the "cups" dependency type from meson which internally uses cups-config.

See #1967

Ported to master from !963
2019-07-01 21:52:06 +02:00
Christoph Reiter
4d4e02c9d0 build/cups: remove checks for httpGetAuthString and http_t.authstring
httpGetAuthString() was added with cups 1.3 and we depend on a newer version
now. The direct field access was a fallback in case httpGetAuthString()
was missing, so this can also be dropped.

Ported to master from !938
2019-07-01 21:34:44 +02:00
Emmanuele Bassi
8ab609e4e7 Add custom parser for guides defined in GtkBuilder UI files
Like we describe constraints, we can also define guides.
2019-07-01 19:22:48 +01:00
Emmanuele Bassi
6bc156c237 Implement GtkBuildable for GtkConstraintLayout
Using GtkBuildable we can provide a custom parser for reading
constraints defined in a GtkBuilder UI file.
2019-07-01 18:03:20 +01:00
Emmanuele Bassi
b435dc4366 Use the right GValue getter for GtkConstraintGuide:strength
The property is defined as an enum.

This fixes the defaultvalue and notify tests.
2019-07-01 18:02:19 +01:00
Emmanuele Bassi
4dd1de4129 Use explicit values for constraint strength
Instead of playing games with mapping negative symbolic values to
positive ones, let's use the appropriate constants everywhere. This
allows us to use:

        GTK_CONSTRAINT_STRENGTH_WEAK * 2

Or

        GTK_CONSTRAINT_STRENGTH_STRONG + 1

In code using the public API.

We also store the strength values as integers, so we can compare them
properly, and only turn them into doubles when they are inserted into
the solver, just like every other variable.
2019-07-01 12:39:24 +01:00
Matthias Clasen
48e6cd4255 constraint editor: Allow dragging children
We add a weak constraint for the position
and update it as the widget is dragged.
2019-07-01 04:24:26 +00:00
Matthias Clasen
658397fad0 Documentation fixes
Make sure all types show up in the docs,
and misc other improvements.
2019-07-01 03:17:58 +00:00
Matthias Clasen
670fc5bb94 constraint editor: Enable max size for guide
Also, use the apis we have now, and make the
spin buttons display 'unset' values as such.
2019-07-01 02:23:39 +00:00
Matthias Clasen
b224df8109 constraint layout: go back to keeping constraints
We want to minimize changes to the solver, so
keep the size constraints around and only update
them when the size changes.
2019-07-01 01:54:57 +00:00
Matthias Clasen
c88e7c180d constraint layout: Use stronger force for min size
We want our edit constraint to be strong enough to
overpower nat. size constraint, therefore use STRONG * 2.
2019-07-01 01:49:20 +00:00
Emmanuele Bassi
2aabd64f1a Fix warnings from the introspection scanner
The name of the arguments of the functions must match the name of the
arguments in the documentation stanza.
2019-07-01 01:13:00 +01:00
Emmanuele Bassi
7990b24287 Add gtkconstraintguide.h to the public headers
It needs to be introspected and installed.
2019-07-01 01:12:25 +01:00
Emmanuele Bassi
c76c1a46e4 Remove specialised API from GtkConstraint
Thet widget-based API for constraint target and source properties is
unused, and not really necessary.
2019-07-01 01:05:04 +01:00
Emmanuele Bassi
68fed63eac Add missing documentation for GtkConstraint 2019-07-01 01:02:56 +01:00
Emmanuele Bassi
46403bac12 docs: Add GtkConstraint and friends to the API reference 2019-07-01 00:49:20 +01:00
Emmanuele Bassi
74c626f835 Document GtkConstraintGuide 2019-07-01 00:48:59 +01:00
Emmanuele Bassi
d45a662679 Move the VFL error domain to a public header
Since the public API will use it to fill out GErrors, it needs to be
publicly available.
2019-07-01 00:48:48 +01:00
Matthias Clasen
f6019f1a16 Merge branch 'gbsneto/fix-popover-dark-theme' into 'master'
Fix GtkPopoverMenu in dark theme

See merge request GNOME/gtk!970
2019-06-30 23:17:40 +00:00
Matthias Clasen
514de0b91a Add a constraint editor demo
This is an initial cut at providing a tool
for interactive exploration of constraints.
2019-07-01 00:10:11 +01:00
Emmanuele Bassi
9a463056d0 constraint layout: Notice when guides change
We need to queue a resize here.
2019-07-01 00:10:11 +01:00
Matthias Clasen
035baa092c Mark the layout as changed
We should mark the layout as changed when
constraints are added or removed.
2019-07-01 00:10:11 +01:00
Matthias Clasen
499738c903 constraint guide: Avoid redundant constraints
There is no point in creating a stay for nat
size when min == max. And no point in a constraint
for <= G_MAXINT either.
2019-07-01 00:10:11 +01:00
Matthias Clasen
f2d7433bf6 constraint guide: Fix initial property values
This was overlooked when the max-width/max-height/
strength properties were added.
2019-07-01 00:10:11 +01:00
Matthias Clasen
405121bccc constraint solver: Use GTK_NOTE
Allow using GTK_DEBUG=constraints to get debug
output from the constraints solver.
2019-07-01 00:10:11 +01:00
Matthias Clasen
cb96b34315 solver: Add private statistics api
No point in keeping these counters without
a way to show them.
2019-07-01 00:10:11 +01:00
Matthias Clasen
9edf6fb6cb constraint layout: Dont reset constraints in allocate
If trust our allocation algorithm, this can never
trigger (and in fact, it never does).
2019-07-01 00:10:11 +01:00
Matthias Clasen
e3c4fb67ca constraints: Add some internal apis
Checking if a set is empty or a singleton can
be done more efficiently than determining its size.
2019-07-01 00:10:11 +01:00
Matthias Clasen
a9dfca04e4 constraint guide: Make strength tweakable
The strength for the natural width can be used
as a tie-breaker to make instable systems behave
in a more predictable way. This can be seen
in the simple constraints demo in gtk-demo.
2019-07-01 00:10:11 +01:00
Matthias Clasen
71b52f485e constraints demo: Update comments 2019-07-01 00:10:11 +01:00
Matthias Clasen
f62fc4e2f2 constraint layout: freeze/thaw on mass ops
In measure and allocate we are potentially
changing quite a few constraints. Don't
optimize at every step.
2019-07-01 00:10:11 +01:00
Matthias Clasen
511e2b435e constraints: Use better data structures
Use a GSequence for GtkVariableSet, to avoid
quadratic behavior.
2019-07-01 00:10:11 +01:00
Matthias Clasen
3f36340921 constraint layout: Measure min/nat size separately
Only constraint the opposite direction if we
actually have a for_size, and measure natural
size after removing the edit constraints. With
these changes, the test that compares constraint
layout to grid layout passes.
2019-07-01 00:10:11 +01:00
Matthias Clasen
b1f0f4478e constraint layout: Use stays for natural size
It makes more sense to treat the natural size
of both children and guides as stays, since
we want to meet these values as closely as we
can, under the circumstances.
2019-07-01 00:10:11 +01:00
Matthias Clasen
90f8dcc5e1 constraint layout: Add debug output for guides
Print out the allocation we end up giving to
guides. This helps in making sense of the
allocations of the child widgets that these
guides relate to.
2019-07-01 00:10:11 +01:00
Matthias Clasen
5a019bfccd constraints demo: Give space a name
Lets call it 'space'.
2019-07-01 00:10:11 +01:00
Matthias Clasen
b39a5fe5dc constraint guide: Add a name property
We need to be able to print meaningful debug messages
regarding these objects, and eventually present them
in the inspector too.
2019-07-01 00:10:11 +01:00
Matthias Clasen
c7ef8411bd constraint guide: Shorten names
Now that this is its own source file,
no need for these prefixes anymore.
2019-07-01 00:10:11 +01:00
Matthias Clasen
dab8a8b5c5 constraint layout: Measure more correctly
Set up all constraints for minimum + natural
width + height when measuring, regardless
of the orientation we're measuring. Anything
else will lead to incorrect answers when
there are constraints that cut across
dimensions.
2019-07-01 00:10:11 +01:00
Matthias Clasen
8b9c5e3a04 solver: Fix a copy/paste error 2019-07-01 00:10:11 +01:00
Matthias Clasen
3d3a672deb constraint solver: Fix repeat suggestions
We were not storing the previous value, causing
the first two suggestions to work, but not later
ones.

Fixes the test added in the previous commit.
2019-07-01 00:10:11 +01:00
Matthias Clasen
2f97134a08 Amend a constraint solver test
Make the 'repeat edit' test make more than to
suggestions in a single edit phase. It turns out
that this does not work, whereas just doing
two in a row does.
2019-07-01 00:10:11 +01:00
Matthias Clasen
47237d32eb demo: Use constraint guide api
Use proper api to create and set up
the guide, and also try max-width.
2019-07-01 00:10:11 +01:00
Matthias Clasen
139a59cae3 Flesh out GtkConstraintGuide
This commit moves GtkConstraintGuide into its own
source files to avoid gtkconstraintlayout.c turning
too messy, adds max size properties and implements
getters and setters.
2019-07-01 00:10:11 +01:00
Matthias Clasen
60fb9092fe Drop an indirection
This struct is not really useful for just
a single hash table, and it gets in the way
of moving the guide code to its own file.
2019-07-01 00:10:11 +01:00
Matthias Clasen
61b4febbaf Detach guides on unroot
We don't want to leave constraints behind.
2019-07-01 00:10:11 +01:00
Matthias Clasen
4f4ba8c4f6 Simplify the guide implementation
Store the values and constraints in
arrays, to facilitate treating them
uniformly.
2019-07-01 00:10:11 +01:00
Emmanuele Bassi
651adbfb39 Return the list of constraints added via VFL description
Otherwise it's impossible to remove them.
2019-07-01 00:10:11 +01:00
Emmanuele Bassi
3204347bb0 Add method to remove all constraints from a layout 2019-07-01 00:10:11 +01:00
Georges Basile Stavracas Neto
b929846cc1 Adwaita: Also apply $color_menu to popover arrows
So that popovers and arrows are always in agreement of
the background color.
2019-06-30 19:51:51 -03:00
Georges Basile Stavracas Neto
fe65da05be Adwaita: Use $menu_color background in popover.menu
GtkPopoverMenus should mimic menus. Commit d936967b7a introduced
some CSS related to menu popovers, however, it hardcodes 'white'
as the background color. That is problematic for the dark theme.

Use '$menu_color' instead of 'white', since $menu_color both
guarantees menu popovers and menus match, and already handles
different colors for dark and light theme variants.
2019-06-30 19:47:32 -03:00
Emmanuele Bassi
06c825df90 Add a C convenience function for VFL constraints
The dictionary-based function is convenient for language bindings, but C
developers will feel more at home with a variadic arguments list.
2019-06-30 23:42:45 +01:00
Emmanuele Bassi
46430ea85b Add Constraints/VFL demo
Shows how to describe constraints using VFL instead of constructing
objects manually.
2019-06-30 23:42:45 +01:00
Emmanuele Bassi
859c95b435 Allow adding constraints described through VFL 2019-06-30 23:42:45 +01:00
Emmanuele Bassi
5ea8167802 Add VFL parser for constraints
Constraints can be expressed with a compact syntax, called VFL (visual
format language).
2019-06-30 23:42:45 +01:00
Emmanuele Bassi
92d3d55164 Remove GtkConstraintVariable.set_prefix()
The prefix and name are set at construction time.
2019-06-30 23:42:45 +01:00
Matthias Clasen
ba2125d8e1 Add an interactive constraints demo 2019-06-30 23:42:44 +01:00
Matthias Clasen
7c96326c18 Make the constraints demo more interesting
Add a max size to the buttons, to force the
space to open up.
2019-06-30 23:42:44 +01:00
Matthias Clasen
38d353dc1a Add GtkConstraintGuide
This is meant to be a flexible space.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi
7ae04ba36b Use generic pointers for constraint targets
Since GtkWidget implements GtkConstraintTarget, we can omit the explicit
cast, and validate the type at run time.
2019-06-30 23:42:44 +01:00
Matthias Clasen
39c284c490 Redefine constraints with GtkConstraintTarget
This is in preparation for allowing non-widgets
to act as constraint targets.
2019-06-30 23:42:44 +01:00
Matthias Clasen
895e8e25a8 widget: Implement GtkConstraintTarget 2019-06-30 23:42:44 +01:00
Matthias Clasen
04562a76e3 Add GtkConstraintTarget
This is an marker interface that we will
use to accept other things that widgets
in constraints.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi
b6781e06c1 Notify a layout change when adding and removing constraints
Changing the set of constraints should cause a relayout.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi
54104b6676 Fix the opposite size measurement in GtkConstraintLayout
We cannot use the given "for size" when querying our children, because
the constraint layout has no idea about the opposite size of its
children until the layout is complete.

Additionally, we should only suggest an opposite size for the layout if
we have one, instead of suggesting a weak zero size.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi
21450d5f23 Remove size constraints from ConstraintLayoutChild
The size constraints are transient to measurement and allocation, so
they don't really need to be stored inside the GtkLayoutChild subclass
created by a GtkConstraintLayout.
2019-06-30 23:42:44 +01:00
Matthias Clasen
a39bbb2041 constraints: Make internal consistency required
The relations between left, right, width
and top, bottom, height are required for
internal consistency. It doesn't make sense
to ever drop these.

Changing the strength of these relations makes
my systems behave much more stable.
2019-06-30 23:42:44 +01:00
Matthias Clasen
176d9c6baf Add gtk_constraint_layout_remove_constraint
Otherwise, you can't do many interesting things.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi
64afa765c8 Do not release reference on the subject of an expression
We don't own the reference in the first place.
2019-06-30 23:42:44 +01:00
Matthias Clasen
a246d8c926 constraints solver: Avoid critials
When the solver is finalized with existing
constraints, we end up with criticals when
the constraints ref finalize code calls
back into the hash table. Avoid that by
emptying the hash table beforehand.
2019-06-30 23:42:44 +01:00
Matthias Clasen
0531e663ee constraint solver: Fix thawing
There was an obviously wrong precondition here.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi
bd2349c0a0 Do not leak LayoutChild instances
Since the LayoutManager owns the LayoutChild it creates, it's also
responsible for mopping them up.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi
636fbc0f1a Add GtkConstraintLayout demo 2019-06-30 23:42:44 +01:00
Emmanuele Bassi
cdf80f1d65 Add GtkConstraintLayout
A layout manager using GtkConstraintSolver to measure and allocate
children.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi
e7b2c530c5 Propagate rooting and unrooting widgets to layout managers
Layout managers may need to get access to data attached to the root of a
scene graph.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi
e07098da03 window: Create a GtkConstraintSolver
Implement the GtkRoot getter for GtkConstraintSolver.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi
98a21bf498 Assign a GtkConstraintSolver to each GtkRoot
Constraints need to work across different parents, so it's better to
have a single constraint solver per top level.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi
c694dd6049 Move the Root interface to a private header
We don't expect out of tree implementations of GtkRoot, and having the
interface structure private to the GTK code allows us to add virtual
functions involving private types.
2019-06-30 23:42:44 +01:00
Emmanuele Bassi
6b308cd71e Add constraint solver
GtkConstraintSolver is an implementation of the Cassowary constraint
solving algorithm:

  http://constraints.cs.washington.edu/cassowary/

The Cassowary method allows to incrementally solve a tableau of linear
equations, in the form of:

  x = y × coefficient + constant

with different weights, or strengths, applied to each one.

These equations can be used to describe constraints applied to a layout
of UI elements, which allows layout managers using the Cassowary method
to quickly, and efficiently, lay out widgets in complex relations
between themselves and their parent container.
2019-06-30 23:42:44 +01:00
Matthias Clasen
3b6ee32f83 Fix a crash in action muxer destruction
I've seen a crash when the action muxer gets
disposed during widget destroy, and tries to
disconnect from widget signals too late.

There is no real need to disconnect, since the
only time an action muxer is going away is when
its widget is destroyed, so just don't do it.
2019-06-30 18:37:32 +00:00
Timm Bäder
3bc3e140dd transform: Add transform_bounds fast path for 2D_AFFINE transforms
E.g. anything involving a scale. This is important when e.g. scrolling
in the node list in the recorder, which scales every recorded node down
to fit in the list.
2019-06-29 09:49:38 +02:00
Timm Bäder
a6a9853676 Adwaita: Fix popover style
We add the .background class to the popover node now.
2019-06-29 09:06:32 +02:00
Timm Bäder
6b42e5b433 gl renderer: Fix push/pop modelview behavior 2019-06-29 08:57:27 +02:00
Timm Bäder
99c01607f1 gl renderer: Remove some dead code 2019-06-29 08:53:36 +02:00
Timm Bäder
071748592d gl renderer: Don't upload GL textures into the icon cache 2019-06-29 07:15:43 +02:00
Timm Bäder
8dd74eac2e transform: Add skew parsing 2019-06-29 07:15:43 +02:00
Matthias Clasen
f6a2678486 Add another grid layout test
This one will be used for comparison
with constraint layouts.
2019-06-28 19:21:21 +00:00
Matthias Clasen
e28ec2a3eb Some more grid layout tests
Add testcases for spanning children and homogeneity.
2019-06-28 18:07:23 +00:00
Matthias Clasen
c4fd786866 Add a test for the grid layout manager
Test some obvious conditions. This is mainly
to test the waters for more intesting tests
with other layout managers later.
2019-06-28 13:30:16 +00:00
Matthias Clasen
8fa7de5563 grid layout: Fix initial property values
Too bad that we don't cover layout children
in the default value test - it would have
caught this.
2019-06-28 12:42:06 +00:00
65 changed files with 4701 additions and 1455 deletions

View File

@@ -105,7 +105,7 @@ pages:
image: registry.gitlab.gnome.org/gnome/gtk/master:v6
stage: deploy
script:
- meson -Ddocumentation=true _build .
- meson -Dgtk_doc=true _build .
- ninja -C _build
- ninja -C _build gdk4-doc gsk4-doc gtk4-doc

View File

@@ -56,12 +56,6 @@
/* Define if GStreamer support is available */
#mesondefine HAVE_GSTREAMER
/* Define to 1 if you have the `httpGetAuthString' function. */
#mesondefine HAVE_HTTPGETAUTHSTRING
/* Define if cups http_t authstring field is accessible */
#mesondefine HAVE_HTTP_AUTHSTRING
/* Define to 1 if you have the <inttypes.h> header file. */
#mesondefine HAVE_INTTYPES_H

View File

@@ -0,0 +1,262 @@
/*
* Copyright © 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen
*/
#include "config.h"
#include "child-editor.h"
struct _ChildEditor
{
GtkWidget parent_instance;
GtkWidget *grid;
GtkWidget *name;
GtkWidget *min_width;
GtkWidget *min_height;
GtkWidget *button;
GtkWidget *child;
gboolean constructed;
};
enum {
PROP_CHILD = 1,
LAST_PROP
};
static GParamSpec *pspecs[LAST_PROP];
enum {
DONE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE(ChildEditor, child_editor, GTK_TYPE_WIDGET);
void
child_editor_serialize_child (GString *str,
int indent,
GtkWidget *child)
{
int min_width, min_height;
const char *name;
name = gtk_widget_get_name (child);
if (!name)
name = "";
gtk_widget_get_size_request (child, &min_width, &min_height);
g_string_append_printf (str, "%*s<child>\n", indent, "");
g_string_append_printf (str, "%*s <object class=\"GtkLabel\" id=\"%s\">\n", indent, "", name);
g_string_append_printf (str, "%*s <property name=\"label\">%s</property>\n", indent, "", name);
if (min_width != -1)
g_string_append_printf (str, "%*s <property name=\"width-request\">%d</property>\n", indent, "", min_width);
if (min_height != -1)
g_string_append_printf (str, "%*s <property name=\"height-request\">%d</property>\n", indent, "", min_height);
g_string_append_printf (str, "%*s </object>\n", indent, "");
g_string_append_printf (str, "%*s</child>\n", indent, "");
}
static void
apply (GtkButton *button,
ChildEditor *editor)
{
const char *name;
int w, h;
name = gtk_editable_get_text (GTK_EDITABLE (editor->name));
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_height));
gtk_widget_set_size_request (editor->child, w, h);
gtk_widget_set_name (editor->child, name);
g_signal_emit (editor, signals[DONE], 0, editor->child);
}
static void
child_editor_init (ChildEditor *editor)
{
gtk_widget_init_template (GTK_WIDGET (editor));
}
static int
min_input (GtkSpinButton *spin_button,
double *new_val)
{
if (strcmp (gtk_editable_get_text (GTK_EDITABLE (spin_button)), "") == 0)
{
*new_val = 0.0;
return TRUE;
}
return FALSE;
}
static gboolean
min_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
double value;
GtkWidget *box, *text;
adjustment = gtk_spin_button_get_adjustment (spin_button);
value = gtk_adjustment_get_value (adjustment);
box = gtk_widget_get_first_child (GTK_WIDGET (spin_button));
text = gtk_widget_get_first_child (box);
if (value <= 0.0)
{
gtk_editable_set_text (GTK_EDITABLE (spin_button), "");
gtk_text_set_placeholder_text (GTK_TEXT (text), "unset");
return TRUE;
}
else
{
gtk_text_set_placeholder_text (GTK_TEXT (text), "");
return FALSE;
}
}
static void
child_editor_constructed (GObject *object)
{
ChildEditor *editor = CHILD_EDITOR (object);
const char *nick;
int w, h;
g_signal_connect (editor->min_width, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->min_width, "output", G_CALLBACK (min_output), NULL);
g_signal_connect (editor->min_height, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->min_height, "output", G_CALLBACK (min_output), NULL);
nick = gtk_widget_get_name (editor->child);
if (nick)
gtk_editable_set_text (GTK_EDITABLE (editor->name), nick);
gtk_widget_get_size_request (editor->child, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), h);
editor->constructed = TRUE;
}
static void
child_editor_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
ChildEditor *self = CHILD_EDITOR (object);
switch (property_id)
{
case PROP_CHILD:
self->child = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
child_editor_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
ChildEditor *self = CHILD_EDITOR (object);
switch (property_id)
{
case PROP_CHILD:
g_value_set_object (value, self->child);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
child_editor_dispose (GObject *object)
{
ChildEditor *self = (ChildEditor *)object;
g_clear_pointer (&self->grid, gtk_widget_unparent);
g_clear_object (&self->child);
G_OBJECT_CLASS (child_editor_parent_class)->dispose (object);
}
static void
child_editor_class_init (ChildEditorClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->constructed = child_editor_constructed;
object_class->dispose = child_editor_dispose;
object_class->set_property = child_editor_set_property;
object_class->get_property = child_editor_get_property;
pspecs[PROP_CHILD] =
g_param_spec_object ("child", "child", "child",
GTK_TYPE_WIDGET,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, LAST_PROP, pspecs);
signals[DONE] =
g_signal_new ("done",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/constraint-editor/child-editor.ui");
gtk_widget_class_bind_template_child (widget_class, ChildEditor, grid);
gtk_widget_class_bind_template_child (widget_class, ChildEditor, name);
gtk_widget_class_bind_template_child (widget_class, ChildEditor, min_width);
gtk_widget_class_bind_template_child (widget_class, ChildEditor, min_height);
gtk_widget_class_bind_template_child (widget_class, ChildEditor, button);
gtk_widget_class_bind_template_callback (widget_class, apply);
}
ChildEditor *
child_editor_new (GtkWidget *child)
{
return g_object_new (CHILD_EDITOR_TYPE,
"child", child,
NULL);
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright © 2019 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen
*/
#pragma once
#include <gtk/gtk.h>
#define CHILD_EDITOR_TYPE (child_editor_get_type ())
G_DECLARE_FINAL_TYPE (ChildEditor, child_editor, CHILD, EDITOR, GtkWidget)
ChildEditor * child_editor_new (GtkWidget *child);
void child_editor_serialize_child (GString *str,
int indent,
GtkWidget *child);

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkAdjustment" id="min_width_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="min_height_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<template class="ChildEditor" parent="GtkWidget">
<child>
<object class="GtkGrid" id="grid">
<property name="margin">20</property>
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<child>
<object class="GtkLabel">
<property name="label">Name</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="name">
<property name="max-width-chars">20</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Min Size</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="min_width">
<property name="adjustment">min_width_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="min_height">
<property name="adjustment">min_height_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton" id="button">
<property name="label">Apply</property>
<signal name="clicked" handler="apply"/>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">5</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -51,6 +51,7 @@ static void
constraint_editor_application_startup (GApplication *app)
{
const char *quit_accels[2] = { "<Ctrl>Q", NULL };
const char *open_accels[2] = { "<Ctrl>O", NULL };
GtkCssProvider *provider;
G_APPLICATION_CLASS (constraint_editor_application_parent_class)->startup (app);
@@ -59,6 +60,7 @@ constraint_editor_application_startup (GApplication *app)
app_entries, G_N_ELEMENTS (app_entries),
app);
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "app.quit", quit_accels);
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "win.open", open_accels);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/org/gtk/gtk4/constraint-editor/constraint-editor.css");
@@ -76,6 +78,23 @@ constraint_editor_application_activate (GApplication *app)
gtk_window_present (GTK_WINDOW (win));
}
static void
constraint_editor_application_open (GApplication *app,
GFile **files,
gint n_files,
const gchar *hint)
{
ConstraintEditorWindow *win;
gint i;
for (i = 0; i < n_files; i++)
{
win = constraint_editor_window_new (CONSTRAINT_EDITOR_APPLICATION (app));
constraint_editor_window_load (win, files[i]);
gtk_window_present (GTK_WINDOW (win));
}
}
static void
constraint_editor_application_class_init (ConstraintEditorApplicationClass *class)
{
@@ -83,6 +102,7 @@ constraint_editor_application_class_init (ConstraintEditorApplicationClass *clas
application_class->startup = constraint_editor_application_startup;
application_class->activate = constraint_editor_application_activate;
application_class->open = constraint_editor_application_open;
}
ConstraintEditorApplication *
@@ -90,5 +110,6 @@ constraint_editor_application_new (void)
{
return g_object_new (CONSTRAINT_EDITOR_APPLICATION_TYPE,
"application-id", "org.gtk.gtk4.ConstraintEditor",
"flags", G_APPLICATION_HANDLES_OPEN,
NULL);
}

View File

@@ -23,6 +23,7 @@
#include "constraint-view.h"
#include "constraint-editor.h"
#include "guide-editor.h"
#include "child-editor.h"
struct _ConstraintEditorWindow
{
@@ -35,36 +36,307 @@ struct _ConstraintEditorWindow
G_DEFINE_TYPE(ConstraintEditorWindow, constraint_editor_window, GTK_TYPE_APPLICATION_WINDOW);
static GtkConstraintTarget *
find_target (GListModel *model,
GtkConstraintTarget *orig)
{
const char *name;
const char *model_name;
gpointer item;
int i;
if (orig == NULL)
return NULL;
if (GTK_IS_LABEL (orig))
name = gtk_label_get_label (GTK_LABEL (orig));
else if (GTK_IS_CONSTRAINT_GUIDE (orig))
name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (orig));
else
{
g_warning ("Don't know how to handle %s targets", G_OBJECT_TYPE_NAME (orig));
return NULL;
}
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
item = g_list_model_get_item (model, i);
g_object_unref (item);
if (GTK_IS_WIDGET (item))
model_name = gtk_widget_get_name (GTK_WIDGET (item));
else
model_name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item));
if (strcmp (name, model_name) == 0)
return GTK_CONSTRAINT_TARGET (item);
}
g_warning ("Failed to find target '%s'", name);
return NULL;
}
gboolean
constraint_editor_window_load (ConstraintEditorWindow *self,
GFile *file)
{
GBytes *bytes;
char *path;
GtkBuilder *builder;
GError *error = NULL;
GtkWidget *view;
GtkLayoutManager *layout;
GtkWidget *child;
const char *name;
gpointer item;
int i;
GListModel *list;
bytes = g_file_load_bytes (file, NULL, NULL, NULL);
if (bytes == NULL)
return FALSE;
path = g_file_get_path (file);
if (!g_utf8_validate (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL))
builder = gtk_builder_new ();
if (!gtk_builder_add_from_file (builder, path, &error))
{
g_bytes_unref (bytes);
g_print ("Could not load %s: %s", path, error->message);
g_error_free (error);
g_free (path);
g_object_unref (builder);
return FALSE;
}
#if 0
view = GTK_WIDGET (gtk_builder_get_object (builder, "view"));
if (!GTK_IS_BOX (view))
{
g_print ("Could not load %s: No GtkBox named 'view'", path);
g_free (path);
g_object_unref (builder);
return FALSE;
}
layout = gtk_widget_get_layout_manager (view);
if (!GTK_IS_CONSTRAINT_LAYOUT (layout))
{
g_print ("Could not load %s: Widget 'view' does not use GtkConstraintLayout", path);
g_free (path);
g_object_unref (builder);
return FALSE;
}
gtk_text_buffer_get_end_iter (self->text_buffer, &end);
gtk_text_buffer_insert (self->text_buffer,
&end,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
#endif
for (child = gtk_widget_get_first_child (view);
child;
child = gtk_widget_get_next_sibling (child))
{
if (!GTK_IS_LABEL (child))
{
g_print ("Skipping non-GtkLabel child\n");
continue;
}
g_bytes_unref (bytes);
name = gtk_label_get_label (GTK_LABEL (child));
constraint_view_add_child (CONSTRAINT_VIEW (self->view), name);
}
list = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (layout));
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
GtkConstraintGuide *guide, *clone;
int w, h;
item = g_list_model_get_item (list, i);
guide = GTK_CONSTRAINT_GUIDE (item);
/* need to clone here, to attach to the right targets */
clone = gtk_constraint_guide_new ();
gtk_constraint_guide_set_name (clone, gtk_constraint_guide_get_name (guide));
gtk_constraint_guide_set_strength (clone, gtk_constraint_guide_get_strength (guide));
gtk_constraint_guide_get_min_size (guide, &w, &h);
gtk_constraint_guide_set_min_size (clone, w, h);
gtk_constraint_guide_get_nat_size (guide, &w, &h);
gtk_constraint_guide_set_nat_size (clone, w, h);
gtk_constraint_guide_get_max_size (guide, &w, &h);
gtk_constraint_guide_set_max_size (clone, w, h);
constraint_view_add_guide (CONSTRAINT_VIEW (self->view), clone);
g_object_unref (guide);
g_object_unref (clone);
}
g_object_unref (list);
list = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (layout));
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
GtkConstraint *constraint;
GtkConstraint *clone;
GtkConstraintTarget *target;
GtkConstraintTarget *source;
item = g_list_model_get_item (list, i);
constraint = GTK_CONSTRAINT (item);
target = gtk_constraint_get_target (constraint);
source = gtk_constraint_get_source (constraint);
clone = gtk_constraint_new (find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), target),
gtk_constraint_get_target_attribute (constraint),
gtk_constraint_get_relation (constraint),
find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), source),
gtk_constraint_get_target_attribute (constraint),
gtk_constraint_get_multiplier (constraint),
gtk_constraint_get_constant (constraint),
gtk_constraint_get_strength (constraint));
constraint_view_add_constraint (CONSTRAINT_VIEW (self->view), clone);
g_object_unref (constraint);
g_object_unref (clone);
}
g_object_unref (list);
g_free (path);
g_object_unref (builder);
return TRUE;
}
static void
open_response_cb (GtkNativeDialog *dialog,
gint response,
ConstraintEditorWindow *self)
{
gtk_native_dialog_hide (dialog);
if (response == GTK_RESPONSE_ACCEPT)
{
GFile *file;
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
constraint_editor_window_load (self, file);
g_object_unref (file);
}
gtk_native_dialog_destroy (dialog);
}
static void
open_cb (GtkWidget *button,
ConstraintEditorWindow *self)
{
GtkFileChooserNative *dialog;
dialog = gtk_file_chooser_native_new ("Open file",
GTK_WINDOW (self),
GTK_FILE_CHOOSER_ACTION_OPEN,
"_Load",
"_Cancel");
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), ".");
g_signal_connect (dialog, "response", G_CALLBACK (open_response_cb), self);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
}
static void
serialize_child (GString *str,
int indent,
GtkWidget *child)
{
const char *name;
name = gtk_widget_get_name (child);
g_string_append_printf (str, "%*s<child>\n", indent, "");
g_string_append_printf (str, "%*s <object class=\"GtkLabel\" id=\"%s\">\n", indent, "", name);
g_string_append_printf (str, "%*s <property name=\"label\">%s</property>\n", indent, "", name);
g_string_append_printf (str, "%*s </object>\n", indent, "");
g_string_append_printf (str, "%*s</child>\n", indent, "");
}
static char *
serialize_model (GListModel *list)
{
GString *str = g_string_new ("");
int i;
g_string_append (str, "<interface>\n");
g_string_append (str, " <object class=\"GtkBox\" id=\"view\">\n");
g_string_append (str, " <property name=\"layout-manager\">\n");
g_string_append (str, " <object class=\"GtkConstraintLayout\">\n");
g_string_append (str, " <constraints>\n");
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
gpointer item = g_list_model_get_item (list, i);
g_object_unref (item);
if (GTK_IS_CONSTRAINT (item))
constraint_editor_serialize_constraint (str, 10, GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
guide_editor_serialize_guide (str, 10, GTK_CONSTRAINT_GUIDE (item));
}
g_string_append (str, " </constraints>\n");
g_string_append (str, " </object>\n");
g_string_append (str, " </property>\n");
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
gpointer item = g_list_model_get_item (list, i);
g_object_unref (item);
if (GTK_IS_WIDGET (item))
serialize_child (str, 4, GTK_WIDGET (item));
}
g_string_append (str, " </object>\n");
g_string_append (str, "</interface>\n");
return g_string_free (str, FALSE);
}
static void
save_response_cb (GtkNativeDialog *dialog,
gint response,
ConstraintEditorWindow *self)
{
gtk_native_dialog_hide (dialog);
if (response == GTK_RESPONSE_ACCEPT)
{
GListModel *model;
char *text, *filename;
GError *error = NULL;
model = constraint_view_get_model (CONSTRAINT_VIEW (self->view));
text = serialize_model (model);
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
if (!g_file_set_contents (filename, text, -1, &error))
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))),
GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"Saving failed");
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", error->message);
g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
g_error_free (error);
}
g_free (filename);
}
gtk_native_dialog_destroy (dialog);
}
static void
save_cb (GtkWidget *button,
ConstraintEditorWindow *self)
{
GtkFileChooserNative *dialog;
dialog = gtk_file_chooser_native_new ("Save constraints",
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (button))),
GTK_FILE_CHOOSER_ACTION_SAVE,
"_Save",
"_Cancel");
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), ".");
g_signal_connect (dialog, "response", G_CALLBACK (save_response_cb), self);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
}
static void
constraint_editor_window_finalize (GObject *object)
{
@@ -95,8 +367,10 @@ add_guide (ConstraintEditorWindow *win)
guide_counter++;
name = g_strdup_printf ("Guide %d", guide_counter);
guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL);
g_object_set_data_full (G_OBJECT (guide), "name", name, g_free);
guide = gtk_constraint_guide_new ();
gtk_constraint_guide_set_name (guide, name);
gtk_constraint_guide_set_min_size (guide, 100, 25);
g_free (name);
constraint_view_add_guide (CONSTRAINT_VIEW (win->view), guide);
}
@@ -158,7 +432,6 @@ guide_editor_done (GuideEditor *editor,
GtkConstraintGuide *guide,
ConstraintEditorWindow *win)
{
constraint_view_guide_changed (CONSTRAINT_VIEW (win->view), guide);
gtk_widget_destroy (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW));
}
@@ -181,6 +454,33 @@ edit_guide (ConstraintEditorWindow *win,
gtk_widget_show (window);
}
static void
child_editor_done (ChildEditor *editor,
GtkWidget *child,
ConstraintEditorWindow *win)
{
gtk_widget_destroy (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW));
}
static void
edit_child (ConstraintEditorWindow *win,
GtkWidget *child)
{
GtkWidget *window;
ChildEditor *editor;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win));
gtk_window_set_title (GTK_WINDOW (window), "Edit Child");
editor = child_editor_new (child);
gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (editor));
g_signal_connect (editor, "done", G_CALLBACK (child_editor_done), win);
gtk_widget_show (window);
}
static void
row_activated (GtkListBox *list,
GtkListBoxRow *row,
@@ -194,6 +494,8 @@ row_activated (GtkListBox *list,
edit_constraint (win, GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
edit_guide (win, GTK_CONSTRAINT_GUIDE (item));
else if (GTK_IS_WIDGET (item))
edit_child (win, GTK_WIDGET (item));
}
static void
@@ -213,6 +515,8 @@ constraint_editor_window_class_init (ConstraintEditorWindowClass *class)
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, view);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, list);
gtk_widget_class_bind_template_callback (widget_class, open_cb);
gtk_widget_class_bind_template_callback (widget_class, save_cb);
gtk_widget_class_bind_template_callback (widget_class, add_child);
gtk_widget_class_bind_template_callback (widget_class, add_guide);
gtk_widget_class_bind_template_callback (widget_class, add_constraint);
@@ -232,6 +536,8 @@ row_edit (GtkButton *button,
edit_constraint (win, GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
edit_guide (win, GTK_CONSTRAINT_GUIDE (item));
else if (GTK_IS_WIDGET (item))
edit_child (win, GTK_WIDGET (item));
}
static void
@@ -294,41 +600,43 @@ create_widget_func (gpointer item,
{
ConstraintEditorWindow *win = user_data;
const char *name;
char *freeme = NULL;
GtkWidget *row, *box, *label, *button;
name = (const char *)g_object_get_data (G_OBJECT (item), "name");
if (GTK_IS_WIDGET (item))
name = gtk_widget_get_name (GTK_WIDGET (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item));
else if (GTK_IS_CONSTRAINT (item))
name = freeme = constraint_editor_constraint_to_string (GTK_CONSTRAINT (item));
else
name = "";
row = gtk_list_box_row_new ();
g_object_set_data (G_OBJECT (row), "item", item);
g_object_set_data_full (G_OBJECT (row), "item", g_object_ref (item), g_object_unref);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
label = gtk_label_new (name);
g_object_set (label,
"margin", 10,
NULL);
if (GTK_IS_WIDGET (item) || GTK_IS_CONSTRAINT_GUIDE (item))
g_object_bind_property (item, "name",
label, "label",
G_BINDING_DEFAULT);
g_object_set (label, "margin", 10, NULL);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_widget_set_hexpand (label, TRUE);
gtk_container_add (GTK_CONTAINER (row), box);
gtk_container_add (GTK_CONTAINER (box), label);
if (GTK_IS_CONSTRAINT (item) || GTK_IS_CONSTRAINT_GUIDE (item))
{
button = gtk_button_new_from_icon_name ("document-edit-symbolic");
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_edit), win);
g_object_set_data (G_OBJECT (row), "edit", button);
gtk_container_add (GTK_CONTAINER (box), button);
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
gtk_container_add (GTK_CONTAINER (box), button);
}
else if (GTK_IS_WIDGET (item))
{
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
gtk_container_add (GTK_CONTAINER (box), button);
}
button = gtk_button_new_from_icon_name ("document-edit-symbolic");
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_edit), win);
g_object_set_data (G_OBJECT (row), "edit", button);
gtk_container_add (GTK_CONTAINER (box), button);
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
gtk_container_add (GTK_CONTAINER (box), button);
g_free (freeme);
return row;
}

View File

@@ -11,6 +11,20 @@
<object class="GtkHeaderBar" id="header">
<property name="title" translatable="yes">GTK Constraint Editor</property>
<property name="show-title-buttons">1</property>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-open-symbolic</property>
<property name="tooltip-text">Open ui file</property>
<signal name="clicked" handler="open_cb"/>
</object>
</child>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-save-symbolic</property>
<property name="tooltip-text">Save to ui file</property>
<signal name="clicked" handler="save_cb"/>
</object>
</child>
</object>
</child>
<child>

View File

@@ -26,7 +26,6 @@ struct _ConstraintEditor
GtkWidget parent_instance;
GtkWidget *grid;
GtkWidget *name;
GtkWidget *target;
GtkWidget *target_attr;
GtkWidget *relation;
@@ -66,8 +65,12 @@ get_target_name (GtkConstraintTarget *target)
{
if (target == NULL)
return "super";
else if (GTK_IS_WIDGET (target))
return gtk_widget_get_name (GTK_WIDGET (target));
else if (GTK_IS_CONSTRAINT_GUIDE (target))
return gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (target));
else
return (const char *)g_object_get_data (G_OBJECT (target), "name");
return "";
}
static void
@@ -145,13 +148,19 @@ get_target (GListModel *model,
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
GObject *item = g_list_model_get_object (model, i);
const char *name;
g_object_unref (item);
if (GTK_IS_CONSTRAINT (item))
continue;
name = (const char *)g_object_get_data (item, "name");
g_object_unref (item);
if (strcmp (name, id) == 0)
return item;
else if (GTK_IS_WIDGET (item))
{
if (strcmp (id, gtk_widget_get_name (GTK_WIDGET (item))) == 0)
return item;
}
else if (GTK_IS_CONSTRAINT_GUIDE (item))
{
if (strcmp (id, gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item))) == 0)
return item;
}
}
return NULL;
@@ -203,6 +212,19 @@ get_relation_nick (GtkConstraintRelation relation)
return nick;
}
static const char *
get_relation_to_string (GtkConstraintRelation relation)
{
switch (relation)
{
case GTK_CONSTRAINT_RELATION_LE: return "";
case GTK_CONSTRAINT_RELATION_EQ: return "=";
case GTK_CONSTRAINT_RELATION_GE: return "";
default:
g_assert_not_reached ();
}
}
static GtkConstraintStrength
get_strength (const char *id)
{
@@ -226,6 +248,40 @@ get_strength_nick (GtkConstraintStrength strength)
return nick;
}
void
constraint_editor_serialize_constraint (GString *str,
int indent,
GtkConstraint *constraint)
{
const char *target;
const char *target_attr;
const char *relation;
const char *source;
const char *source_attr;
double multiplier;
double constant;
const char *strength;
target = get_target_name (gtk_constraint_get_target (constraint));
target_attr = get_attr_nick (gtk_constraint_get_target_attribute (constraint));
relation = get_relation_nick (gtk_constraint_get_relation (constraint));
source = get_target_name (gtk_constraint_get_source (constraint));
source_attr = get_attr_nick (gtk_constraint_get_source_attribute (constraint));
multiplier = gtk_constraint_get_multiplier (constraint);
constant = gtk_constraint_get_constant (constraint);
strength = get_strength_nick (gtk_constraint_get_strength (constraint));
g_string_append_printf (str, "%*s<constraint target=\"%s\" target-attribute=\"%s\"\n", indent, "", target, target_attr);
g_string_append_printf (str, "%*s relation=\"%s\"\n", indent, "", relation);
if (strcmp (source_attr, "none") != 0)
{
g_string_append_printf (str, "%*s source=\"%s\" source-attribute=\"%s\"\n", indent, "", source, source_attr);
g_string_append_printf (str, "%*s multiplier=\"%g\"\n", indent, "", multiplier);
}
g_string_append_printf (str, "%*s constant=\"%g\"\n", indent, "", constant);
g_string_append_printf (str, "%*s strength=\"%s\" />\n", indent, "", strength);
}
static void
create_constraint (GtkButton *button,
ConstraintEditor *editor)
@@ -240,7 +296,6 @@ create_constraint (GtkButton *button,
double constant;
int strength;
GtkConstraint *constraint;
const char *name;
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target));
target = get_target (editor->model, id);
@@ -248,9 +303,17 @@ create_constraint (GtkButton *button,
target_attr = get_target_attr (id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
source = get_target (editor->model, id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
source_attr = get_target_attr (id);
if (id != NULL)
{
source = get_target (editor->model, id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
source_attr = get_target_attr (id);
}
else
{
source = NULL;
source_attr = GTK_CONSTRAINT_ATTRIBUTE_NONE;
}
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->relation));
relation = get_relation (id);
@@ -262,15 +325,12 @@ create_constraint (GtkButton *button,
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
strength = get_strength (id);
name = gtk_editable_get_text (GTK_EDITABLE (editor->name));
constraint = gtk_constraint_new (target, target_attr,
relation,
source, source_attr,
multiplier,
constant,
strength);
g_object_set_data_full (G_OBJECT (constraint), "name", g_strdup (name), g_free);
g_signal_emit (editor, signals[DONE], 0, constraint);
g_object_unref (constraint);
}
@@ -295,6 +355,53 @@ source_attr_changed (ConstraintEditor *editor)
}
}
char *
constraint_editor_constraint_to_string (GtkConstraint *constraint)
{
GString *str;
const char *name;
const char *attr;
const char *relation;
double c, m;
str = g_string_new ("");
name = get_target_name (gtk_constraint_get_target (constraint));
attr = get_attr_nick (gtk_constraint_get_target_attribute (constraint));
relation = get_relation_to_string (gtk_constraint_get_relation (constraint));
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s %s ", name, attr, relation);
c = gtk_constraint_get_constant (constraint);
attr = get_attr_nick (gtk_constraint_get_source_attribute (constraint));
if (strcmp (attr, "none") != 0)
{
name = get_target_name (gtk_constraint_get_source (constraint));
m = gtk_constraint_get_multiplier (constraint);
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s", name, attr);
if (m != 1.0)
g_string_append_printf (str, " × %g", m);
if (c > 0.0)
g_string_append_printf (str, " + %g", c);
else if (c < 0.0)
g_string_append_printf (str, " - %g", -c);
}
else
g_string_append_printf (str, "%g", c);
return g_string_free (str, FALSE);
}
static void
update_preview (ConstraintEditor *editor)
{
@@ -322,14 +429,20 @@ update_preview (ConstraintEditor *editor)
g_free (relation);
constant = gtk_editable_get_text (GTK_EDITABLE (editor->constant));
c = g_ascii_strtod (constant, NULL);
if (constant[0] != '\0')
c = g_ascii_strtod (constant, NULL);
else
c = 0.0;
attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
if (strcmp (attr, "none") != 0)
{
name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
multiplier = gtk_editable_get_text (GTK_EDITABLE (editor->multiplier));
m = g_ascii_strtod (multiplier, NULL);
if (multiplier[0] != '\0')
m = g_ascii_strtod (multiplier, NULL);
else
m = 1.0;
if (name == NULL)
name = "[ ]";
@@ -355,8 +468,7 @@ update_preview (ConstraintEditor *editor)
static void
update_button (ConstraintEditor *editor)
{
if (gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target)) != NULL &&
gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source)) != NULL)
if (gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target)) != NULL)
gtk_widget_set_sensitive (editor->button, TRUE);
else
gtk_widget_set_sensitive (editor->button, FALSE);
@@ -368,8 +480,6 @@ constraint_editor_init (ConstraintEditor *editor)
gtk_widget_init_template (GTK_WIDGET (editor));
}
static int constraint_counter;
static void
constraint_editor_constructed (GObject *object)
{
@@ -394,9 +504,6 @@ constraint_editor_constructed (GObject *object)
double multiplier;
double constant;
nick = (char *)g_object_get_data (G_OBJECT (editor->constraint), "name");
gtk_editable_set_text (GTK_EDITABLE (editor->name), nick);
target = gtk_constraint_get_target (editor->constraint);
nick = get_target_name (target);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target), nick);
@@ -435,13 +542,6 @@ constraint_editor_constructed (GObject *object)
}
else
{
char *name;
constraint_counter++;
name = g_strdup_printf ("Constraint %d", constraint_counter);
gtk_editable_set_text (GTK_EDITABLE (editor->name), name);
g_free (name);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), "left");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), "left");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), "eq");
@@ -554,7 +654,6 @@ constraint_editor_class_init (ConstraintEditorClass *class)
"/org/gtk/gtk4/constraint-editor/constraint-editor.ui");
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, grid);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, name);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target_attr);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, relation);

View File

@@ -7,6 +7,7 @@ constraintview .child {
background: red;
}
constraintview .guide {
constraintview guide {
background: blue;
border: 1px solid white;
}

View File

@@ -4,6 +4,7 @@
<file preprocess="xml-stripblanks">constraint-editor-window.ui</file>
<file preprocess="xml-stripblanks">constraint-editor.ui</file>
<file preprocess="xml-stripblanks">guide-editor.ui</file>
<file preprocess="xml-stripblanks">child-editor.ui</file>
<file>constraint-editor.css</file>
</gresource>
</gresources>

View File

@@ -27,3 +27,8 @@ G_DECLARE_FINAL_TYPE (ConstraintEditor, constraint_editor, CONSTRAINT, EDITOR, G
ConstraintEditor * constraint_editor_new (GListModel *model,
GtkConstraint *constraint);
void constraint_editor_serialize_constraint (GString *str,
int indent,
GtkConstraint *constraint);
char *constraint_editor_constraint_to_string (GtkConstraint *constraint);

View File

@@ -6,23 +6,6 @@
<property name="margin">20</property>
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<child>
<object class="GtkLabel">
<property name="label">Name</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="name">
<layout>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Target</property>

View File

@@ -16,12 +16,15 @@
#include <gtk/gtk.h>
#include "constraint-view.h"
#include "guide-placeholder.h"
struct _ConstraintView
{
GtkWidget parent;
GListStore *store;
GListModel *model;
GtkWidget *drag_widget;
};
G_DEFINE_TYPE (ConstraintView, constraint_view, GTK_TYPE_WIDGET);
@@ -35,7 +38,7 @@ constraint_view_dispose (GObject *object)
while ((child = gtk_widget_get_first_child (GTK_WIDGET (view))) != NULL)
gtk_widget_unparent (child);
g_clear_object (&view->store);
g_clear_object (&view->model);
G_OBJECT_CLASS (constraint_view_parent_class)->dispose (object);
}
@@ -51,13 +54,153 @@ constraint_view_class_init (ConstraintViewClass *klass)
gtk_widget_class_set_css_name (widget_class, "constraintview");
}
static void
update_weak_position (ConstraintView *self,
GtkWidget *child,
double x,
double y)
{
GtkLayoutManager *manager;
GtkConstraint *constraint;
manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
constraint = (GtkConstraint *)g_object_get_data (G_OBJECT (child), "x-constraint");
if (constraint)
{
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "x-constraint", NULL);
}
if (x != -100)
{
constraint = gtk_constraint_new_constant (child,
GTK_CONSTRAINT_ATTRIBUTE_CENTER_X,
GTK_CONSTRAINT_RELATION_EQ,
x,
GTK_CONSTRAINT_STRENGTH_WEAK);
g_object_set_data (G_OBJECT (constraint), "internal", "yes");
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "x-constraint", constraint);
}
constraint = (GtkConstraint *)g_object_get_data (G_OBJECT (child), "y-constraint");
if (constraint)
{
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "y-constraint", NULL);
}
if (y != -100)
{
constraint = gtk_constraint_new_constant (child,
GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y,
GTK_CONSTRAINT_RELATION_EQ,
y,
GTK_CONSTRAINT_STRENGTH_WEAK);
g_object_set_data (G_OBJECT (constraint), "internal", "yes");
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "y-constraint", constraint);
}
}
static void
drag_begin (GtkGestureDrag *drag,
double start_x,
double start_y,
ConstraintView *self)
{
GtkWidget *widget;
GtkWidget *target;
widget = gtk_widget_pick (GTK_WIDGET (self), start_x, start_y, GTK_PICK_DEFAULT);
if (widget)
{
target = gtk_widget_get_ancestor (widget, GUIDE_PLACEHOLDER_TYPE);
if (!target)
target = gtk_widget_get_ancestor (widget, GTK_TYPE_FRAME);
if (target &&
gtk_widget_get_parent (target) == (GtkWidget *)self)
{
self->drag_widget = target;
}
}
}
static void
drag_update (GtkGestureDrag *drag,
double offset_x,
double offset_y,
ConstraintView *self)
{
double x, y;
if (!self->drag_widget)
return;
gtk_gesture_drag_get_start_point (drag, &x, &y);
update_weak_position (self, self->drag_widget, x + offset_x, y + offset_y);
}
static void
drag_end (GtkGestureDrag *drag,
double offset_x,
double offset_y,
ConstraintView *self)
{
self->drag_widget = NULL;
}
static gboolean
omit_internal (gpointer item, gpointer user_data)
{
if (g_object_get_data (G_OBJECT (item), "internal"))
return FALSE;
return TRUE;
}
static void
constraint_view_init (ConstraintView *self)
{
gtk_widget_set_layout_manager (GTK_WIDGET (self),
gtk_constraint_layout_new ());
GtkLayoutManager *manager;
GtkEventController *controller;
GListStore *list;
GListModel *all_children;
GListModel *all_constraints;
GListModel *guides;
GListModel *children;
GListModel *constraints;
self->store = g_list_store_new (G_TYPE_OBJECT);
manager = gtk_constraint_layout_new ();
gtk_widget_set_layout_manager (GTK_WIDGET (self), manager);
all_children = gtk_widget_observe_children (GTK_WIDGET (self));
all_constraints = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (manager));
guides = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (manager));
constraints = (GListModel *)gtk_filter_list_model_new (all_constraints, omit_internal, NULL, NULL);
children = (GListModel *)gtk_filter_list_model_new (all_children, omit_internal, NULL, NULL);
list = g_list_store_new (G_TYPE_LIST_MODEL);
g_list_store_append (list, children);
g_list_store_append (list, guides);
g_list_store_append (list, constraints);
self->model = G_LIST_MODEL (gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list)));
g_object_unref (children);
g_object_unref (guides);
g_object_unref (constraints);
g_object_unref (all_children);
g_object_unref (all_constraints);
g_object_unref (list);
controller = (GtkEventController *)gtk_gesture_drag_new ();
g_signal_connect (controller, "drag-begin", G_CALLBACK (drag_begin), self);
g_signal_connect (controller, "drag-update", G_CALLBACK (drag_update), self);
g_signal_connect (controller, "drag-end", G_CALLBACK (drag_end), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
}
ConstraintView *
@@ -73,168 +216,109 @@ constraint_view_add_child (ConstraintView *view,
GtkWidget *frame;
GtkWidget *label;
label = gtk_label_new (name);
frame = gtk_frame_new (NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (frame), "child");
g_object_set_data_full (G_OBJECT (frame), "name", g_strdup (name), g_free);
gtk_widget_set_name (frame, name);
gtk_widget_set_size_request (frame, 100, 25);
label = gtk_label_new (name);
gtk_container_add (GTK_CONTAINER (frame), label);
g_object_bind_property (frame, "name",
label, "label",
G_BINDING_DEFAULT);
gtk_widget_set_parent (frame, GTK_WIDGET (view));
g_list_store_append (view->store, frame);
update_weak_position (view, frame, 100, 100);
}
void
constraint_view_remove_child (ConstraintView *view,
GtkWidget *child)
{
int i;
update_weak_position (view, child, -100, -100);
gtk_widget_unparent (child);
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (view->store)); i++)
{
if (g_list_model_get_item (G_LIST_MODEL (view->store), i) == (GObject*)child)
{
g_list_store_remove (view->store, i);
break;
}
}
}
void
constraint_view_add_guide (ConstraintView *view,
GtkConstraintGuide *guide)
{
GtkLayoutManager *manager;
GtkWidget *frame;
GtkWidget *label;
GtkConstraintLayout *layout;
GtkWidget *placeholder;
const char *name;
GtkConstraint *constraint;
name = (const char *)g_object_get_data (G_OBJECT (guide), "name");
label = gtk_label_new (name);
frame = gtk_frame_new (NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (frame), "guide");
g_object_set_data_full (G_OBJECT (frame), "name", g_strdup (name), g_free);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_set_parent (frame, GTK_WIDGET (view));
g_object_set_data (G_OBJECT (guide), "frame", frame);
g_object_set_data (G_OBJECT (guide), "label", label);
manager = gtk_widget_get_layout_manager (GTK_WIDGET (view));
gtk_constraint_layout_add_guide (GTK_CONSTRAINT_LAYOUT (manager),
g_object_ref (guide));
constraint = gtk_constraint_new (frame,
GTK_CONSTRAINT_ATTRIBUTE_LEFT,
GTK_CONSTRAINT_RELATION_EQ,
guide,
GTK_CONSTRAINT_ATTRIBUTE_LEFT,
1.0, 0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED);
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (guide), "left-constraint", constraint);
constraint = gtk_constraint_new (frame,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
guide,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
1.0, 0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED);
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (guide), "top-constraint", constraint);
constraint = gtk_constraint_new (frame,
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
GTK_CONSTRAINT_RELATION_EQ,
guide,
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
1.0, 0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED);
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (guide), "width-constraint", constraint);
constraint = gtk_constraint_new (frame,
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
GTK_CONSTRAINT_RELATION_EQ,
guide,
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
1.0, 0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED);
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (guide), "height-constraint", constraint);
g_list_store_append (view->store, guide);
}
void
constraint_view_guide_changed (ConstraintView *view,
GtkConstraintGuide *guide)
{
GtkWidget *label;
const char *name;
struct {
const char *name;
GtkConstraintAttribute attr;
} names[] = {
{ "left-constraint", GTK_CONSTRAINT_ATTRIBUTE_LEFT },
{ "top-constraint", GTK_CONSTRAINT_ATTRIBUTE_TOP },
{ "width-constraint", GTK_CONSTRAINT_ATTRIBUTE_WIDTH },
{ "height-constraint", GTK_CONSTRAINT_ATTRIBUTE_HEIGHT },
};
int i;
name = (const char *)g_object_get_data (G_OBJECT (guide), "name");
label = (GtkWidget *)g_object_get_data (G_OBJECT (guide), "label");
gtk_label_set_label (GTK_LABEL (label), name);
name = gtk_constraint_guide_get_name (guide);
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (view->store)); i++)
placeholder = guide_placeholder_new (guide);
gtk_widget_set_tooltip_text (placeholder, name);
g_object_bind_property (guide, "name",
placeholder, "tooltip-text",
G_BINDING_DEFAULT);
g_object_set_data (G_OBJECT (placeholder), "internal", "yes");
gtk_widget_insert_after (placeholder, GTK_WIDGET (view), NULL);
g_object_set_data (G_OBJECT (guide), "placeholder", placeholder);
layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (view)));
gtk_constraint_layout_add_guide (layout, g_object_ref (guide));
for (i = 0; i < G_N_ELEMENTS (names); i++)
{
if (g_list_model_get_item (G_LIST_MODEL (view->store), i) == (GObject*)guide)
{
g_list_model_items_changed (G_LIST_MODEL (view->store), i, 1, 1);
break;
}
constraint = gtk_constraint_new (placeholder,
names[i].attr,
GTK_CONSTRAINT_RELATION_EQ,
guide,
names[i].attr,
1.0, 0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED);
g_object_set_data (G_OBJECT (constraint), "internal", "yes");
gtk_constraint_layout_add_constraint (layout, constraint);
g_object_set_data (G_OBJECT (guide), names[i].name, constraint);
}
update_weak_position (view, placeholder, 150, 150);
}
void
constraint_view_remove_guide (ConstraintView *view,
GtkConstraintGuide *guide)
{
GtkLayoutManager *manager;
GtkWidget *frame;
GtkConstraintLayout *layout;
GtkWidget *placeholder;
GtkConstraint *constraint;
const char *names[] = {
"left-constraint",
"top-constraint",
"width-constraint",
"height-constraint"
};
int i;
manager = gtk_widget_get_layout_manager (GTK_WIDGET (view));
layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (view)));
constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), "left-constraint");
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), "top-constraint");
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), "width-constraint");
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), "height-constraint");
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
frame = (GtkWidget *)g_object_get_data (G_OBJECT (guide), "frame");
gtk_widget_unparent (frame);
gtk_constraint_layout_remove_guide (GTK_CONSTRAINT_LAYOUT (manager),
guide);
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (view->store)); i++)
for (i = 0; i < G_N_ELEMENTS (names); i++)
{
if (g_list_model_get_item (G_LIST_MODEL (view->store), i) == (GObject*)guide)
{
g_list_store_remove (view->store, i);
break;
}
constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), names[i]);
gtk_constraint_layout_remove_constraint (layout, constraint);
}
placeholder = (GtkWidget *)g_object_get_data (G_OBJECT (guide), "placeholder");
update_weak_position (view, placeholder, -100, -100);
gtk_widget_unparent (placeholder);
gtk_constraint_layout_remove_guide (layout, guide);
}
void
@@ -246,8 +330,6 @@ constraint_view_add_constraint (ConstraintView *view,
manager = gtk_widget_get_layout_manager (GTK_WIDGET (view));
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
g_object_ref (constraint));
g_list_store_append (view->store, constraint);
}
void
@@ -255,23 +337,14 @@ constraint_view_remove_constraint (ConstraintView *view,
GtkConstraint *constraint)
{
GtkLayoutManager *manager;
int i;
manager = gtk_widget_get_layout_manager (GTK_WIDGET (view));
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (view->store)); i++)
{
if (g_list_model_get_item (G_LIST_MODEL (view->store), i) == (GObject*)constraint)
{
g_list_store_remove (view->store, i);
break;
}
}
}
GListModel *
constraint_view_get_model (ConstraintView *view)
{
return G_LIST_MODEL (view->store);
return view->model;
}

View File

@@ -89,38 +89,55 @@ get_strength_nick (GtkConstraintStrength strength)
return nick;
}
void
guide_editor_serialize_guide (GString *str,
int indent,
GtkConstraintGuide *guide)
{
int min_width, min_height;
int nat_width, nat_height;
int max_width, max_height;
const char *name;
const char *strength;
gtk_constraint_guide_get_min_size (guide, &min_width, &min_height);
gtk_constraint_guide_get_nat_size (guide, &nat_width, &nat_height);
gtk_constraint_guide_get_max_size (guide, &max_width, &max_height);
name = gtk_constraint_guide_get_name (guide);
strength = get_strength_nick (gtk_constraint_guide_get_strength (guide));
g_string_append_printf (str, "%*s<guide min-width=\"%d\" min-height=\"%d\"\n", indent, "", min_width, min_height);
g_string_append_printf (str, "%*s nat-width=\"%d\" nat-height=\"%d\"\n", indent, "", nat_width, nat_height);
g_string_append_printf (str, "%*s max-width=\"%d\" max-height=\"%d\"\n", indent, "", max_width, max_height);
g_string_append_printf (str, "%*s name=\"%s\" strength=\"%s\" />\n", indent, "", name, strength);
}
static void
create_guide (GtkButton *button,
GuideEditor *editor)
{
#if 0
const char *id;
int strength;
#endif
const char *name;
int w, h;
GtkConstraintGuide *guide;
//guide = gtk_constraint_guide_new ();
if (editor->guide)
guide = g_object_ref (editor->guide);
else
guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL);
guide = gtk_constraint_guide_new ();
name = gtk_editable_get_text (GTK_EDITABLE (editor->name));
g_object_set_data_full (G_OBJECT (guide), "name", g_strdup (name), g_free);
gtk_constraint_guide_set_name (guide, name);
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_height));
//gtk_constraint_guide_set_min_size (guide, w, h);
g_object_set (guide, "min-width", w, "min-height", h, NULL);
gtk_constraint_guide_set_min_size (guide, w, h);
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_height));
//gtk_constraint_guide_set_nat_size (guide, w, h);
g_object_set (guide, "nat-width", w, "nat-height", h, NULL);
gtk_constraint_guide_set_nat_size (guide, w, h);
#if 0
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_height));
gtk_constraint_guide_set_max_size (guide, w, h);
@@ -128,7 +145,6 @@ create_guide (GtkButton *button,
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
strength = get_strength (id);
gtk_constraint_guide_set_strength (guide, strength);
#endif
g_signal_emit (editor, signals[DONE], 0, guide);
g_object_unref (guide);
@@ -142,6 +158,84 @@ guide_editor_init (GuideEditor *editor)
static int guide_counter;
static int
min_input (GtkSpinButton *spin_button,
double *new_val)
{
if (strcmp (gtk_editable_get_text (GTK_EDITABLE (spin_button)), "") == 0)
{
*new_val = 0.0;
return TRUE;
}
return FALSE;
}
static int
max_input (GtkSpinButton *spin_button,
double *new_val)
{
if (strcmp (gtk_editable_get_text (GTK_EDITABLE (spin_button)), "") == 0)
{
*new_val = G_MAXINT;
return TRUE;
}
return FALSE;
}
static gboolean
min_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
double value;
GtkWidget *box, *text;
adjustment = gtk_spin_button_get_adjustment (spin_button);
value = gtk_adjustment_get_value (adjustment);
box = gtk_widget_get_first_child (GTK_WIDGET (spin_button));
text = gtk_widget_get_first_child (box);
if (value == 0.0)
{
gtk_editable_set_text (GTK_EDITABLE (spin_button), "");
gtk_text_set_placeholder_text (GTK_TEXT (text), "unset");
return TRUE;
}
else
{
gtk_text_set_placeholder_text (GTK_TEXT (text), "");
return FALSE;
}
}
static gboolean
max_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
double value;
GtkWidget *box, *text;
adjustment = gtk_spin_button_get_adjustment (spin_button);
value = gtk_adjustment_get_value (adjustment);
box = gtk_widget_get_first_child (GTK_WIDGET (spin_button));
text = gtk_widget_get_first_child (box);
if (value == (double)G_MAXINT)
{
gtk_editable_set_text (GTK_EDITABLE (spin_button), "");
gtk_text_set_placeholder_text (GTK_TEXT (text), "unset");
return TRUE;
}
else
{
gtk_text_set_placeholder_text (GTK_TEXT (text), "");
return FALSE;
}
}
static void
guide_editor_constructed (GObject *object)
{
@@ -149,40 +243,43 @@ guide_editor_constructed (GObject *object)
guide_strength_combo (editor->strength);
gtk_widget_set_sensitive (editor->max_width, FALSE);
gtk_widget_set_sensitive (editor->max_height, FALSE);
gtk_widget_set_sensitive (editor->strength, FALSE);
g_signal_connect (editor->min_width, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->min_width, "output", G_CALLBACK (min_output), NULL);
g_signal_connect (editor->min_height, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->min_height, "output", G_CALLBACK (min_output), NULL);
g_signal_connect (editor->max_width, "input", G_CALLBACK (max_input), NULL);
g_signal_connect (editor->max_width, "output", G_CALLBACK (max_output), NULL);
g_signal_connect (editor->max_height, "input", G_CALLBACK (max_input), NULL);
g_signal_connect (editor->max_height, "output", G_CALLBACK (max_output), NULL);
if (editor->guide)
{
#if 0
GtkConstaintStrength strength;
#endif
GtkConstraintStrength strength;
const char *nick;
int w, h;
nick = (char *)g_object_get_data (G_OBJECT (editor->guide), "name");
gtk_editable_set_text (GTK_EDITABLE (editor->name), nick);
nick = gtk_constraint_guide_get_name (editor->guide);
if (nick)
gtk_editable_set_text (GTK_EDITABLE (editor->name), nick);
//gtk_constaint_guide_get_min_size (editor->guide, &w, &h);
g_object_get (editor->guide, "min-width", &w, "min-height", &h, NULL);
gtk_constraint_guide_get_min_size (editor->guide, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), h);
//gtk_constaint_guide_get_nat_size (editor->guide, &w, &h);
g_object_get (editor->guide, "nat-width", &w, "nat-height", &h, NULL);
gtk_constraint_guide_get_nat_size (editor->guide, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), h);
#if 0
gtk_constaint_guide_get_max_size (editor->guide, &w, &h);
gtk_constraint_guide_get_max_size (editor->guide, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), h);
strength = gtk_guide_get_strength (editor->guide);
strength = gtk_constraint_guide_get_strength (editor->guide);
nick = get_strength_nick (strength);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), nick);
#endif
gtk_button_set_label (GTK_BUTTON (editor->button), "Apply");
}
@@ -199,12 +296,10 @@ guide_editor_constructed (GObject *object)
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), 0.0);
#if 0
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), G_MAXINT);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), G_MAXINT);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "medium");
#endif
gtk_button_set_label (GTK_BUTTON (editor->button), "Create");
}

View File

@@ -26,3 +26,7 @@
G_DECLARE_FINAL_TYPE (GuideEditor, guide_editor, GUIDE, EDITOR, GtkWidget)
GuideEditor * guide_editor_new (GtkConstraintGuide *guide);
void guide_editor_serialize_guide (GString *str,
int indent,
GtkConstraintGuide *guide);

View File

@@ -0,0 +1,179 @@
/*
* Copyright © 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen
*/
#include "config.h"
#include "guide-placeholder.h"
struct _GuidePlaceholder {
GtkWidget parent_instance;
GtkWidget *label;
GtkConstraintGuide *guide;
};
enum {
PROP_GUIDE = 1,
LAST_PROP
};
static GParamSpec *props[LAST_PROP];
G_DEFINE_TYPE (GuidePlaceholder, guide_placeholder, GTK_TYPE_WIDGET);
static void
guide_placeholder_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GuidePlaceholder *self = GUIDE_PLACEHOLDER (widget);
int min_width, min_height;
int nat_width, nat_height;
gtk_constraint_guide_get_min_size (self->guide, &min_width, &min_height);
gtk_constraint_guide_get_nat_size (self->guide, &nat_width, &nat_height);
gtk_widget_measure (self->label, orientation, for_size, minimum, natural, NULL, NULL);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
*minimum = min_width;
*natural = nat_width;
}
else
{
*minimum = min_height;
*natural = nat_height;
}
}
static void
guide_placeholder_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
GuidePlaceholder *self = GUIDE_PLACEHOLDER (widget);
gtk_widget_allocate (self->label, width, height, baseline, NULL);
}
static void
guide_changed (GObject *obj, GParamSpec *pspec, GuidePlaceholder *self)
{
gtk_label_set_label (GTK_LABEL (self->label), gtk_constraint_guide_get_name (self->guide));
gtk_widget_queue_resize (GTK_WIDGET (self));
}
static void
guide_placeholder_dispose (GObject *object)
{
GuidePlaceholder *self = GUIDE_PLACEHOLDER (object);
g_signal_handlers_disconnect_by_func (self->guide, guide_changed, self);
g_object_unref (self->guide);
gtk_widget_unparent (self->label);
G_OBJECT_CLASS (guide_placeholder_parent_class)->dispose (object);
}
static void
guide_placeholder_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GuidePlaceholder *self = GUIDE_PLACEHOLDER (object);
switch (prop_id)
{
case PROP_GUIDE:
self->guide = g_value_dup_object (value);
g_signal_connect (self->guide, "notify", G_CALLBACK (guide_changed), self);
guide_changed ((GObject *)self->guide, NULL, self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
guide_placeholder_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GuidePlaceholder *self = GUIDE_PLACEHOLDER (object);
switch (prop_id)
{
case PROP_GUIDE:
g_value_set_object (value, self->guide);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
guide_placeholder_class_init (GuidePlaceholderClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = guide_placeholder_dispose;
object_class->set_property = guide_placeholder_set_property;
object_class->get_property = guide_placeholder_get_property;
widget_class->measure = guide_placeholder_measure;
widget_class->size_allocate = guide_placeholder_size_allocate;
props[PROP_GUIDE] =
g_param_spec_object ("guide", "guide", "guide",
GTK_TYPE_CONSTRAINT_GUIDE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, LAST_PROP, props);
gtk_widget_class_set_css_name (widget_class, "guide");
}
static void
guide_placeholder_init (GuidePlaceholder *self)
{
self->label = gtk_label_new ("");
gtk_widget_set_parent (self->label, GTK_WIDGET (self));
}
GtkWidget *
guide_placeholder_new (GtkConstraintGuide *guide)
{
return g_object_new (guide_placeholder_get_type (),
"guide", guide,
NULL);
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright © 2019 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen
*/
#pragma once
#include <gtk/gtk.h>
#define GUIDE_PLACEHOLDER_TYPE (guide_placeholder_get_type ())
G_DECLARE_FINAL_TYPE (GuidePlaceholder, guide_placeholder, GUIDE, PLACEHOLDER, GtkWidget)
GtkWidget * guide_placeholder_new (GtkConstraintGuide *guide);

View File

@@ -5,6 +5,8 @@ constraint_editor_sources = [
'constraint-view.c',
'constraint-editor.c',
'guide-editor.c',
'child-editor.c',
'guide-placeholder.c',
]
constraint_editor_resources = gnome.compile_resources('constraint_editor_resources',

View File

@@ -44,20 +44,21 @@ simple_grid_class_init (SimpleGridClass *klass)
/* Layout:
*
* +-----------------------------+
* | +-----------+ +-----------+ |
* | | Child 1 | | Child 2 | |
* | +-----------+ +-----------+ |
* | +-------------------------+ |
* | | Child 3 | |
* | +-------------------------+ |
* +-----------------------------+
* +-------------------------------------+
* | +-----------++-------++-----------+ |
* | | Child 1 || Space || Child 2 | |
* | +-----------++-------++-----------+ |
* | +---------------------------------+ |
* | | Child 3 | |
* | +---------------------------------+ |
* +-------------------------------------+
*
* Constraints:
*
* super.start = child1.start - 8
* child1.width = child2.width
* child1.end = child2.start - 12
* child1.end = space.start
* space.end = child2.start
* child2.end = super.end - 8
* super.start = child3.start - 8
* child3.end = super.end - 8
@@ -69,6 +70,12 @@ simple_grid_class_init (SimpleGridClass *klass)
* child3.height = child2.height
* child3.bottom = super.bottom - 8
*
* To add some flexibility, we make the space
* stretchable:
*
* space.width >= 10
* space.width = 100
* space.width <= 200
*/
static void
build_constraints (SimpleGrid *self,
@@ -76,12 +83,12 @@ build_constraints (SimpleGrid *self,
{
GtkConstraintGuide *guide;
guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE,
"min-width", 10,
"min-height", 10,
"nat-width", 100,
"nat-height", 10,
NULL);
guide = gtk_constraint_guide_new ();
gtk_constraint_guide_set_name (guide, "space");
gtk_constraint_guide_set_min_size (guide, 10, 10);
gtk_constraint_guide_set_nat_size (guide, 100, 10);
gtk_constraint_guide_set_max_size (guide, 200, 20);
gtk_constraint_guide_set_strength (guide, GTK_CONSTRAINT_STRENGTH_STRONG);
gtk_constraint_layout_add_guide (manager, guide);
gtk_constraint_layout_add_constraint (manager,

View File

@@ -1707,7 +1707,7 @@ activate (GApplication *app)
gtk_css_provider_load_from_resource (provider, "/org/gtk/WidgetFactory4/widget-factory.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_unref (provider);
builder = gtk_builder_new_from_resource ("/org/gtk/WidgetFactory4/widget-factory.ui");

View File

@@ -99,7 +99,7 @@ if wayland_enabled
src_dir += [ gdkwayland_inc ]
endif
if get_option('documentation')
if get_option('gtk_doc')
configure_file(input: 'version.xml.in', output: 'version.xml', configuration: version_conf)
gnome.gtkdoc('gdk4',

View File

@@ -34,7 +34,7 @@ private_headers = [
images = [
]
if get_option('documentation')
if get_option('gtk_doc')
configure_file(input: 'version.xml.in', output: 'version.xml', configuration: version_conf)
gnome.gtkdoc('gsk4',

View File

@@ -355,8 +355,8 @@ How to compile GTK itself
</group>
<sbr/>
<group>
<arg choice="plain">-Ddocumentation=true</arg>
<arg choice="plain">-Ddocumentation=false</arg>
<arg choice="plain">-Dgtk_doc=true</arg>
<arg choice="plain">-Dgtk_doc=false</arg>
</group>
<sbr/>
<group>
@@ -382,7 +382,7 @@ How to compile GTK itself
</formalpara>
<formalpara>
<title><systemitem>documentation</systemitem> and
<title><systemitem>gtk_doc</systemitem> and
<systemitem>man-pages</systemitem></title>
<para>
@@ -394,7 +394,7 @@ How to compile GTK itself
<application>gtk-doc</application> installed and
are modifying GTK, you may want to enable
<application>gtk-doc</application> support by passing
in <systemitem>documentation</systemitem>.
in <systemitem>gtk_doc</systemitem>.
</para>
<para>
Additionally, some tools provided by GTK have their own

View File

@@ -109,6 +109,9 @@
<xi:include href="xml/gtkcustomlayout.xml" />
<xi:include href="xml/gtkfixedlayout.xml" />
<xi:include href="xml/gtkgridlayout.xml" />
<xi:include href="xml/gtkconstraintlayout.xml" />
<xi:include href="xml/gtkconstraint.xml" />
<xi:include href="xml/gtkconstraintguide.xml" />
</chapter>
<chapter id="DisplayWidgets">

View File

@@ -7287,3 +7287,87 @@ gtk_grid_layout_get_type
GTK_TYPE_GRID_LAYOUT_CHILD
gtk_grid_layout_child_get_type
</SECTION>
<SECTION>
<FILE>gtkconstraint</FILE>
GtkConstraint
GtkConstraintTarget
gtk_constraint_new
gtk_constraint_new_constant
gtk_constraint_get_target
GtkConstraintAttribute
gtk_constraint_get_target_attribute
GtkConstraintRelation
gtk_constraint_get_relation
gtk_constraint_get_source
gtk_constraint_get_source_attribute
gtk_constraint_get_multiplier
gtk_constraint_get_constant
GtkConstraintStrength
gtk_constraint_get_strength
gtk_constraint_is_required
gtk_constraint_is_attached
gtk_constraint_is_constant
<SUBSECTION Standard>
GTK_TYPE_CONSTRAINT
gtk_constraint_get_type
GTK_TYPE_CONSTRAINT_TARGET
gtk_constraint_target_get_type
</SECTION>
<SECTION>
<FILE>gtkconstraintlayout</FILE>
GtkConstraintLayout
GtkConstraintLayoutChild
GtkConstraintVflParserError
gtk_constraint_layout_new
<SUBSECTION Constraints>
gtk_constraint_layout_add_constraint
gtk_constraint_layout_remove_constraint
gtk_constraint_layout_remove_all_constraints
<SUBSECTION Guides>
gtk_constraint_layout_add_guide
gtk_constraint_layout_remove_guide
<SUBSECTION VFL>
gtk_constraint_layout_add_constraints_from_description
gtk_constraint_layout_add_constraints_from_descriptionv
<SUBSECTION>
gtk_constraint_layout_observe_constraints
gtk_constraint_layout_observe_guides
<SUBSECTION Standard>
GTK_TYPE_CONSTRAINT_LAYOUT
gtk_constraint_layout_get_type
GTK_TYPE_CONSTRAINT_LAYOUT_CHILD
gtk_constraint_layout_child_get_type
GTK_CONSTRAINT_VFL_PARSER_ERROR
gtk_constraint_vfl_parser_error_quark
</SECTION>
<SECTION>
<FILE>gtkconstraintguide</FILE>
GtkConstraintGuide
gtk_constraint_guide_new
gtk_constraint_guide_set_name
gtk_constraint_guide_get_name
gtk_constraint_guide_set_strength
gtk_constraint_guide_get_strength
gtk_constraint_guide_set_min_size
gtk_constraint_guide_get_min_size
gtk_constraint_guide_set_nat_size
gtk_constraint_guide_get_nat_size
gtk_constraint_guide_set_max_size
gtk_constraint_guide_get_max_size
<SUBSECTION Standard>
GTK_TYPE_CONSTRAINT_GUIDE
gtk_constraint_guide_get_tyoe
</SECTION>

View File

@@ -49,6 +49,10 @@ gtk_color_chooser_dialog_get_type
gtk_color_chooser_widget_get_type
gtk_combo_box_get_type
gtk_combo_box_text_get_type
gtk_constraint_get_type
gtk_constraint_guide_get_type
gtk_constraint_layout_get_type
gtk_constraint_target_get_type
gtk_container_get_type
gtk_css_provider_get_type
gtk_dialog_get_type

View File

@@ -23,6 +23,13 @@ private_headers = [
'gtkcolorswatchprivate.h',
'gtkcomboboxprivate.h',
'gtkcontainerprivate.h',
'gtkconstraintexpressionprivate.h',
'gtkconstraintguideprivate.h',
'gtkconstraintlayoutprivate.h',
'gtkconstraintprivate.h',
'gtkconstraintsolverprivate.h',
'gtkconstrainttypesprivate.h',
'gtkconstraintvflparserprivate.h',
'gtkcssanimatedstyleprivate.h',
'gtkcssanimationprivate.h',
'gtkcssarrayvalueprivate.h',
@@ -394,7 +401,7 @@ else
types_conf.set('DISABLE_ON_QUARTZ', '')
endif
if get_option('documentation')
if get_option('gtk_doc')
configure_file(input: 'version.xml.in', output: 'version.xml', configuration: version_conf)
configure_file(input: 'getting_started.xml.in', output: 'getting_started.xml', configuration: src_dir_conf)

View File

@@ -1,4 +1,4 @@
if get_option('documentation')
if get_option('gtk_doc')
glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')

View File

@@ -1,4 +1,4 @@
if x11_enabled and get_option('documentation')
if x11_enabled and get_option('gtk_doc')
doc_shooter_sources = [
'shadow.c',
'shooter.c',

View File

@@ -808,7 +808,8 @@ upload_texture (GskGLRenderer *self,
int texture_id;
if (texture->width <= 128 &&
texture->height <= 128)
texture->height <= 128 &&
!GDK_IS_GL_TEXTURE (texture))
{
graphene_rect_t trect;
@@ -943,11 +944,9 @@ render_transform_node (GskGLRenderer *self,
case GSK_TRANSFORM_CATEGORY_2D:
default:
{
graphene_matrix_t mat;
if (node_supports_transform (child))
{
gsk_transform_to_matrix (node_transform, &mat);
ops_push_modelview (builder, node_transform);
gsk_gl_renderer_add_render_ops (self, child, builder);
ops_pop_modelview (builder);
@@ -972,7 +971,6 @@ render_transform_node (GskGLRenderer *self,
&region, &is_offscreen,
RESET_CLIP | RESET_OPACITY);
gsk_transform_to_matrix (node_transform, &mat);
ops_push_modelview (builder, node_transform);
ops_set_texture (builder, region.texture_id);
ops_set_program (builder, &self->blit_program);

View File

@@ -339,9 +339,12 @@ ops_set_modelview_internal (RenderOpBuilder *builder,
RenderOp op;
graphene_matrix_t matrix;
#if 0
XXX This is not possible if we want pop() to work.
if (builder->current_program &&
gsk_transform_equal (builder->current_program_state->modelview, transform))
return;
#endif
gsk_transform_to_matrix (transform, &matrix);

View File

@@ -1690,11 +1690,26 @@ gsk_transform_transform_bounds (GskTransform *self,
}
break;
case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
{
float dx, dy, scale_x, scale_y;
gsk_transform_to_affine (self, &scale_x, &scale_y, &dx, &dy);
*out_rect = *rect;
out_rect->origin.x *= scale_x;
out_rect->origin.y *= scale_y;
out_rect->size.width *= scale_x;
out_rect->size.height *= scale_y;
out_rect->origin.x += dx;
out_rect->origin.y += dy;
}
break;
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
case GSK_TRANSFORM_CATEGORY_ANY:
case GSK_TRANSFORM_CATEGORY_3D:
case GSK_TRANSFORM_CATEGORY_2D:
case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
default:
{
graphene_matrix_t mat;
@@ -1886,18 +1901,43 @@ gsk_transform_parser_parse (GtkCssParser *parser,
transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (0.f, 0.f, f[0]));
}
#if 0
/* FIXME: add these */
else if (gtk_css_token_is_function (token, "skew"))
{
graphene_matrix_t matrix;
if (!gtk_css_parser_consume_function (parser, 2, 2, gsk_transform_parse_float, f))
goto fail;
f[0] = f[0] / 180.0 * G_PI;
f[1] = f[1] / 180.0 * G_PI;
graphene_matrix_init_skew (&matrix, f[0], f[1]);
transform = gsk_transform_matrix (transform, &matrix);
}
else if (gtk_css_token_is_function (token, "skewX"))
{
graphene_matrix_t matrix;
if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
goto fail;
f[0] = f[0] / 180.0 * G_PI;
graphene_matrix_init_skew (&matrix, f[0], 0);
transform = gsk_transform_matrix (transform, &matrix);
}
else if (gtk_css_token_is_function (token, "skewY"))
{
graphene_matrix_t matrix;
if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
goto fail;
f[0] = f[0] / 180.0 * G_PI;
graphene_matrix_init_skew (&matrix, 0, f[0]);
transform = gsk_transform_matrix (transform, &matrix);
}
#endif
else
{
break;

View File

@@ -211,7 +211,7 @@ gtk_constraint_class_init (GtkConstraintClass *klass)
/**
* GtkConstraint:relation:
*
* The relation order between the terms of the constraint.
* The order relation between the terms of the constraint.
*/
obj_props[PROP_RELATION] =
g_param_spec_enum ("relation",
@@ -292,7 +292,7 @@ gtk_constraint_class_init (GtkConstraintClass *klass)
g_param_spec_int ("strength",
P_("Strength"),
P_("The strength of the constraint"),
GTK_CONSTRAINT_STRENGTH_WEAK, G_MAXINT,
0, GTK_CONSTRAINT_STRENGTH_REQUIRED,
GTK_CONSTRAINT_STRENGTH_REQUIRED,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
@@ -387,24 +387,16 @@ gtk_constraint_new_constant (gpointer target,
}
/**
* gtk_constraint_get_target_widget:
* gtk_constraint_get_target:
* @constraint: a #GtkConstraint
*
* Retrieves the target widget for the @constraint.
* Retrieves the #GtkConstraintTarget used as the target for @constraint.
*
* Returns: (transfer none) (nullable): a #GtkWidget
* If the #GtkConstraint:target property is set to %NULL, the @constraint
* will use the #GtkConstraintLayout's widget.
*
* Returns: (transfer none) (nullable): a #GtkConstraintTarget
*/
GtkWidget *
gtk_constraint_get_target_widget (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), NULL);
if (GTK_IS_WIDGET (constraint->target))
return GTK_WIDGET (constraint->target);
return NULL;
}
GtkConstraintTarget *
gtk_constraint_get_target (GtkConstraint *constraint)
{
@@ -413,6 +405,14 @@ gtk_constraint_get_target (GtkConstraint *constraint)
return constraint->target;
}
/**
* gtk_constraint_get_target_attribute:
* @constraint: a #GtkConstraint
*
* Retrieves the attribute of the target to be set by the @constraint.
*
* Returns: the target's attribute
*/
GtkConstraintAttribute
gtk_constraint_get_target_attribute (GtkConstraint *constraint)
{
@@ -422,24 +422,16 @@ gtk_constraint_get_target_attribute (GtkConstraint *constraint)
}
/**
* gtk_constraint_get_source_widget:
* gtk_constraint_get_source:
* @constraint: a #GtkConstraint
*
* Retrieves the source widget for the @constraint.
* Retrieves the #GtkConstraintTarget used as the source for @constraint.
*
* Returns: (transfer none) (nullable): a #GtkWidget
* If the #GtkConstraint:source property is set to %NULL, the @constraint
* will use the #GtkConstraintLayout's widget.
*
* Returns: (transfer none) (nullable): a #GtkConstraintTarget
*/
GtkWidget *
gtk_constraint_get_source_widget (GtkConstraint *constraint)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), NULL);
if (GTK_IS_WIDGET (constraint->source))
return GTK_WIDGET (constraint->source);
return NULL;
}
GtkConstraintTarget *
gtk_constraint_get_source (GtkConstraint *constraint)
{
@@ -448,6 +440,14 @@ gtk_constraint_get_source (GtkConstraint *constraint)
return constraint->source;
}
/**
* gtk_constraint_get_source_attribute:
* @constraint: a #GtkConstraint
*
* Retrieves the attribute of the source to be read by the @constraint.
*
* Returns: the target's attribute
*/
GtkConstraintAttribute
gtk_constraint_get_source_attribute (GtkConstraint *constraint)
{
@@ -456,6 +456,14 @@ gtk_constraint_get_source_attribute (GtkConstraint *constraint)
return constraint->source_attribute;
}
/**
* gtk_constraint_get_relation:
* @constraint: a #GtkConstraint
*
* The order relation between the terms of the @constraint.
*
* Returns: a #GtkConstraintRelation value
*/
GtkConstraintRelation
gtk_constraint_get_relation (GtkConstraint *constraint)
{
@@ -464,6 +472,15 @@ gtk_constraint_get_relation (GtkConstraint *constraint)
return constraint->relation;
}
/**
* gtk_constraint_get_multiplier:
* @constraint: a #GtkConstraint
*
* Retrieves the multiplication factor applied to the source
* attribute's value.
*
* Returns: a multiplication factor
*/
double
gtk_constraint_get_multiplier (GtkConstraint *constraint)
{
@@ -472,6 +489,14 @@ gtk_constraint_get_multiplier (GtkConstraint *constraint)
return constraint->multiplier;
}
/**
* gtk_constraint_get_constant:
* @constraint: a #GtkConstraint
*
* Retrieves the constant factor added to the source attributes' value.
*
* Returns: a constant factor
*/
double
gtk_constraint_get_constant (GtkConstraint *constraint)
{
@@ -480,6 +505,14 @@ gtk_constraint_get_constant (GtkConstraint *constraint)
return constraint->constant;
}
/**
* gtk_constraint_get_strength:
* @constraint: a #GtkConstraint
*
* Retrieves the strength of the constraint.
*
* Returns: the strength of the constraint
*/
int
gtk_constraint_get_strength (GtkConstraint *constraint)
{
@@ -488,42 +521,6 @@ gtk_constraint_get_strength (GtkConstraint *constraint)
return constraint->strength;
}
/*< private >
* gtk_constraint_get_weight:
* @constraint: a #GtkConstraint
*
* Computes the weight of the @constraint to be used with
* #GtkConstraintSolver.
*
* Returns: the weight of the constraint
*/
double
gtk_constraint_get_weight (GtkConstraint *constraint)
{
if (constraint->strength > 0)
return constraint->strength;
switch (constraint->strength)
{
case GTK_CONSTRAINT_STRENGTH_REQUIRED:
return GTK_CONSTRAINT_WEIGHT_REQUIRED;
case GTK_CONSTRAINT_STRENGTH_STRONG:
return GTK_CONSTRAINT_WEIGHT_STRONG;
case GTK_CONSTRAINT_STRENGTH_MEDIUM:
return GTK_CONSTRAINT_WEIGHT_MEDIUM;
case GTK_CONSTRAINT_STRENGTH_WEAK:
return GTK_CONSTRAINT_WEIGHT_WEAK;
default:
g_assert_not_reached ();
}
return 0;
}
/**
* gtk_constraint_is_required:
* @constraint: a #GtkConstraint

View File

@@ -73,15 +73,11 @@ GtkConstraint * gtk_constraint_new_constant (gpointer
double constant,
int strength);
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_constraint_get_target_widget (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
GtkConstraintTarget * gtk_constraint_get_target (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
GtkConstraintAttribute gtk_constraint_get_target_attribute (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_constraint_get_source_widget (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
GtkConstraintTarget * gtk_constraint_get_source (GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
GtkConstraintAttribute gtk_constraint_get_source_attribute (GtkConstraint *constraint);

View File

@@ -371,11 +371,8 @@ gtk_constraint_variable_is_dummy (const GtkConstraintVariable *variable)
* A set of variables.
*/
struct _GtkConstraintVariableSet {
/* HashSet<Variable>, owns a reference */
GHashTable *set;
/* List<Variable>, used for iterating */
GList *ordered_set;
/* List<Variable>, owns a reference */
GSequence *set;
/* Age of the set, to guard against mutations while iterating */
gint64 age;
@@ -392,8 +389,7 @@ gtk_constraint_variable_set_free (GtkConstraintVariableSet *set)
{
g_return_if_fail (set != NULL);
g_list_free (set->ordered_set);
g_hash_table_unref (set->set);
g_sequence_free (set->set);
g_free (set);
}
@@ -410,10 +406,7 @@ gtk_constraint_variable_set_new (void)
{
GtkConstraintVariableSet *res = g_new (GtkConstraintVariableSet, 1);
res->set = g_hash_table_new_full (NULL, NULL,
(GDestroyNotify) gtk_constraint_variable_unref,
NULL);
res->ordered_set = NULL;
res->set = g_sequence_new ((GDestroyNotify) gtk_constraint_variable_unref);
res->age = 0;
@@ -422,7 +415,8 @@ gtk_constraint_variable_set_new (void)
static int
sort_by_variable_id (gconstpointer a,
gconstpointer b)
gconstpointer b,
gpointer data)
{
const GtkConstraintVariable *va = a, *vb = b;
@@ -450,16 +444,17 @@ gboolean
gtk_constraint_variable_set_add (GtkConstraintVariableSet *set,
GtkConstraintVariable *variable)
{
if (g_hash_table_contains (set->set, variable))
return FALSE;
GSequenceIter *iter;
g_hash_table_add (set->set, gtk_constraint_variable_ref (variable));
iter = g_sequence_search (set->set, variable, sort_by_variable_id, NULL);
if (!g_sequence_iter_is_end (iter))
{
GtkConstraintVariable *v = g_sequence_get (iter);
if (v->_id == variable->_id)
return FALSE;
}
/* This is a tricky bit; the variables in the set must be ordered
* not by insertion, but by the incremental id of each variable,
* as that's the expected iteration order
*/
set->ordered_set = g_list_insert_sorted (set->ordered_set, variable, sort_by_variable_id);
g_sequence_insert_before (iter, gtk_constraint_variable_ref (variable));
set->age += 1;
@@ -482,10 +477,12 @@ gboolean
gtk_constraint_variable_set_remove (GtkConstraintVariableSet *set,
GtkConstraintVariable *variable)
{
if (g_hash_table_contains (set->set, variable))
GSequenceIter *iter;
iter = g_sequence_lookup (set->set, variable, sort_by_variable_id, NULL);
if (iter != NULL)
{
set->ordered_set = g_list_remove (set->ordered_set, variable);
g_hash_table_remove (set->set, variable);
g_sequence_remove (iter);
set->age += 1;
return TRUE;
@@ -505,7 +502,19 @@ gtk_constraint_variable_set_remove (GtkConstraintVariableSet *set,
int
gtk_constraint_variable_set_size (GtkConstraintVariableSet *set)
{
return g_hash_table_size (set->set);
return g_sequence_get_length (set->set);
}
gboolean
gtk_constraint_variable_set_is_empty (GtkConstraintVariableSet *set)
{
return g_sequence_is_empty (set->set);
}
gboolean
gtk_constraint_variable_set_is_singleton (GtkConstraintVariableSet *set)
{
return g_sequence_iter_next (g_sequence_get_begin_iter (set->set)) == g_sequence_get_end_iter (set->set);
}
/*< private >
@@ -516,7 +525,7 @@ gtk_constraint_variable_set_size (GtkConstraintVariableSet *set)
/* Keep in sync with GtkConstraintVariableSetIter */
typedef struct {
GtkConstraintVariableSet *set;
GList *current;
GSequenceIter *iter;
gint64 age;
} RealVariableSetIter;
@@ -539,7 +548,7 @@ gtk_constraint_variable_set_iter_init (GtkConstraintVariableSetIter *iter,
g_return_if_fail (set != NULL);
riter->set = set;
riter->current = NULL;
riter->iter = g_sequence_get_begin_iter (set->set);
riter->age = set->age;
}
@@ -563,15 +572,13 @@ gtk_constraint_variable_set_iter_next (GtkConstraintVariableSetIter *iter,
g_assert (riter->age == riter->set->age);
if (riter->current == NULL)
riter->current = riter->set->ordered_set;
else
riter->current = riter->current->next;
if (g_sequence_iter_is_end (riter->iter))
return FALSE;
if (riter->current != NULL)
*variable_p = riter->current->data;
*variable_p = g_sequence_get (riter->iter);
riter->iter = g_sequence_iter_next (riter->iter);
return riter->current != NULL;
return TRUE;
}
/*< private >

View File

@@ -94,6 +94,12 @@ gboolean
gtk_constraint_variable_set_remove (GtkConstraintVariableSet *set,
GtkConstraintVariable *variable);
gboolean
gtk_constraint_variable_set_is_empty (GtkConstraintVariableSet *set);
gboolean
gtk_constraint_variable_set_is_singleton (GtkConstraintVariableSet *set);
int
gtk_constraint_variable_set_size (GtkConstraintVariableSet *set);

694
gtk/gtkconstraintguide.c Normal file
View File

@@ -0,0 +1,694 @@
/* gtkconstraintguide.c: Flexible space for constraints
* Copyright 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
/**
* SECTION:gtkconstraintguide
* @Title: GtkConstraintGuide
* @Short_description: An invisible constraint target
*
* A #GtkConstraintGuide is an invisible layout element that can be
* used by widgets inside a #GtkConstraintLayout as a source or a target
* of a #GtkConstraint. Guides can be used like guidelines or as
* flexible space.
*
* Unlike a #GtkWidget, a #GtkConstraintGuide will not be drawn.
*/
#include "config.h"
#include "gtkconstraintguide.h"
#include "gtkconstraintguideprivate.h"
#include "gtkconstraintlayoutprivate.h"
#include "gtkconstraintexpressionprivate.h"
#include "gtkconstraintsolverprivate.h"
#include "gtkdebug.h"
#include "gtkintl.h"
#include "gtkprivate.h"
typedef enum {
MIN_WIDTH,
MIN_HEIGHT,
NAT_WIDTH,
NAT_HEIGHT,
MAX_WIDTH,
MAX_HEIGHT,
LAST_VALUE
} GuideValue;
struct _GtkConstraintGuide
{
GObject parent_instance;
char *name;
int strength;
int values[LAST_VALUE];
GtkConstraintLayout *layout;
/* HashTable<static string, Variable>; a hash table of variables,
* one for each attribute; we use these to query and suggest the
* values for the solver. The string is static and does not need
* to be freed.
*/
GHashTable *bound_attributes;
GtkConstraintRef *constraints[LAST_VALUE];
};
struct _GtkConstraintGuideClass {
GObjectClass parent_class;
};
enum {
PROP_MIN_WIDTH = 1,
PROP_MIN_HEIGHT,
PROP_NAT_WIDTH,
PROP_NAT_HEIGHT,
PROP_MAX_WIDTH,
PROP_MAX_HEIGHT,
PROP_STRENGTH,
PROP_NAME,
LAST_PROP
};
static GParamSpec *guide_props[LAST_PROP];
static void
gtk_constraint_guide_constraint_target_iface_init (GtkConstraintTargetInterface *iface)
{
}
G_DEFINE_TYPE_WITH_CODE (GtkConstraintGuide, gtk_constraint_guide, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_CONSTRAINT_TARGET,
gtk_constraint_guide_constraint_target_iface_init))
static void
gtk_constraint_guide_init (GtkConstraintGuide *guide)
{
guide->strength = GTK_CONSTRAINT_STRENGTH_MEDIUM;
guide->values[MIN_WIDTH] = 0;
guide->values[MIN_HEIGHT] = 0;
guide->values[NAT_WIDTH] = 0;
guide->values[NAT_HEIGHT] = 0;
guide->values[MAX_WIDTH] = G_MAXINT;
guide->values[MAX_HEIGHT] = G_MAXINT;
guide->bound_attributes =
g_hash_table_new_full (g_str_hash, g_str_equal,
NULL,
(GDestroyNotify) gtk_constraint_variable_unref);
}
static void
gtk_constraint_guide_update_constraint (GtkConstraintGuide *guide,
GuideValue index)
{
GtkConstraintSolver *solver;
GtkConstraintVariable *var;
if (!guide->layout)
return;
solver = gtk_constraint_layout_get_solver (guide->layout);
if (!solver)
return;
if (guide->constraints[index] != NULL)
{
gtk_constraint_solver_remove_constraint (solver, guide->constraints[index]);
guide->constraints[index] = NULL;
}
if (index == MIN_WIDTH || index == NAT_WIDTH || index == MAX_WIDTH)
var = gtk_constraint_layout_get_attribute (guide->layout, GTK_CONSTRAINT_ATTRIBUTE_WIDTH, "guide", NULL, guide->bound_attributes);
else
var = gtk_constraint_layout_get_attribute (guide->layout, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT, "guide", NULL, guide->bound_attributes);
/* We always install min-size constraints,
* but we avoid nat-size constraints if min == max
* and we avoid max-size constraints if max == G_MAXINT
*/
if (index == MIN_WIDTH || index == MIN_HEIGHT)
{
guide->constraints[index] =
gtk_constraint_solver_add_constraint (solver,
var,
GTK_CONSTRAINT_RELATION_GE,
gtk_constraint_expression_new (guide->values[index]),
GTK_CONSTRAINT_STRENGTH_REQUIRED);
}
else if ((index == NAT_WIDTH && guide->values[MIN_WIDTH] != guide->values[MAX_WIDTH]) ||
(index == NAT_HEIGHT && guide->values[MIN_HEIGHT] != guide->values[MAX_HEIGHT]))
{
gtk_constraint_variable_set_value (var, guide->values[index]);
guide->constraints[index] =
gtk_constraint_solver_add_stay_variable (solver,
var,
guide->strength);
}
else if ((index == MAX_WIDTH || index == MAX_HEIGHT) &&
guide->values[index] < G_MAXINT)
{
guide->constraints[index] =
gtk_constraint_solver_add_constraint (solver,
var,
GTK_CONSTRAINT_RELATION_LE,
gtk_constraint_expression_new (guide->values[index]),
GTK_CONSTRAINT_STRENGTH_REQUIRED);
}
gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (guide->layout));
}
void
gtk_constraint_guide_update (GtkConstraintGuide *guide)
{
int i;
for (i = 0; i < LAST_VALUE; i++)
gtk_constraint_guide_update_constraint (guide, i);
}
void
gtk_constraint_guide_detach (GtkConstraintGuide *guide)
{
GtkConstraintSolver *solver;
int i;
if (!guide->layout)
return;
solver = gtk_constraint_layout_get_solver (guide->layout);
if (!solver)
return;
for (i = 0; i < LAST_VALUE; i++)
{
if (guide->constraints[i])
{
gtk_constraint_solver_remove_constraint (solver, guide->constraints[i]);
guide->constraints[i] = NULL;
}
}
g_hash_table_remove_all (guide->bound_attributes);
}
GtkConstraintVariable *
gtk_constraint_guide_get_attribute (GtkConstraintGuide *guide,
GtkConstraintAttribute attr)
{
GtkLayoutManager *manager = GTK_LAYOUT_MANAGER (guide->layout);
GtkWidget *widget = gtk_layout_manager_get_widget (manager);
return gtk_constraint_layout_get_attribute (guide->layout, attr, "guide", widget, guide->bound_attributes);
}
GtkConstraintLayout *
gtk_constraint_guide_get_layout (GtkConstraintGuide *guide)
{
return guide->layout;
}
void
gtk_constraint_guide_set_layout (GtkConstraintGuide *guide,
GtkConstraintLayout *layout)
{
guide->layout = layout;
}
static void
gtk_constraint_guide_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkConstraintGuide *self = GTK_CONSTRAINT_GUIDE (gobject);
int val;
GuideValue index;
switch (prop_id)
{
case PROP_MIN_WIDTH:
case PROP_MIN_HEIGHT:
case PROP_NAT_WIDTH:
case PROP_NAT_HEIGHT:
case PROP_MAX_WIDTH:
case PROP_MAX_HEIGHT:
val = g_value_get_int (value);
index = prop_id - 1;
if (self->values[index] != val)
{
self->values[index] = val;
g_object_notify_by_pspec (gobject, pspec);
gtk_constraint_guide_update_constraint (self, index);
if (index == MIN_WIDTH || index == MAX_WIDTH)
gtk_constraint_guide_update_constraint (self, NAT_WIDTH);
if (index == MIN_HEIGHT || index == MAX_HEIGHT)
gtk_constraint_guide_update_constraint (self, NAT_HEIGHT);
}
break;
case PROP_STRENGTH:
gtk_constraint_guide_set_strength (self, g_value_get_enum (value));
break;
case PROP_NAME:
gtk_constraint_guide_set_name (self, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gtk_constraint_guide_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkConstraintGuide *self = GTK_CONSTRAINT_GUIDE (gobject);
switch (prop_id)
{
case PROP_MIN_WIDTH:
case PROP_MIN_HEIGHT:
case PROP_NAT_WIDTH:
case PROP_NAT_HEIGHT:
case PROP_MAX_WIDTH:
case PROP_MAX_HEIGHT:
g_value_set_int (value, self->values[prop_id - 1]);
break;
case PROP_STRENGTH:
g_value_set_enum (value, self->strength);
break;
case PROP_NAME:
g_value_set_string (value, self->name);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gtk_constraint_guide_finalize (GObject *object)
{
GtkConstraintGuide *self = GTK_CONSTRAINT_GUIDE (object);
g_free (self->name);
g_clear_pointer (&self->bound_attributes, g_hash_table_unref);
G_OBJECT_CLASS (gtk_constraint_guide_parent_class)->finalize (object);
}
static void
gtk_constraint_guide_class_init (GtkConstraintGuideClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = gtk_constraint_guide_finalize;
object_class->set_property = gtk_constraint_guide_set_property;
object_class->get_property = gtk_constraint_guide_get_property;
/**
* GtkConstraintGuide:min-width:
*
* The minimum width of the guide.
*/
guide_props[PROP_MIN_WIDTH] =
g_param_spec_int ("min-width",
"Minimum width",
"Minimum width",
0, G_MAXINT, 0,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:min-height:
*
* The minimum height of the guide.
*/
guide_props[PROP_MIN_HEIGHT] =
g_param_spec_int ("min-height",
"Minimum height",
"Minimum height",
0, G_MAXINT, 0,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:nat-width:
*
* The preferred, or natural, width of the guide.
*/
guide_props[PROP_NAT_WIDTH] =
g_param_spec_int ("nat-width",
"Natural width",
"Natural width",
0, G_MAXINT, 0,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:nat-height:
*
* The preferred, or natural, height of the guide.
*/
guide_props[PROP_NAT_HEIGHT] =
g_param_spec_int ("nat-height",
"Natural height",
"Natural height",
0, G_MAXINT, 0,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:max-width:
*
* The maximum width of the guide.
*/
guide_props[PROP_MAX_WIDTH] =
g_param_spec_int ("max-width",
"Maximum width",
"Maximum width",
0, G_MAXINT, G_MAXINT,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:max-height:
*
* The maximum height of the guide.
*/
guide_props[PROP_MAX_HEIGHT] =
g_param_spec_int ("max-height",
"Maximum height",
"Maximum height",
0, G_MAXINT, G_MAXINT,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:strength:
*
* The #GtkConstraintStrength to be used for the constraint on
* the natural size of the guide.
*/
guide_props[PROP_STRENGTH] =
g_param_spec_enum ("strength",
"Strength",
"The strength to use for natural size",
GTK_TYPE_CONSTRAINT_STRENGTH,
GTK_CONSTRAINT_STRENGTH_MEDIUM,
G_PARAM_READWRITE|
G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkConstraintGuide:name:
*
* A name that identifies the #GtkConstraintGuide, for debugging.
*/
guide_props[PROP_NAME] =
g_param_spec_string ("name",
"Name",
"A name to use in debug message",
NULL,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, LAST_PROP, guide_props);
}
/**
* gtk_constraint_guide_new:
*
* Creates a new #GtkConstraintGuide object.
*
* Return: a new #GtkConstraintGuide object.
*/
GtkConstraintGuide *
gtk_constraint_guide_new (void)
{
return g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL);
}
/**
* gtk_constraint_guide_set_min_size:
* @guide: a #GtkConstraintGuide object
* @width: the new minimum width, or -1 to not change it
* @height: the new minimum height, or -1 to not change it
*
* Sets the minimum size of @guide.
*
* If @guide is attached to a #GtkConstraintLayout,
* the constraints will be updated to reflect the new size.
*/
void
gtk_constraint_guide_set_min_size (GtkConstraintGuide *guide,
int width,
int height)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
g_return_if_fail (width >= -1);
g_return_if_fail (height >= -1);
g_object_freeze_notify (G_OBJECT (guide));
if (width != -1)
g_object_set (guide, "min-width", width, NULL);
if (height != -1)
g_object_set (guide, "min-height", height, NULL);
g_object_thaw_notify (G_OBJECT (guide));
}
/**
* gtk_constraint_guide_get_min_size:
* @guide: a #GtkContraintGuide object
* @width: (allow-none): return location for the minimum width,
* or %NULL
* @height: (allow-none): return location for the minimum height,
* or %NULL
*
* Gets the minimum size of @guide.
*/
void
gtk_constraint_guide_get_min_size (GtkConstraintGuide *guide,
int *width,
int *height)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
if (width)
*width = guide->values[MIN_WIDTH];
if (height)
*height = guide->values[MIN_HEIGHT];
}
/**
* gtk_constraint_guide_set_nat_size:
* @guide: a #GtkConstraintGuide object
* @width: the new natural width, or -1 to not change it
* @height: the new natural height, or -1 to not change it
*
* Sets the natural size of @guide.
*
* If @guide is attached to a #GtkConstraintLayout,
* the constraints will be updated to reflect the new size.
*/
void
gtk_constraint_guide_set_nat_size (GtkConstraintGuide *guide,
int width,
int height)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
g_return_if_fail (width >= -1);
g_return_if_fail (height >= -1);
g_object_freeze_notify (G_OBJECT (guide));
if (width != -1)
g_object_set (guide, "nat-width", width, NULL);
if (height != -1)
g_object_set (guide, "nat-height", height, NULL);
g_object_thaw_notify (G_OBJECT (guide));
}
/**
* gtk_constraint_guide_get_nat_size:
* @guide: a #GtkContraintGuide object
* @width: (allow-none): return location for the natural width,
* or %NULL
* @height: (allow-none): return location for the natural height,
* or %NULL
*
* Gets the natural size of @guide.
*/
void
gtk_constraint_guide_get_nat_size (GtkConstraintGuide *guide,
int *width,
int *height)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
if (width)
*width = guide->values[NAT_WIDTH];
if (height)
*height = guide->values[NAT_HEIGHT];
}
/**
* gtk_constraint_guide_set_max_size:
* @guide: a #GtkConstraintGuide object
* @width: the new maximum width, or -1 to not change it
* @height: the new maximum height, or -1 to not change it
*
* Sets the maximum size of @guide.
*
* If @guide is attached to a #GtkConstraintLayout,
* the constraints will be updated to reflect the new size.
*/
void
gtk_constraint_guide_set_max_size (GtkConstraintGuide *guide,
int width,
int height)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
g_return_if_fail (width >= -1);
g_return_if_fail (height >= -1);
g_object_freeze_notify (G_OBJECT (guide));
if (width != -1)
g_object_set (guide, "max-width", width, NULL);
if (height != -1)
g_object_set (guide, "max-height", height, NULL);
g_object_thaw_notify (G_OBJECT (guide));
}
/**
* gtk_constraint_guide_get_max_size:
* @guide: a #GtkContraintGuide object
* @width: (allow-none): return location for the maximum width,
* or %NULL
* @height: (allow-none): return location for the maximum height,
* or %NULL
*
* Gets the maximum size of @guide.
*/
void
gtk_constraint_guide_get_max_size (GtkConstraintGuide *guide,
int *width,
int *height)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
if (width)
*width = guide->values[MAX_WIDTH];
if (height)
*height = guide->values[MAX_HEIGHT];
}
/**
* gtk_constraint_guide_get_name:
* @guide: a #GtkConstraintGuide
*
* Retrieves the name set using gtk_constraint_guide_set_name().
*
* Returns: (transfer none) (nullable): the name of the guide
*/
const char *
gtk_constraint_guide_get_name (GtkConstraintGuide *guide)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide), NULL);
return guide->name;
}
/**
* gtk_constraint_guide_set_name:
* @guide: a #GtkConstraintGuide
* @name: (nullable): a name for the @guide
*
* Sets a name for the given #GtkConstraintGuide.
*
* The name is useful for debugging purposes.
*/
void
gtk_constraint_guide_set_name (GtkConstraintGuide *guide,
const char *name)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
g_free (guide->name);
guide->name = g_strdup (name);
g_object_notify_by_pspec (G_OBJECT (guide), guide_props[PROP_NAME]);
}
/**
* gtk_constraint_guide_get_strength:
* @guide: a #GtkConstraintGuide
*
* Retrieves the strength set using gtk_constraint_guide_set_strength().
*
* Returns: the strength of the constraint on the natural size
*/
GtkConstraintStrength
gtk_constraint_guide_get_strength (GtkConstraintGuide *guide)
{
g_return_val_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide),
GTK_CONSTRAINT_STRENGTH_MEDIUM);
return guide->strength;
}
/**
* gtk_constraint_guide_set_strength:
* @guide: a #GtkConstraintGuide
* @strength: the strength of the constraint
*
* Sets the strength of the constraint on the natural size of the
* given #GtkConstraintGuide.
*/
void
gtk_constraint_guide_set_strength (GtkConstraintGuide *guide,
GtkConstraintStrength strength)
{
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
if (guide->strength == strength)
return;
guide->strength = strength;
g_object_notify_by_pspec (G_OBJECT (guide), guide_props[PROP_STRENGTH]);
gtk_constraint_guide_update_constraint (guide, NAT_WIDTH);
gtk_constraint_guide_update_constraint (guide, NAT_HEIGHT);
}

83
gtk/gtkconstraintguide.h Normal file
View File

@@ -0,0 +1,83 @@
/* gtkconstraintguide.h: Flexible space for constraints
* Copyright 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#pragma once
#include <gtk/gtktypes.h>
#include <gtk/gtkenums.h>
#include <gtk/gtktypebuiltins.h>
G_BEGIN_DECLS
#define GTK_TYPE_CONSTRAINT_GUIDE (gtk_constraint_guide_get_type ())
/**
* GtkConstraintGuide:
*
* An object that can be added to a #GtkConstraintLayout and be
* used in constraints like a widget, without being drawn.
*
* Guides have a minimum, maximum and natural size. Depending
* on the constraints that are applied, they can act like a
* guideline that widgets can be aligned to, or like 'flexible space'.
*/
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (GtkConstraintGuide, gtk_constraint_guide, GTK, CONSTRAINT_GUIDE, GObject)
GDK_AVAILABLE_IN_ALL
GtkConstraintGuide * gtk_constraint_guide_new (void);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_set_min_size (GtkConstraintGuide *guide,
int width,
int height);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_get_min_size (GtkConstraintGuide *guide,
int *width,
int *height);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_set_nat_size (GtkConstraintGuide *guide,
int width,
int height);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_get_nat_size (GtkConstraintGuide *guide,
int *width,
int *height);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_set_max_size (GtkConstraintGuide *guide,
int width,
int height);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_get_max_size (GtkConstraintGuide *guide,
int *width,
int *height);
GDK_AVAILABLE_IN_ALL
GtkConstraintStrength gtk_constraint_guide_get_strength (GtkConstraintGuide *guide);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_set_strength (GtkConstraintGuide *guide,
GtkConstraintStrength strength);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_guide_set_name (GtkConstraintGuide *guide,
const char *name);
GDK_AVAILABLE_IN_ALL
const char * gtk_constraint_guide_get_name (GtkConstraintGuide *guide);
G_END_DECLS

View File

@@ -0,0 +1,38 @@
/* gtkconstraintguideprivate.h: Constraint between two widgets
* Copyright 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#pragma once
#include "gtkconstraintguide.h"
#include "gtkconstraintlayout.h"
#include "gtkconstrainttypesprivate.h"
G_BEGIN_DECLS
void gtk_constraint_guide_update (GtkConstraintGuide *guide);
void gtk_constraint_guide_detach (GtkConstraintGuide *guide);
GtkConstraintVariable *gtk_constraint_guide_get_attribute (GtkConstraintGuide *guide,
GtkConstraintAttribute attr);
GtkConstraintLayout *gtk_constraint_guide_get_layout (GtkConstraintGuide *guide);
void gtk_constraint_guide_set_layout (GtkConstraintGuide *guide,
GtkConstraintLayout *layout);
G_END_DECLS

File diff suppressed because it is too large Load Diff

View File

@@ -20,12 +20,13 @@
#include <gtk/gtklayoutmanager.h>
#include <gtk/gtkconstraint.h>
#include <gtk/gtkconstraintguide.h>
G_BEGIN_DECLS
#define GTK_TYPE_CONSTRAINT_LAYOUT (gtk_constraint_layout_get_type ())
#define GTK_TYPE_CONSTRAINT_LAYOUT_CHILD (gtk_constraint_layout_child_get_type ())
#define GTK_TYPE_CONSTRAINT_GUIDE (gtk_constraint_guide_get_type ())
#define GTK_CONSTRAINT_VFL_PARSER_ERROR (gtk_constraint_vfl_parser_error_quark ())
/**
* GtkConstraintLayoutChild:
@@ -35,21 +36,6 @@ G_BEGIN_DECLS
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (GtkConstraintLayoutChild, gtk_constraint_layout_child, GTK, CONSTRAINT_LAYOUT_CHILD, GtkLayoutChild)
/**
* GtkConstraintGuide:
*
* An object that can be added to a #GtkConstraintLayout and be
* used in constraints like a widget, without being drawn. Guides
* have a minimal and natural size. Depending on the constraints
* that are applied, they can act like a guideline that widgets
* can be aligned to, or like 'flexible space'.
*/
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (GtkConstraintGuide, gtk_constraint_guide, GTK, CONSTRAINT_GUIDE, GObject)
GDK_AVAILABLE_IN_ALL
GtkConstraintGuide * gtk_constraint_guide_new (void);
/**
* GtkConstraintLayout:
*
@@ -59,25 +45,30 @@ GtkConstraintGuide * gtk_constraint_guide_new (void);
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (GtkConstraintLayout, gtk_constraint_layout, GTK, CONSTRAINT_LAYOUT, GtkLayoutManager)
GDK_AVAILABLE_IN_ALL
GQuark gtk_constraint_vfl_parser_error_quark (void);
GDK_AVAILABLE_IN_ALL
GtkLayoutManager * gtk_constraint_layout_new (void);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_layout_add_constraint (GtkConstraintLayout *manager,
void gtk_constraint_layout_add_constraint (GtkConstraintLayout *layout,
GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_layout_remove_constraint (GtkConstraintLayout *manager,
void gtk_constraint_layout_remove_constraint (GtkConstraintLayout *layout,
GtkConstraint *constraint);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_layout_add_guide (GtkConstraintLayout *manager,
void gtk_constraint_layout_add_guide (GtkConstraintLayout *layout,
GtkConstraintGuide *guide);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_layout_remove_guide (GtkConstraintLayout *manager,
void gtk_constraint_layout_remove_guide (GtkConstraintLayout *layout,
GtkConstraintGuide *guide);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_layout_remove_all_constraints (GtkConstraintLayout *layout);
GDK_AVAILABLE_IN_ALL
gboolean gtk_constraint_layout_add_constraints_from_description (GtkConstraintLayout *manager,
GList * gtk_constraint_layout_add_constraints_from_description (GtkConstraintLayout *layout,
const char * const lines[],
gsize n_lines,
int hspacing,
@@ -86,7 +77,7 @@ gboolean gtk_constraint_layout_add_constraints_from_description
const char *first_view,
...) G_GNUC_NULL_TERMINATED;
GDK_AVAILABLE_IN_ALL
gboolean gtk_constraint_layout_add_constraints_from_descriptionv (GtkConstraintLayout *manager,
GList * gtk_constraint_layout_add_constraints_from_descriptionv (GtkConstraintLayout *layout,
const char * const lines[],
gsize n_lines,
int hspacing,
@@ -95,6 +86,8 @@ gboolean gtk_constraint_layout_add_constraints_from_descriptionv
GError **error);
GDK_AVAILABLE_IN_ALL
void gtk_constraint_layout_remove_all_constraints (GtkConstraintLayout *manager);
GListModel * gtk_constraint_layout_observe_constraints (GtkConstraintLayout *layout);
GDK_AVAILABLE_IN_ALL
GListModel * gtk_constraint_layout_observe_guides (GtkConstraintLayout *layout);
G_END_DECLS

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#pragma once
#include "gtkconstraintlayout.h"
#include "gtkconstraintsolverprivate.h"
G_BEGIN_DECLS
GtkConstraintSolver *
gtk_constraint_layout_get_solver (GtkConstraintLayout *layout);
GtkConstraintVariable *
gtk_constraint_layout_get_attribute (GtkConstraintLayout *layout,
GtkConstraintAttribute attr,
const char *prefix,
GtkWidget *widget,
GHashTable *bound_attributes);
G_END_DECLS

View File

@@ -52,8 +52,6 @@ struct _GtkConstraint
guint active : 1;
};
double gtk_constraint_get_weight (GtkConstraint *constraint);
void gtk_constraint_attach (GtkConstraint *constraint,
GtkConstraintSolver *solver,
GtkConstraintRef *ref);

View File

@@ -73,14 +73,14 @@
* e = gtk_constraint_expression_builder_finish (&builder);
* gtk_constraint_solver_add_constraint (solver,
* right, GTK_CONSTRAINT_RELATION_EQ, e,
* GTK_CONSTRAINT_WEIGHT_REQUIRED);
* GTK_CONSTRAINT_STRENGTH_REQUIRED);
*
* // right ≤ 100
* gtk_constraint_expression_builder_constant (&builder, 100.0);
* e = gtk_constraint_expression_builder_finish (&builder);
* gtk_constraint_solver_add_constraint (solver,
* right, GTK_CONSTRAINT_RELATION_LE, e,
* GTK_CONSTRAINT_WEIGHT_REQUIRED);
* GTK_CONSTRAINT_STRENGTH_REQUIRED);
*
* // middle = (left + right) / 2
* gtk_constraint_expression_builder_term (&builder, left);
@@ -91,14 +91,14 @@
* e = gtk_constraint_expression_builder_finish (&builder);
* gtk_constraint_solver_add_constraint (solver
* middle, GTK_CONSTRAINT_RELATION_EQ, e,
* GTK_CONSTRAINT_WEIGHT_REQUIRED);
* GTK_CONSTRAINT_STRENGTH_REQUIRED);
*
* // left ≥ 0
* gtk_constraint_expression_builder_constant (&builder, 0.0);
* e = gtk_constraint_expression_builder_finish (&builder);
* gtk_constraint_solver_add_constraint (solver,
* left, GTK_CONSTRAINT_RELATION_GE, e,
* GTK_CONSTRAINT_WEIGHT_REQUIRED);
* GTK_CONSTRAINT_STRENGTH_REQUIRED);
* ]|
*
* Now that we have all our constraints in place, suppose we wish to find
@@ -110,8 +110,8 @@
* |[
* // Set the value first
* gtk_constraint_variable_set_value (middle, 45.0);
* // and then add the stay constraint, with a weak weight
* gtk_constraint_solver_add_stay_variable (solver, middle, GTK_CONSTRAINT_WEIGHT_WEAK);
* // and then add the stay constraint, with a weak strength
* gtk_constraint_solver_add_stay_variable (solver, middle, GTK_CONSTRAINT_STRENGTH_WEAK);
* ]|
*
* GtkConstraintSolver incrementally solves the system every time a constraint
@@ -185,8 +185,11 @@ struct _GtkConstraintRef
/* The original relation used when creating the constraint */
GtkConstraintRelation relation;
/* The weight, or strength, of the constraint */
double weight;
/* The strength of the constraint; this value is used to strengthen
* or weaken a constraint weight in the tableau when coming to a
* solution
*/
int strength;
GtkConstraintSolver *solver;
@@ -374,7 +377,7 @@ gtk_constraint_ref_is_inequality (const GtkConstraintRef *self)
static gboolean
gtk_constraint_ref_is_required (const GtkConstraintRef *self)
{
return self->weight >= GTK_CONSTRAINT_WEIGHT_REQUIRED;
return self->strength == GTK_CONSTRAINT_STRENGTH_REQUIRED;
}
static const char *relations[] = {
@@ -390,15 +393,12 @@ relation_to_string (GtkConstraintRelation r)
}
static const char *
weight_to_string (double s)
strength_to_string (int s)
{
if (s >= GTK_CONSTRAINT_WEIGHT_REQUIRED)
return "required";
if (s >= GTK_CONSTRAINT_WEIGHT_STRONG)
if (s >= GTK_CONSTRAINT_STRENGTH_STRONG)
return "strong";
if (s >= GTK_CONSTRAINT_WEIGHT_MEDIUM)
if (s >= GTK_CONSTRAINT_STRENGTH_MEDIUM)
return "medium";
return "weak";
@@ -423,9 +423,12 @@ gtk_constraint_ref_to_string (const GtkConstraintRef *self)
g_string_append (buf, relation_to_string (self->relation));
g_string_append (buf, " 0.0");
g_string_append_printf (buf, " [weight:%s (%g)]",
weight_to_string (self->weight),
self->weight);
if (gtk_constraint_ref_is_required (self))
g_string_append (buf, " [strength:required]");
else
g_string_append_printf (buf, " [strength:%d (%s)]",
self->strength,
strength_to_string (self->strength));
return g_string_free (buf, FALSE);
}
@@ -736,17 +739,12 @@ gtk_constraint_solver_optimize (GtkConstraintSolver *self,
self->optimize_count += 1;
#ifdef G_ENABLE_DEBUG
{
char *str;
str = gtk_constraint_variable_to_string (z);
g_debug ("optimize: %s\n", str);
g_free (str);
str = gtk_constraint_solver_to_string (self);
g_debug ("%s\n", str);
g_free (str);
}
if (GTK_DEBUG_CHECK (CONSTRAINTS))
{
char *str = gtk_constraint_variable_to_string (z);
g_message ("optimize: %s", str);
g_free (str);
}
#endif
while (TRUE)
@@ -802,28 +800,28 @@ gtk_constraint_solver_optimize (GtkConstraintSolver *self,
if (min_ratio == DBL_MAX)
{
g_debug ("Unbounded objective variable during optimization");
GTK_NOTE (CONSTRAINTS, g_message ("Unbounded objective variable during optimization"));
break;
}
#ifdef G_ENABLE_DEBUG
{
char *entry_s = gtk_constraint_variable_to_string (entry);
char *exit_s = gtk_constraint_variable_to_string (exit);
g_debug ("pivot(entry: %s, exit: %s)", entry_s, exit_s);
g_free (entry_s);
g_free (exit_s);
}
if (GTK_DEBUG_CHECK (CONSTRAINTS))
{
char *entry_s = gtk_constraint_variable_to_string (entry);
char *exit_s = gtk_constraint_variable_to_string (exit);
g_message ("pivot(entry: %s, exit: %s)", entry_s, exit_s);
g_free (entry_s);
g_free (exit_s);
}
#endif
gtk_constraint_solver_pivot (self, entry, exit);
}
#ifdef G_ENABLE_DEBUG
g_debug ("solver.optimize.time := %.3f ms (pass: %d)",
(float) (g_get_monotonic_time () - start_time) / 1000.f,
self->optimize_count);
#endif
GTK_NOTE (CONSTRAINTS,
g_message ("solver.optimize.time := %.3f ms (pass: %d)",
(float) (g_get_monotonic_time () - start_time) / 1000.f,
self->optimize_count));
}
/*< private >
@@ -914,7 +912,7 @@ gtk_constraint_solver_new_expression (GtkConstraintSolver *self,
gtk_constraint_variable_unref (eminus);
z_row = g_hash_table_lookup (self->rows, self->objective);
gtk_constraint_expression_set_variable (z_row, eminus, constraint->weight);
gtk_constraint_expression_set_variable (z_row, eminus, constraint->strength);
gtk_constraint_solver_insert_error_variable (self, constraint, eminus);
gtk_constraint_solver_note_added_variable (self, eminus, self->objective);
@@ -973,8 +971,8 @@ gtk_constraint_solver_new_expression (GtkConstraintSolver *self,
z_row = g_hash_table_lookup (self->rows, self->objective);
gtk_constraint_expression_set_variable (z_row, eplus, constraint->weight);
gtk_constraint_expression_set_variable (z_row, eminus, constraint->weight);
gtk_constraint_expression_set_variable (z_row, eplus, constraint->strength);
gtk_constraint_expression_set_variable (z_row, eminus, constraint->strength);
gtk_constraint_solver_note_added_variable (self, eplus, self->objective);
gtk_constraint_solver_note_added_variable (self, eminus, self->objective);
@@ -1061,10 +1059,9 @@ gtk_constraint_solver_dual_optimize (GtkConstraintSolver *self)
gtk_constraint_solver_pivot (self, entry_var, exit_var);
}
#ifdef G_ENABLE_DEBUG
g_debug ("dual_optimize.time := %.3f ms",
(float) (g_get_monotonic_time () - start_time) / 1000.f);
#endif
GTK_NOTE (CONSTRAINTS,
g_message ("dual_optimize.time := %.3f ms",
(float) (g_get_monotonic_time () - start_time) / 1000.f));
}
static void
@@ -1168,7 +1165,7 @@ gtk_constraint_solver_choose_subject (GtkConstraintSolver *self,
GtkConstraintVariableSet *cset = g_hash_table_lookup (self->columns, t_v);
if (cset == NULL ||
(gtk_constraint_variable_set_size (cset) == 1 &&
(gtk_constraint_variable_set_is_singleton (cset) &&
g_hash_table_contains (self->columns, self->objective)))
{
subject = t_v;
@@ -1205,7 +1202,8 @@ gtk_constraint_solver_choose_subject (GtkConstraintSolver *self,
if (!G_APPROX_VALUE (gtk_constraint_expression_get_constant (expression), 0.0, 0.001))
{
g_debug ("Unable to satisfy required constraint (choose_subject)");
GTK_NOTE (CONSTRAINTS,
g_message ("Unable to satisfy required constraint (choose_subject)"));
return NULL;
}
@@ -1266,14 +1264,17 @@ gtk_constraint_solver_add_with_artificial_variable (GtkConstraintSolver *self,
az_tableau_row = g_hash_table_lookup (self->rows, az);
if (!G_APPROX_VALUE (gtk_constraint_expression_get_constant (az_tableau_row), 0.0, 0.001))
{
char *str = gtk_constraint_expression_to_string (expression);
gtk_constraint_solver_remove_column (self, av);
gtk_constraint_solver_remove_row (self, az, TRUE);
g_debug ("Unable to satisfy a required constraint (add): %s", str);
g_free (str);
#ifdef G_ENABLE_DEBUG
if (GTK_DEBUG_CHECK (CONSTRAINTS))
{
char *str = gtk_constraint_expression_to_string (expression);
g_message ("Unable to satisfy a required constraint (add): %s", str);
g_free (str);
}
#endif
return;
}
@@ -1318,15 +1319,14 @@ gtk_constraint_solver_add_constraint_internal (GtkConstraintSolver *self,
&prev_constant);
#ifdef G_ENABLE_DEBUG
{
char *expr_s = gtk_constraint_expression_to_string (expr);
char *ref_s = gtk_constraint_ref_to_string (constraint);
g_debug ("Adding constraint '%s' (normalized expression: '%s')\n", ref_s, expr_s);
g_free (ref_s);
g_free (expr_s);
}
if (GTK_DEBUG_CHECK (CONSTRAINTS))
{
char *expr_s = gtk_constraint_expression_to_string (expr);
char *ref_s = gtk_constraint_ref_to_string (constraint);
g_message ("Adding constraint '%s' (normalized expression: '%s')", ref_s, expr_s);
g_free (ref_s);
g_free (expr_s);
}
#endif
if (constraint->is_stay)
@@ -1485,6 +1485,8 @@ gtk_constraint_solver_create_variable (GtkConstraintSolver *self,
res = gtk_constraint_variable_new (prefix, name);
gtk_constraint_variable_set_value (res, value);
self->var_counter++;
return res;
}
@@ -1510,10 +1512,9 @@ gtk_constraint_solver_resolve (GtkConstraintSolver *solver)
gtk_constraint_solver_reset_stay_constants (solver);
#ifdef G_ENABLE_DEBUG
g_debug ("resolve.time := %.3f ms",
(float) (g_get_monotonic_time () - start_time) / 1000.f);
#endif
GTK_NOTE (CONSTRAINTS,
g_message ("resolve.time := %.3f ms",
(float) (g_get_monotonic_time () - start_time) / 1000.f));
solver->needs_solving = FALSE;
}
@@ -1524,7 +1525,7 @@ gtk_constraint_solver_resolve (GtkConstraintSolver *solver)
* @variable: the subject of the constraint
* @relation: the relation of the constraint
* @expression: the expression of the constraint
* @strength: the weight of the constraint
* @strength: the strength of the constraint
*
* Adds a new constraint in the form of:
*
@@ -1543,12 +1544,12 @@ gtk_constraint_solver_add_constraint (GtkConstraintSolver *self,
GtkConstraintVariable *variable,
GtkConstraintRelation relation,
GtkConstraintExpression *expression,
double strength)
int strength)
{
GtkConstraintRef *res = g_new0 (GtkConstraintRef, 1);
res->solver = self;
res->weight = strength;
res->strength = strength;
res->is_edit = FALSE;
res->is_stay = FALSE;
res->relation = relation;
@@ -1600,7 +1601,7 @@ gtk_constraint_solver_add_constraint (GtkConstraintSolver *self,
* gtk_constraint_solver_add_stay_variable:
* @self: a #GtkConstraintSolver
* @variable: a stay #GtkConstraintVariable
* @strength: the weight of the constraint
* @strength: the strength of the constraint
*
* Adds a constraint on a stay @variable with the given @strength.
*
@@ -1614,14 +1615,14 @@ gtk_constraint_solver_add_constraint (GtkConstraintSolver *self,
GtkConstraintRef *
gtk_constraint_solver_add_stay_variable (GtkConstraintSolver *self,
GtkConstraintVariable *variable,
double strength)
int strength)
{
GtkConstraintRef *res = g_new0 (GtkConstraintRef, 1);
res->solver = self;
res->variable = gtk_constraint_variable_ref (variable);
res->relation = GTK_CONSTRAINT_RELATION_EQ;
res->weight = strength;
res->strength = strength;
res->is_stay = TRUE;
res->is_edit = FALSE;
@@ -1632,11 +1633,12 @@ gtk_constraint_solver_add_stay_variable (GtkConstraintSolver *self,
self);
#ifdef G_ENABLE_DEBUG
{
char *str = gtk_constraint_expression_to_string (res->expression);
g_debug ("Adding stay variable: %s", str);
g_free (str);
}
if (GTK_DEBUG_CHECK (CONSTRAINTS))
{
char *str = gtk_constraint_expression_to_string (res->expression);
g_message ("Adding stay variable: %s", str);
g_free (str);
}
#endif
gtk_constraint_solver_add_constraint_internal (self, res);
@@ -1693,14 +1695,14 @@ gtk_constraint_solver_remove_stay_variable (GtkConstraintSolver *self,
GtkConstraintRef *
gtk_constraint_solver_add_edit_variable (GtkConstraintSolver *self,
GtkConstraintVariable *variable,
double strength)
int strength)
{
GtkConstraintRef *res = g_new0 (GtkConstraintRef, 1);
res->solver = self;
res->variable = gtk_constraint_variable_ref (variable);
res->relation = GTK_CONSTRAINT_RELATION_EQ;
res->weight = strength;
res->strength = strength;
res->is_stay = FALSE;
res->is_edit = TRUE;
@@ -1734,7 +1736,7 @@ gtk_constraint_solver_remove_edit_variable (GtkConstraintSolver *self,
{
char *str = gtk_constraint_variable_to_string (variable);
g_critical ("Unknown stay variable '%s'", str);
g_critical ("Unknown edit variable '%s'", str);
g_free (str);
@@ -1783,7 +1785,7 @@ gtk_constraint_solver_remove_constraint (GtkConstraintSolver *self,
{
gtk_constraint_expression_add_variable (z_row,
v,
constraint->weight,
constraint->strength,
self->objective,
self);
}
@@ -1791,7 +1793,7 @@ gtk_constraint_solver_remove_constraint (GtkConstraintSolver *self,
{
gtk_constraint_expression_add_expression (z_row,
e,
constraint->weight,
constraint->strength,
self->objective,
self);
}
@@ -1865,7 +1867,7 @@ gtk_constraint_solver_remove_constraint (GtkConstraintSolver *self,
if (exit_var == NULL)
{
if (gtk_constraint_variable_set_size (set) == 0)
if (gtk_constraint_variable_set_is_empty (set))
gtk_constraint_solver_remove_column (self, marker);
else
{
@@ -1971,6 +1973,7 @@ gtk_constraint_solver_suggest_value (GtkConstraintSolver *self,
double value)
{
EditInfo *ei = g_hash_table_lookup (self->edit_var_map, variable);
double delta;
if (ei == NULL)
{
g_critical ("Suggesting value '%g' but variable %p is not editable",
@@ -1986,9 +1989,10 @@ gtk_constraint_solver_suggest_value (GtkConstraintSolver *self,
return;
}
ei->prev_constant = value - ei->prev_constant;
delta = value - ei->prev_constant;
ei->prev_constant = value;
gtk_constraint_solver_delta_edit_constant (self, ei->prev_constant, ei->eplus, ei->eminus);
gtk_constraint_solver_delta_edit_constant (self, delta, ei->eplus, ei->eminus);
}
/*< private >
@@ -2205,3 +2209,39 @@ gtk_constraint_solver_to_string (GtkConstraintSolver *solver)
return g_string_free (buf, FALSE);
}
char *
gtk_constraint_solver_statistics (GtkConstraintSolver *solver)
{
GString *buf = g_string_new (NULL);
g_string_append_printf (buf, "Variables: %d\n", solver->var_counter);
g_string_append_printf (buf, "Slack vars: %d\n", solver->slack_counter);
g_string_append_printf (buf, "Artificial vars: %d\n", solver->artificial_counter);
g_string_append_printf (buf, "Dummy vars: %d\n", solver->dummy_counter);
g_string_append_printf (buf, "Stay vars: %d\n", g_hash_table_size (solver->stay_var_map));
g_string_append_printf (buf, "Optimize count: %d\n", solver->optimize_count);
g_string_append_printf (buf, "Rows: %d\n", g_hash_table_size (solver->rows));
g_string_append_printf (buf, "Columns: %d\n", g_hash_table_size (solver->columns));
if (g_hash_table_size (solver->columns) > 0)
{
GHashTableIter iter;
gpointer val;
double sum = 0;
g_hash_table_iter_init (&iter, solver->columns);
while (g_hash_table_iter_next (&iter, NULL, &val))
{
GtkConstraintVariableSet *set = val;
sum += gtk_constraint_variable_set_size (set);
}
g_string_append_printf (buf, "Avg column size: %g\n", sum / g_hash_table_size (solver->columns));
}
g_string_append_printf (buf, "Infeasible rows: %d\n", solver->infeasible_rows->len);
g_string_append_printf (buf, "External basic variables: %d\n", g_hash_table_size (solver->external_rows));
g_string_append_printf (buf, "External parametric variables: %d\n", g_hash_table_size (solver->external_parametric_vars));
return g_string_free (buf, FALSE);
}

View File

@@ -29,37 +29,6 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GtkConstraintSolver, gtk_constraint_solver, GTK, CONSTRAINT_SOLVER, GObject)
/* Symbolic weight thresholds
*
* Constraint weights live on a continuum, but we use thresholds for simplicity's
* sake, so we don't have to necessarily reason in terms of numeric values.
*
* The public API has a similar approach, where the symbolic constants are negative
* values, and positive values are explicit weights. We map those values into
* numeric values that the GtkConstraintSolver can plug into the linear equations
* tableau.
*/
#define GTK_CONSTRAINT_WEIGHT_REQUIRED (make_weight (1000, 1000, 1000, 1))
#define GTK_CONSTRAINT_WEIGHT_STRONG (make_weight ( 1, 0, 0, 1))
#define GTK_CONSTRAINT_WEIGHT_MEDIUM (make_weight ( 0, 1, 0, 1))
#define GTK_CONSTRAINT_WEIGHT_WEAK (make_weight ( 0, 0, 1, 1))
G_GNUC_PURE
static inline double
make_weight (double a,
double b,
double c,
double w)
{
double res = 0;
res += CLAMP (a * w, 0, 1000) * 1000000;
res += CLAMP (b * w, 0, 1000) * 1000;
res += CLAMP (c * w, 0, 1000);
return res;
}
GtkConstraintSolver *
gtk_constraint_solver_new (void);
@@ -83,7 +52,7 @@ gtk_constraint_solver_add_constraint (GtkConstraintSolver *solver,
GtkConstraintVariable *variable,
GtkConstraintRelation relation,
GtkConstraintExpression *expression,
double strength);
int strength);
void
gtk_constraint_solver_remove_constraint (GtkConstraintSolver *solver,
@@ -92,7 +61,7 @@ gtk_constraint_solver_remove_constraint (GtkConstraintSolver *solver,
GtkConstraintRef *
gtk_constraint_solver_add_stay_variable (GtkConstraintSolver *solver,
GtkConstraintVariable *variable,
double strength);
int strength);
void
gtk_constraint_solver_remove_stay_variable (GtkConstraintSolver *solver,
@@ -105,7 +74,7 @@ gtk_constraint_solver_has_stay_variable (GtkConstraintSolver *solver,
GtkConstraintRef *
gtk_constraint_solver_add_edit_variable (GtkConstraintSolver *solver,
GtkConstraintVariable *variable,
double strength);
int strength);
void
gtk_constraint_solver_remove_edit_variable (GtkConstraintSolver *solver,
@@ -142,4 +111,7 @@ gtk_constraint_solver_clear (GtkConstraintSolver *solver);
char *
gtk_constraint_solver_to_string (GtkConstraintSolver *solver);
char *
gtk_constraint_solver_statistics (GtkConstraintSolver *solver);
G_END_DECLS

View File

@@ -22,6 +22,7 @@
#include "config.h"
#include "gtkconstraintvflparserprivate.h"
#include "gtkenums.h"
#include <string.h>
@@ -101,11 +102,11 @@ struct _GtkConstraintVflParser
VflView *views;
};
GQuark
gtk_constraint_vfl_parser_error_quark (void)
{
return g_quark_from_static_string ("gtk-constraint-vfl-parser-error-quark");
}
/* NOTE: These two symbols are defined in gtkconstraintlayout.h, but we
* cannot include that header here
*/
#define GTK_CONSTRAINT_VFL_PARSER_ERROR (gtk_constraint_vfl_parser_error_quark ())
GQuark gtk_constraint_vfl_parser_error_quark (void);
GtkConstraintVflParser *
gtk_constraint_vfl_parser_new (void)

View File

@@ -25,17 +25,6 @@
G_BEGIN_DECLS
#define GTK_CONSTRAINT_VFL_PARSER_ERROR (gtk_constraint_vfl_parser_error_quark ())
typedef enum {
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_SYMBOL,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_ATTRIBUTE,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_VIEW,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_METRIC,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_PRIORITY,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_RELATION
} VflError;
typedef struct _GtkConstraintVflParser GtkConstraintVflParser;
typedef struct {
@@ -49,8 +38,6 @@ typedef struct {
double strength;
} GtkConstraintVfl;
GQuark gtk_constraint_vfl_parser_error_quark (void);
GtkConstraintVflParser *
gtk_constraint_vfl_parser_new (void);

View File

@@ -51,7 +51,8 @@ typedef enum {
GTK_DEBUG_ACTIONS = 1 << 13,
GTK_DEBUG_RESIZE = 1 << 14,
GTK_DEBUG_LAYOUT = 1 << 15,
GTK_DEBUG_SNAPSHOT = 1 << 16
GTK_DEBUG_SNAPSHOT = 1 << 16,
GTK_DEBUG_CONSTRAINTS = 1 << 17,
} GtkDebugFlag;
#ifdef G_ENABLE_DEBUG

View File

@@ -1080,10 +1080,10 @@ typedef enum {
* integer; the values of this enumeration can be used for readability.
*/
typedef enum {
GTK_CONSTRAINT_STRENGTH_REQUIRED = 0,
GTK_CONSTRAINT_STRENGTH_STRONG = -1,
GTK_CONSTRAINT_STRENGTH_MEDIUM = -2,
GTK_CONSTRAINT_STRENGTH_WEAK = -3
GTK_CONSTRAINT_STRENGTH_REQUIRED = 1001001000,
GTK_CONSTRAINT_STRENGTH_STRONG = 1000000000,
GTK_CONSTRAINT_STRENGTH_MEDIUM = 1000,
GTK_CONSTRAINT_STRENGTH_WEAK = 1
} GtkConstraintStrength;
/**
@@ -1127,4 +1127,24 @@ typedef enum {
GTK_CONSTRAINT_ATTRIBUTE_BASELINE
} GtkConstraintAttribute;
/**
* GtkConstraintVflParserError:
* @GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_SYMBOL: Invalid or unknown symbol
* @GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_ATTRIBUTE: Invalid or unknown attribute
* @GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_VIEW: Invalid or unknown view
* @GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_METRIC: Invalid or unknown metric
* @GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_PRIORITY: Invalid or unknown priority
* @GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_RELATION: Invalid or unknown relation
*
* Domain for VFL parsing errors.
*/
typedef enum {
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_SYMBOL,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_ATTRIBUTE,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_VIEW,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_METRIC,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_PRIORITY,
GTK_CONSTRAINT_VFL_PARSER_ERROR_INVALID_RELATION
} GtkConstraintVflParserError;
#endif /* __GTK_ENUMS_H__ */

View File

@@ -216,17 +216,25 @@ gtk_flatten_list_model_items_changed_cb (GListModel *model,
guint added,
gpointer _node)
{
FlattenNode *node = _node, *parent;
FlattenNode *node = _node, *parent, *left;
GtkFlattenListModel *self = node->list;
guint real_position;
gtk_rb_tree_node_mark_dirty (node);
real_position = position;
for (real_position = position;
left = gtk_rb_tree_node_get_left (node);
if (left)
{
FlattenAugment *aug = gtk_rb_tree_get_augment (self->items, left);
real_position += aug->n_items;
}
for (;
(parent = gtk_rb_tree_node_get_parent (node)) != NULL;
node = parent)
{
FlattenNode *left = gtk_rb_tree_node_get_left (parent);
left = gtk_rb_tree_node_get_left (parent);
if (left != node)
{
if (left)

View File

@@ -212,6 +212,8 @@ gtk_grid_layout_child_class_init (GtkGridLayoutChildClass *klass)
static void
gtk_grid_layout_child_init (GtkGridLayoutChild *self)
{
CHILD_ROW_SPAN (self) = 1;
CHILD_COL_SPAN (self) = 1;
}
/**

View File

@@ -179,7 +179,8 @@ static const GDebugKey gtk_debug_keys[] = {
{ "actions", GTK_DEBUG_ACTIONS },
{ "resize", GTK_DEBUG_RESIZE },
{ "layout", GTK_DEBUG_LAYOUT },
{ "snapshot", GTK_DEBUG_SNAPSHOT }
{ "snapshot", GTK_DEBUG_SNAPSHOT },
{ "constraints", GTK_DEBUG_CONSTRAINTS },
};
#endif /* G_ENABLE_DEBUG */

View File

@@ -203,6 +203,7 @@ gtk_public_sources = files([
'gtkcombobox.c',
'gtkcomboboxtext.c',
'gtkcomposetable.c',
'gtkconstraintguide.c',
'gtkconstraintlayout.c',
'gtkconstraint.c',
'gtkcontainer.c',
@@ -464,6 +465,7 @@ gtk_public_headers = files([
'gtkcolorutils.h',
'gtkcombobox.h',
'gtkcomboboxtext.h',
'gtkconstraintguide.h',
'gtkconstraintlayout.h',
'gtkconstraint.h',
'gtkcontainer.h',

View File

@@ -2178,11 +2178,11 @@ popover>contents {
margin: 0px;
}
popover>contents.background {
popover.background>contents {
background-color: $popover_bg_color;
box-shadow: 0 1px 2px transparentize(black, 0.7);
.csd &, & {
.csd &, & {
border: 1px solid $borders_color;
border-radius: $popover_radius;
}
@@ -4766,8 +4766,9 @@ popover.menu {
padding-bottom: 5px;
}
arrow,
&.background contents {
background: white;
background-color: $menu_color;
}
&.background separator {

View File

@@ -82,9 +82,9 @@ assistant .sidebar label { padding: 6px 12px; }
assistant .sidebar label.highlight { background-color: #5a5a59; }
.csd popover > contents.background.touch-selection, .csd popover > contents.background.magnifier, popover > contents.background.touch-selection, popover > contents.background.magnifier, .csd popover > contents.background.osd, popover > contents.background.osd, .app-notification, .app-notification.frame, .osd .scale-popup, .osd { color: #eeeeec; border: none; background-color: rgba(38, 38, 38, 0.7); background-clip: padding-box; text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; }
.csd popover.background > contents.touch-selection, .csd popover.background > contents.magnifier, popover.background > contents.touch-selection, popover.background > contents.magnifier, .csd popover.background > contents.osd, popover.background > contents.osd, .app-notification, .app-notification.frame, .osd .scale-popup, .osd { color: #eeeeec; border: none; background-color: rgba(37, 37, 38, 0.7); background-clip: padding-box; text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; }
.csd popover > contents.background.touch-selection:backdrop, .csd popover > contents.background.magnifier:backdrop, popover > contents.background.touch-selection:backdrop, popover > contents.background.magnifier:backdrop, .csd popover > contents.background.osd:backdrop, popover > contents.background.osd:backdrop, .app-notification:backdrop, .osd .scale-popup:backdrop, .osd:backdrop { text-shadow: none; -gtk-icon-shadow: none; }
.csd popover.background > contents.touch-selection:backdrop, .csd popover.background > contents.magnifier:backdrop, popover.background > contents.touch-selection:backdrop, popover.background > contents.magnifier:backdrop, .csd popover.background > contents.osd:backdrop, popover.background > contents.osd:backdrop, .app-notification:backdrop, .osd .scale-popup:backdrop, .osd:backdrop { text-shadow: none; -gtk-icon-shadow: none; }
/********************* Spinner Animation * */
@keyframes spin { to { -gtk-icon-transform: rotate(1turn); } }
@@ -265,7 +265,7 @@ row:selected button.sidebar-button:not(:active):not(:checked):not(:hover):not(di
row:selected button.sidebar-button:not(:active):not(:checked):not(:hover):not(disabled):backdrop, row:selected button.flat:not(:active):not(:checked):not(:hover):not(disabled):backdrop { color: #919190; }
button.osd { min-width: 26px; min-height: 32px; color: #eeeeec; border-radius: 5px; color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); border: none; box-shadow: none; }
button.osd { min-width: 26px; min-height: 32px; color: #eeeeec; border-radius: 5px; color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(37, 37, 38, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); border: none; box-shadow: none; }
button.osd.image-button { min-width: 34px; }
@@ -275,27 +275,27 @@ button.osd:active, button.osd:checked { color: white; border-color: rgba(0, 0, 0
button.osd:disabled:backdrop, button.osd:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; border: none; }
button.osd:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; border: none; }
button.osd:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(37, 37, 38, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; border: none; }
.csd popover > contents.background.touch-selection button, .csd popover > contents.background.magnifier button, popover > contents.background.touch-selection button, popover > contents.background.magnifier button, .app-notification button, .app-notification.frame button, .osd button { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover.background > contents.touch-selection button, .csd popover.background > contents.magnifier button, popover.background > contents.touch-selection button, popover.background > contents.magnifier button, .app-notification button, .app-notification.frame button, .osd button { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(37, 37, 38, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover > contents.background.touch-selection button:hover, .csd popover > contents.background.magnifier button:hover, popover > contents.background.touch-selection button:hover, popover > contents.background.magnifier button:hover, .app-notification button:hover, .osd button:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(68, 68, 68, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover.background > contents.touch-selection button:hover, .csd popover.background > contents.magnifier button:hover, popover.background > contents.touch-selection button:hover, popover.background > contents.magnifier button:hover, .app-notification button:hover, .osd button:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(68, 68, 68, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover > contents.background.touch-selection button:active:backdrop, .csd popover > contents.background.magnifier button:active:backdrop, popover > contents.background.touch-selection button:active:backdrop, popover > contents.background.magnifier button:active:backdrop, .app-notification button:active:backdrop, .csd popover > contents.background.touch-selection button:active, .csd popover > contents.background.magnifier button:active, popover > contents.background.touch-selection button:active, popover > contents.background.magnifier button:active, .app-notification button:active, .csd popover > contents.background.touch-selection button:checked:backdrop, .csd popover > contents.background.magnifier button:checked:backdrop, popover > contents.background.touch-selection button:checked:backdrop, popover > contents.background.magnifier button:checked:backdrop, .app-notification button:checked:backdrop, .csd popover > contents.background.touch-selection button:checked, .csd popover > contents.background.magnifier button:checked, popover > contents.background.touch-selection button:checked, popover > contents.background.magnifier button:checked, .app-notification button:checked, .osd button:active:backdrop, .osd button:active, .osd button:checked:backdrop, .osd button:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover.background > contents.touch-selection button:active:backdrop, .csd popover.background > contents.magnifier button:active:backdrop, popover.background > contents.touch-selection button:active:backdrop, popover.background > contents.magnifier button:active:backdrop, .app-notification button:active:backdrop, .csd popover.background > contents.touch-selection button:active, .csd popover.background > contents.magnifier button:active, popover.background > contents.touch-selection button:active, popover.background > contents.magnifier button:active, .app-notification button:active, .csd popover.background > contents.touch-selection button:checked:backdrop, .csd popover.background > contents.magnifier button:checked:backdrop, popover.background > contents.touch-selection button:checked:backdrop, popover.background > contents.magnifier button:checked:backdrop, .app-notification button:checked:backdrop, .csd popover.background > contents.touch-selection button:checked, .csd popover.background > contents.magnifier button:checked, popover.background > contents.touch-selection button:checked, popover.background > contents.magnifier button:checked, .app-notification button:checked, .osd button:active:backdrop, .osd button:active, .osd button:checked:backdrop, .osd button:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover > contents.background.touch-selection button:disabled:backdrop, .csd popover > contents.background.magnifier button:disabled:backdrop, popover > contents.background.touch-selection button:disabled:backdrop, popover > contents.background.magnifier button:disabled:backdrop, .app-notification button:disabled:backdrop, .csd popover > contents.background.touch-selection button:disabled, .csd popover > contents.background.magnifier button:disabled, popover > contents.background.touch-selection button:disabled, popover > contents.background.magnifier button:disabled, .app-notification button:disabled, .osd button:disabled:backdrop, .osd button:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
.csd popover.background > contents.touch-selection button:disabled:backdrop, .csd popover.background > contents.magnifier button:disabled:backdrop, popover.background > contents.touch-selection button:disabled:backdrop, popover.background > contents.magnifier button:disabled:backdrop, .app-notification button:disabled:backdrop, .csd popover.background > contents.touch-selection button:disabled, .csd popover.background > contents.magnifier button:disabled, popover.background > contents.touch-selection button:disabled, popover.background > contents.magnifier button:disabled, .app-notification button:disabled, .osd button:disabled:backdrop, .osd button:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
.csd popover > contents.background.touch-selection button:backdrop, .csd popover > contents.background.magnifier button:backdrop, popover > contents.background.touch-selection button:backdrop, popover > contents.background.magnifier button:backdrop, .app-notification button:backdrop, .osd button:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
.csd popover.background > contents.touch-selection button:backdrop, .csd popover.background > contents.magnifier button:backdrop, popover.background > contents.touch-selection button:backdrop, popover.background > contents.magnifier button:backdrop, .app-notification button:backdrop, .osd button:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(37, 37, 38, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
.csd popover > contents.background.touch-selection button.flat, .csd popover > contents.background.magnifier button.flat, popover > contents.background.touch-selection button.flat, popover > contents.background.magnifier button.flat, .app-notification button.flat, .osd button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: inset 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; box-shadow: none; text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; }
.csd popover.background > contents.touch-selection button.flat, .csd popover.background > contents.magnifier button.flat, popover.background > contents.touch-selection button.flat, popover.background > contents.magnifier button.flat, .app-notification button.flat, .osd button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: inset 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; box-shadow: none; text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; }
.csd popover > contents.background.touch-selection button.flat:hover, .csd popover > contents.background.magnifier button.flat:hover, popover > contents.background.touch-selection button.flat:hover, popover > contents.background.magnifier button.flat:hover, .app-notification button.flat:hover, .osd button.flat:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(68, 68, 68, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover.background > contents.touch-selection button.flat:hover, .csd popover.background > contents.magnifier button.flat:hover, popover.background > contents.touch-selection button.flat:hover, popover.background > contents.magnifier button.flat:hover, .app-notification button.flat:hover, .osd button.flat:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(68, 68, 68, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover > contents.background.touch-selection button.flat:disabled, .csd popover > contents.background.magnifier button.flat:disabled, popover > contents.background.touch-selection button.flat:disabled, popover > contents.background.magnifier button.flat:disabled, .app-notification button.flat:disabled, .osd button.flat:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; background-image: none; border-color: transparent; box-shadow: none; }
.csd popover.background > contents.touch-selection button.flat:disabled, .csd popover.background > contents.magnifier button.flat:disabled, popover.background > contents.touch-selection button.flat:disabled, popover.background > contents.magnifier button.flat:disabled, .app-notification button.flat:disabled, .osd button.flat:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; background-image: none; border-color: transparent; box-shadow: none; }
.csd popover > contents.background.touch-selection button.flat:backdrop, .csd popover > contents.background.magnifier button.flat:backdrop, popover > contents.background.touch-selection button.flat:backdrop, popover > contents.background.magnifier button.flat:backdrop, .app-notification button.flat:backdrop, .osd button.flat:backdrop { border-color: transparent; background-color: transparent; background-image: none; box-shadow: inset 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; }
.csd popover.background > contents.touch-selection button.flat:backdrop, .csd popover.background > contents.magnifier button.flat:backdrop, popover.background > contents.touch-selection button.flat:backdrop, popover.background > contents.magnifier button.flat:backdrop, .app-notification button.flat:backdrop, .osd button.flat:backdrop { border-color: transparent; background-color: transparent; background-image: none; box-shadow: inset 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; }
.csd popover > contents.background.touch-selection button.flat:active, .csd popover > contents.background.magnifier button.flat:active, popover > contents.background.touch-selection button.flat:active, popover > contents.background.magnifier button.flat:active, .app-notification button.flat:active, .csd popover > contents.background.touch-selection button.flat:checked, .csd popover > contents.background.magnifier button.flat:checked, popover > contents.background.touch-selection button.flat:checked, popover > contents.background.magnifier button.flat:checked, .app-notification button.flat:checked, .osd button.flat:active, .osd button.flat:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover.background > contents.touch-selection button.flat:active, .csd popover.background > contents.magnifier button.flat:active, popover.background > contents.touch-selection button.flat:active, popover.background > contents.magnifier button.flat:active, .app-notification button.flat:active, .csd popover.background > contents.touch-selection button.flat:checked, .csd popover.background > contents.magnifier button.flat:checked, popover.background > contents.touch-selection button.flat:checked, popover.background > contents.magnifier button.flat:checked, .app-notification button.flat:checked, .osd button.flat:active, .osd button.flat:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; outline-color: rgba(238, 238, 236, 0.3); }
button.suggested-action { color: white; outline-color: rgba(255, 255, 255, 0.3); border-color: #0f3b71; border-bottom-color: #092444; background-image: linear-gradient(to top, #155099 2px, #15539e); text-shadow: 0 -1px rgba(0, 0, 0, 0.719216); -gtk-icon-shadow: 0 -1px rgba(0, 0, 0, 0.719216); box-shadow: inset 0 1px rgba(255, 255, 255, 0.02), 0 1px 2px rgba(0, 0, 0, 0.07); }
@@ -497,7 +497,7 @@ button:link > label:active, button:visited > label:active, *:link:active, button
*:selected button:link > label:active, *:selected button:visited > label:active, *:selected *:link:active, *:selected button:active:link, *:selected button:active:visited { color: #d0ddec; }
button:link > label:disabled, button:visited > label:disabled, button:link > label:disabled:backdrop, button:visited > label:disabled:backdrop, *:link:disabled, button:disabled:link, button:disabled:visited, *:link:disabled:backdrop, button:disabled:backdrop:link, button:disabled:backdrop:visited { color: rgba(141, 141, 141, 0.8); }
button:link > label:disabled, button:visited > label:disabled, button:link > label:disabled:backdrop, button:visited > label:disabled:backdrop, *:link:disabled, button:disabled:link, button:disabled:visited, *:link:disabled:backdrop, button:disabled:backdrop:link, button:disabled:backdrop:visited { color: rgba(140, 140, 141, 0.8); }
button:link > label:backdrop:backdrop:hover, button:visited > label:backdrop:backdrop:hover, button:link > label:backdrop:backdrop:hover:selected, button:visited > label:backdrop:backdrop:hover:selected, button:link > label:backdrop, button:visited > label:backdrop, *:link:backdrop:backdrop:hover, button:backdrop:backdrop:hover:link, button:backdrop:backdrop:hover:visited, *:link:backdrop:backdrop:hover:selected, button:backdrop:backdrop:hover:selected:link, button:backdrop:backdrop:hover:selected:visited, .selection-mode .titlebar:not(headerbar) .subtitle:backdrop:backdrop:hover:link, .selection-mode.titlebar:not(headerbar) .subtitle:backdrop:backdrop:hover:link, .selection-mode headerbar .subtitle:backdrop:backdrop:hover:link, headerbar.selection-mode .subtitle:backdrop:backdrop:hover:link, *:link:backdrop, button:backdrop:link, button:backdrop:visited { color: #15539e; }
@@ -564,7 +564,7 @@ spinbutton.vertical button.up { border-bottom-style: none; border-bottom-left-ra
spinbutton.vertical button.down { border-top-style: none; border-top-left-radius: 0; border-top-right-radius: 0; }
.osd spinbutton.vertical button:first-child { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.osd spinbutton.vertical button:first-child { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(37, 37, 38, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.osd spinbutton.vertical button:first-child:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(68, 68, 68, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
@@ -572,7 +572,7 @@ spinbutton.vertical button.down { border-top-style: none; border-top-left-radius
.osd spinbutton.vertical button:first-child:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
.osd spinbutton.vertical button:first-child:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
.osd spinbutton.vertical button:first-child:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(37, 37, 38, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
treeview spinbutton:not(.vertical) { min-height: 0; border-style: none; border-radius: 0; }
@@ -590,7 +590,7 @@ toolbar { padding: 4px 3px 3px 4px; }
.osd toolbar { background-color: transparent; }
toolbar.osd { padding: 13px; border: none; border-radius: 5px; background-color: rgba(38, 38, 38, 0.7); }
toolbar.osd { padding: 13px; border: none; border-radius: 5px; background-color: rgba(37, 37, 38, 0.7); }
toolbar.osd.left, toolbar.osd.right, toolbar.osd.top, toolbar.osd.bottom { border-radius: 0; }
@@ -613,7 +613,7 @@ searchbar > revealer > box { padding: 6px; border-width: 0 0 1px; }
.inline-toolbar:backdrop, .location-bar:backdrop, searchbar > revealer > box:backdrop { border-color: #202020; background-color: #2e2e2e; box-shadow: none; transition: 200ms ease-out; }
/*************** Header bars * */
.titlebar:not(headerbar), headerbar { padding: 0 6px; min-height: 46px; border-width: 0 0 1px; border-style: solid; border-color: #070707; border-radius: 0; background: #1b1b1b linear-gradient(to top, #262626, #2b2b2b); box-shadow: inset 0 1px rgba(238, 238, 236, 0.07); /* Darken switchbuttons for headerbars. issue #1588 */ /* hide the close button separator */ }
.titlebar:not(headerbar), headerbar { padding: 0 6px; min-height: 46px; border-width: 0 0 1px; border-style: solid; border-color: #070707; border-radius: 0; background: #1b1b1b linear-gradient(to top, #252526, #2b2b2b); box-shadow: inset 0 1px rgba(238, 238, 236, 0.07); /* Darken switchbuttons for headerbars. issue #1588 */ /* hide the close button separator */ }
.titlebar:backdrop:not(headerbar), headerbar:backdrop { border-color: #202020; background-color: #353535; background-image: none; box-shadow: inset 0 1px rgba(238, 238, 236, 0.07); transition: 200ms ease-out; }
@@ -879,19 +879,19 @@ popover.menu > arrow, popover > arrow { background-color: #353535; border: 1px s
popover > contents { padding: 8px; background-color: #353535; border: 1px solid #1b1b1b; margin: 0px; }
popover > contents.background { background-color: #353535; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); }
popover.background > contents { background-color: #353535; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); }
.csd popover > contents.background, popover > contents.background { border: 1px solid #1b1b1b; border-radius: 9px; }
.csd popover.background > contents, popover.background > contents { border: 1px solid #1b1b1b; border-radius: 9px; }
popover > contents.background:backdrop { background-color: #353535; box-shadow: none; }
popover.background > contents:backdrop { background-color: #353535; box-shadow: none; }
popover > contents.background > list, popover > contents.background > .view, popover > contents.background > iconview, popover > contents.background > toolbar { border-style: none; background-color: transparent; }
popover.background > contents > list, popover.background > contents > .view, popover.background > contents > iconview, popover.background > contents > toolbar { border-style: none; background-color: transparent; }
.csd popover > contents.background.touch-selection, .csd popover > contents.background.magnifier, popover > contents.background.touch-selection, popover > contents.background.magnifier { border: 1px solid rgba(255, 255, 255, 0.1); }
.csd popover.background > contents.touch-selection, .csd popover.background > contents.magnifier, popover.background > contents.touch-selection, popover.background > contents.magnifier { border: 1px solid rgba(255, 255, 255, 0.1); }
popover > contents.background separator { margin: 3px; }
popover.background > contents separator { margin: 3px; }
popover > contents.background list separator { margin: 0px; }
popover.background > contents list separator { margin: 0px; }
/************* Notebooks * */
notebook box > header { padding: 1px; border-color: #1b1b1b; border-width: 1px; background-color: #282828; }
@@ -1141,7 +1141,7 @@ switch:backdrop:disabled slider label, switch:backdrop:disabled slider { color:
.view.content-view.check:active:not(list), iconview.content-view.check:active:not(list), .content-view .tile check:active:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: rgba(21, 83, 158, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; }
.view.content-view.check:backdrop:not(list), iconview.content-view.check:backdrop:not(list), .content-view .tile check:backdrop:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: rgba(90, 90, 90, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; }
.view.content-view.check:backdrop:not(list), iconview.content-view.check:backdrop:not(list), .content-view .tile check:backdrop:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: rgba(89, 89, 90, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; }
.view.content-view.check:checked:not(list), iconview.content-view.check:checked:not(list), .content-view .tile check:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: rgba(21, 83, 158, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; }
@@ -1149,7 +1149,7 @@ switch:backdrop:disabled slider label, switch:backdrop:disabled slider { color:
.view.content-view.check:checked:active:not(list), iconview.content-view.check:checked:active:not(list), .content-view .tile check:checked:active:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: rgba(21, 83, 158, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; }
.view.content-view.check:backdrop:checked:not(list), iconview.content-view.check:backdrop:checked:not(list), .content-view .tile check:backdrop:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: rgba(238, 238, 236, 0.8); background-color: rgba(90, 90, 90, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; }
.view.content-view.check:backdrop:checked:not(list), iconview.content-view.check:backdrop:checked:not(list), .content-view .tile check:backdrop:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: rgba(238, 238, 236, 0.8); background-color: rgba(89, 89, 90, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; }
checkbutton.text-button, radiobutton.text-button { padding: 2px 0; outline-offset: 0; }
@@ -1157,7 +1157,7 @@ checkbutton.text-button label:not(:only-child):first-child, radiobutton.text-but
checkbutton.text-button label:not(:only-child):last-child, radiobutton.text-button label:not(:only-child):last-child { margin-right: 4px; }
check, radio { margin: 0 4px; min-height: 14px; min-width: 14px; border: 1px solid; -gtk-icon-source: none; color: #eeeeec; outline-color: rgba(238, 238, 236, 0.3); border-color: #070707; text-shadow: 0 -1px rgba(0, 0, 0, 0.834353); -gtk-icon-shadow: 0 -1px rgba(0, 0, 0, 0.834353); background-image: linear-gradient(to bottom, #2d2d2d 20%, #262626 90%); box-shadow: inset 0 1px rgba(255, 255, 255, 0.02), 0 1px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.07); }
check, radio { margin: 0 4px; min-height: 14px; min-width: 14px; border: 1px solid; -gtk-icon-source: none; color: #eeeeec; outline-color: rgba(238, 238, 236, 0.3); border-color: #070707; text-shadow: 0 -1px rgba(0, 0, 0, 0.834353); -gtk-icon-shadow: 0 -1px rgba(0, 0, 0, 0.834353); background-image: linear-gradient(to bottom, #2d2d2d 20%, #252526 90%); box-shadow: inset 0 1px rgba(255, 255, 255, 0.02), 0 1px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.07); }
check:only-child, radio:only-child { margin: 0; }
@@ -1181,13 +1181,13 @@ check:backdrop:disabled, radio:backdrop:disabled { border-color: #202020; backgr
check:backdrop:disabled label, check:backdrop:disabled, radio:backdrop:disabled label, radio:backdrop:disabled { color: #5b5b5b; }
.osd check, .osd radio { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.osd check, .osd radio { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(37, 37, 38, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.osd check:hover, .osd radio:hover { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.osd check:hover, .osd radio:hover { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(37, 37, 38, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.osd check:active, .osd radio:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; outline-color: rgba(238, 238, 236, 0.3); }
.osd check:backdrop, .osd radio:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
.osd check:backdrop, .osd radio:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(37, 37, 38, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
.osd check:disabled, .osd radio:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
@@ -1280,7 +1280,7 @@ scale fill:disabled:backdrop, scale fill:disabled { border-color: transparent; b
.osd scale fill:disabled:backdrop, .osd scale fill:disabled { border-color: transparent; background-color: transparent; }
scale slider { color: #eeeeec; outline-color: rgba(238, 238, 236, 0.3); border-color: #070707; text-shadow: 0 -1px rgba(0, 0, 0, 0.834353); -gtk-icon-shadow: 0 -1px rgba(0, 0, 0, 0.834353); background-image: linear-gradient(to bottom, #2d2d2d 20%, #262626 90%); box-shadow: inset 0 1px rgba(255, 255, 255, 0.02), 0 1px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.07); border: 1px solid black; border-radius: 100%; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: background, border, box-shadow; }
scale slider { color: #eeeeec; outline-color: rgba(238, 238, 236, 0.3); border-color: #070707; text-shadow: 0 -1px rgba(0, 0, 0, 0.834353); -gtk-icon-shadow: 0 -1px rgba(0, 0, 0, 0.834353); background-image: linear-gradient(to bottom, #2d2d2d 20%, #252526 90%); box-shadow: inset 0 1px rgba(255, 255, 255, 0.02), 0 1px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.07); border: 1px solid black; border-radius: 100%; transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94); transition-property: background, border, box-shadow; }
scale slider:hover { color: #eeeeec; outline-color: rgba(238, 238, 236, 0.3); border-color: #070707; box-shadow: inset 0 1px rgba(255, 255, 255, 0.02), 0 1px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.07); background-image: linear-gradient(to bottom, #353535 20%, #2b2b2b 90%); }
@@ -1300,17 +1300,17 @@ scale slider:backdrop:disabled label, scale slider:backdrop:disabled { color: #5
row:selected scale slider:disabled, row:selected scale slider { border-color: #030c17; }
.osd scale slider { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); border-color: rgba(0, 0, 0, 0.7); background-color: #262626; }
.osd scale slider { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(37, 37, 38, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); border-color: rgba(0, 0, 0, 0.7); background-color: #252526; }
.osd scale slider:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(68, 68, 68, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); background-color: #262626; }
.osd scale slider:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(68, 68, 68, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); background-color: #252526; }
.osd scale slider:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; outline-color: rgba(238, 238, 236, 0.3); background-color: #262626; }
.osd scale slider:active { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; outline-color: rgba(238, 238, 236, 0.3); background-color: #252526; }
.osd scale slider:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; background-color: #262626; }
.osd scale slider:disabled { color: #8a8a89; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(58, 58, 57, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; background-color: #252526; }
.osd scale slider:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(38, 38, 38, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; background-color: #262626; }
.osd scale slider:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(37, 37, 38, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; background-color: #252526; }
.osd scale slider:backdrop:disabled { background-color: #262626; }
.osd scale slider:backdrop:disabled { background-color: #252526; }
scale value { color: alpha(currentColor,0.55); }
@@ -1636,7 +1636,7 @@ row.activatable:selected.has-open-popup, row.activatable:selected:hover { backgr
row.activatable:selected:backdrop { background-color: #15539e; }
/********************* App Notifications * */
.app-notification, .app-notification.frame { padding: 10px; border-radius: 0 0 5px 5px; background-color: rgba(38, 38, 38, 0.7); background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.2), transparent 2px); background-clip: padding-box; }
.app-notification, .app-notification.frame { padding: 10px; border-radius: 0 0 5px 5px; background-color: rgba(37, 37, 38, 0.7); background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.2), transparent 2px); background-clip: padding-box; }
.app-notification:backdrop, .app-notification.frame:backdrop { background-image: none; transition: 200ms ease-out; }
@@ -2063,7 +2063,7 @@ popover.menu box.inline-buttons { border-radius: 5px; border-style: none; border
popover.menu box.circular-buttons { padding-bottom: 5px; }
popover.menu.background contents { background: white; }
popover.menu arrow, popover.menu.background contents { background-color: #2f2f2f; }
popover.menu.background separator { margin: 5px 0px; }

View File

@@ -82,9 +82,9 @@ assistant .sidebar label { padding: 6px 12px; }
assistant .sidebar label.highlight { background-color: #cecece; }
.csd popover > contents.background.touch-selection, .csd popover > contents.background.magnifier, popover > contents.background.touch-selection, popover > contents.background.magnifier, .csd popover > contents.background.osd, popover > contents.background.osd, .app-notification, .app-notification.frame, .osd .scale-popup, .osd { color: #eeeeec; border: none; background-color: rgba(53, 53, 53, 0.7); background-clip: padding-box; text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; }
.csd popover.background > contents.touch-selection, .csd popover.background > contents.magnifier, popover.background > contents.touch-selection, popover.background > contents.magnifier, .csd popover.background > contents.osd, popover.background > contents.osd, .app-notification, .app-notification.frame, .osd .scale-popup, .osd { color: #eeeeec; border: none; background-color: rgba(53, 53, 53, 0.7); background-clip: padding-box; text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; }
.csd popover > contents.background.touch-selection:backdrop, .csd popover > contents.background.magnifier:backdrop, popover > contents.background.touch-selection:backdrop, popover > contents.background.magnifier:backdrop, .csd popover > contents.background.osd:backdrop, popover > contents.background.osd:backdrop, .app-notification:backdrop, .osd .scale-popup:backdrop, .osd:backdrop { text-shadow: none; -gtk-icon-shadow: none; }
.csd popover.background > contents.touch-selection:backdrop, .csd popover.background > contents.magnifier:backdrop, popover.background > contents.touch-selection:backdrop, popover.background > contents.magnifier:backdrop, .csd popover.background > contents.osd:backdrop, popover.background > contents.osd:backdrop, .app-notification:backdrop, .osd .scale-popup:backdrop, .osd:backdrop { text-shadow: none; -gtk-icon-shadow: none; }
/********************* Spinner Animation * */
@keyframes spin { to { -gtk-icon-transform: rotate(1turn); } }
@@ -279,25 +279,25 @@ button.osd:disabled:backdrop, button.osd:disabled { color: #919190; border-color
button.osd:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; border: none; }
.csd popover > contents.background.touch-selection button, .csd popover > contents.background.magnifier button, popover > contents.background.touch-selection button, popover > contents.background.magnifier button, .app-notification button, .app-notification.frame button, .osd button { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover.background > contents.touch-selection button, .csd popover.background > contents.magnifier button, popover.background > contents.touch-selection button, popover.background > contents.magnifier button, .app-notification button, .app-notification.frame button, .osd button { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover > contents.background.touch-selection button:hover, .csd popover > contents.background.magnifier button:hover, popover > contents.background.touch-selection button:hover, popover > contents.background.magnifier button:hover, .app-notification button:hover, .osd button:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(83, 83, 83, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover.background > contents.touch-selection button:hover, .csd popover.background > contents.magnifier button:hover, popover.background > contents.touch-selection button:hover, popover.background > contents.magnifier button:hover, .app-notification button:hover, .osd button:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(83, 83, 83, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover > contents.background.touch-selection button:active:backdrop, .csd popover > contents.background.magnifier button:active:backdrop, popover > contents.background.touch-selection button:active:backdrop, popover > contents.background.magnifier button:active:backdrop, .app-notification button:active:backdrop, .csd popover > contents.background.touch-selection button:active, .csd popover > contents.background.magnifier button:active, popover > contents.background.touch-selection button:active, popover > contents.background.magnifier button:active, .app-notification button:active, .csd popover > contents.background.touch-selection button:checked:backdrop, .csd popover > contents.background.magnifier button:checked:backdrop, popover > contents.background.touch-selection button:checked:backdrop, popover > contents.background.magnifier button:checked:backdrop, .app-notification button:checked:backdrop, .csd popover > contents.background.touch-selection button:checked, .csd popover > contents.background.magnifier button:checked, popover > contents.background.touch-selection button:checked, popover > contents.background.magnifier button:checked, .app-notification button:checked, .osd button:active:backdrop, .osd button:active, .osd button:checked:backdrop, .osd button:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover.background > contents.touch-selection button:active:backdrop, .csd popover.background > contents.magnifier button:active:backdrop, popover.background > contents.touch-selection button:active:backdrop, popover.background > contents.magnifier button:active:backdrop, .app-notification button:active:backdrop, .csd popover.background > contents.touch-selection button:active, .csd popover.background > contents.magnifier button:active, popover.background > contents.touch-selection button:active, popover.background > contents.magnifier button:active, .app-notification button:active, .csd popover.background > contents.touch-selection button:checked:backdrop, .csd popover.background > contents.magnifier button:checked:backdrop, popover.background > contents.touch-selection button:checked:backdrop, popover.background > contents.magnifier button:checked:backdrop, .app-notification button:checked:backdrop, .csd popover.background > contents.touch-selection button:checked, .csd popover.background > contents.magnifier button:checked, popover.background > contents.touch-selection button:checked, popover.background > contents.magnifier button:checked, .app-notification button:checked, .osd button:active:backdrop, .osd button:active, .osd button:checked:backdrop, .osd button:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover > contents.background.touch-selection button:disabled:backdrop, .csd popover > contents.background.magnifier button:disabled:backdrop, popover > contents.background.touch-selection button:disabled:backdrop, popover > contents.background.magnifier button:disabled:backdrop, .app-notification button:disabled:backdrop, .csd popover > contents.background.touch-selection button:disabled, .csd popover > contents.background.magnifier button:disabled, popover > contents.background.touch-selection button:disabled, popover > contents.background.magnifier button:disabled, .app-notification button:disabled, .osd button:disabled:backdrop, .osd button:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
.csd popover.background > contents.touch-selection button:disabled:backdrop, .csd popover.background > contents.magnifier button:disabled:backdrop, popover.background > contents.touch-selection button:disabled:backdrop, popover.background > contents.magnifier button:disabled:backdrop, .app-notification button:disabled:backdrop, .csd popover.background > contents.touch-selection button:disabled, .csd popover.background > contents.magnifier button:disabled, popover.background > contents.touch-selection button:disabled, popover.background > contents.magnifier button:disabled, .app-notification button:disabled, .osd button:disabled:backdrop, .osd button:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
.csd popover > contents.background.touch-selection button:backdrop, .csd popover > contents.background.magnifier button:backdrop, popover > contents.background.touch-selection button:backdrop, popover > contents.background.magnifier button:backdrop, .app-notification button:backdrop, .osd button:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
.csd popover.background > contents.touch-selection button:backdrop, .csd popover.background > contents.magnifier button:backdrop, popover.background > contents.touch-selection button:backdrop, popover.background > contents.magnifier button:backdrop, .app-notification button:backdrop, .osd button:backdrop { color: #eeeeec; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(53, 53, 53, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; }
.csd popover > contents.background.touch-selection button.flat, .csd popover > contents.background.magnifier button.flat, popover > contents.background.touch-selection button.flat, popover > contents.background.magnifier button.flat, .app-notification button.flat, .osd button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: inset 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; box-shadow: none; text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; }
.csd popover.background > contents.touch-selection button.flat, .csd popover.background > contents.magnifier button.flat, popover.background > contents.touch-selection button.flat, popover.background > contents.magnifier button.flat, .app-notification button.flat, .osd button.flat { border-color: transparent; background-color: transparent; background-image: none; box-shadow: inset 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; box-shadow: none; text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; }
.csd popover > contents.background.touch-selection button.flat:hover, .csd popover > contents.background.magnifier button.flat:hover, popover > contents.background.touch-selection button.flat:hover, popover > contents.background.magnifier button.flat:hover, .app-notification button.flat:hover, .osd button.flat:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(83, 83, 83, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover.background > contents.touch-selection button.flat:hover, .csd popover.background > contents.magnifier button.flat:hover, popover.background > contents.touch-selection button.flat:hover, popover.background > contents.magnifier button.flat:hover, .app-notification button.flat:hover, .osd button.flat:hover { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(83, 83, 83, 0.7)); background-clip: padding-box; box-shadow: inset 0 1px rgba(255, 255, 255, 0.1); text-shadow: 0 1px black; -gtk-icon-shadow: 0 1px black; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover > contents.background.touch-selection button.flat:disabled, .csd popover > contents.background.magnifier button.flat:disabled, popover > contents.background.touch-selection button.flat:disabled, popover > contents.background.magnifier button.flat:disabled, .app-notification button.flat:disabled, .osd button.flat:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; background-image: none; border-color: transparent; box-shadow: none; }
.csd popover.background > contents.touch-selection button.flat:disabled, .csd popover.background > contents.magnifier button.flat:disabled, popover.background > contents.touch-selection button.flat:disabled, popover.background > contents.magnifier button.flat:disabled, .app-notification button.flat:disabled, .osd button.flat:disabled { color: #919190; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(71, 71, 71, 0.5)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; background-image: none; border-color: transparent; box-shadow: none; }
.csd popover > contents.background.touch-selection button.flat:backdrop, .csd popover > contents.background.magnifier button.flat:backdrop, popover > contents.background.touch-selection button.flat:backdrop, popover > contents.background.magnifier button.flat:backdrop, .app-notification button.flat:backdrop, .osd button.flat:backdrop { border-color: transparent; background-color: transparent; background-image: none; box-shadow: inset 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; }
.csd popover.background > contents.touch-selection button.flat:backdrop, .csd popover.background > contents.magnifier button.flat:backdrop, popover.background > contents.touch-selection button.flat:backdrop, popover.background > contents.magnifier button.flat:backdrop, .app-notification button.flat:backdrop, .osd button.flat:backdrop { border-color: transparent; background-color: transparent; background-image: none; box-shadow: inset 0 1px rgba(255, 255, 255, 0); text-shadow: none; -gtk-icon-shadow: none; }
.csd popover > contents.background.touch-selection button.flat:active, .csd popover > contents.background.magnifier button.flat:active, popover > contents.background.touch-selection button.flat:active, popover > contents.background.magnifier button.flat:active, .app-notification button.flat:active, .csd popover > contents.background.touch-selection button.flat:checked, .csd popover > contents.background.magnifier button.flat:checked, popover > contents.background.touch-selection button.flat:checked, popover > contents.background.magnifier button.flat:checked, .app-notification button.flat:checked, .osd button.flat:active, .osd button.flat:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; outline-color: rgba(238, 238, 236, 0.3); }
.csd popover.background > contents.touch-selection button.flat:active, .csd popover.background > contents.magnifier button.flat:active, popover.background > contents.touch-selection button.flat:active, popover.background > contents.magnifier button.flat:active, .app-notification button.flat:active, .csd popover.background > contents.touch-selection button.flat:checked, .csd popover.background > contents.magnifier button.flat:checked, popover.background > contents.touch-selection button.flat:checked, popover.background > contents.magnifier button.flat:checked, .app-notification button.flat:checked, .osd button.flat:active, .osd button.flat:checked { color: white; border-color: rgba(0, 0, 0, 0.7); background-color: transparent; background-image: image(rgba(0, 0, 0, 0.7)); background-clip: padding-box; box-shadow: none; text-shadow: none; -gtk-icon-shadow: none; outline-color: rgba(238, 238, 236, 0.3); }
button.suggested-action { color: white; outline-color: rgba(255, 255, 255, 0.3); border-color: #1b6acb; border-bottom-color: #15539e; background-image: linear-gradient(to top, #2379e2 2px, #3584e4); text-shadow: 0 -1px rgba(0, 0, 0, 0.559216); -gtk-icon-shadow: 0 -1px rgba(0, 0, 0, 0.559216); box-shadow: inset 0 1px rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.07); }
@@ -887,19 +887,19 @@ popover.menu > arrow, popover > arrow { background-color: #f6f5f4; border: 1px s
popover > contents { padding: 8px; background-color: #f6f5f4; border: 1px solid #cdc7c2; margin: 0px; }
popover > contents.background { background-color: #f6f5f4; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); }
popover.background > contents { background-color: #f6f5f4; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); }
.csd popover > contents.background, popover > contents.background { border: 1px solid #cdc7c2; border-radius: 9px; }
.csd popover.background > contents, popover.background > contents { border: 1px solid #cdc7c2; border-radius: 9px; }
popover > contents.background:backdrop { background-color: #f6f5f4; box-shadow: none; }
popover.background > contents:backdrop { background-color: #f6f5f4; box-shadow: none; }
popover > contents.background > list, popover > contents.background > .view, popover > contents.background > iconview, popover > contents.background > toolbar { border-style: none; background-color: transparent; }
popover.background > contents > list, popover.background > contents > .view, popover.background > contents > iconview, popover.background > contents > toolbar { border-style: none; background-color: transparent; }
.csd popover > contents.background.touch-selection, .csd popover > contents.background.magnifier, popover > contents.background.touch-selection, popover > contents.background.magnifier { border: 1px solid rgba(255, 255, 255, 0.1); }
.csd popover.background > contents.touch-selection, .csd popover.background > contents.magnifier, popover.background > contents.touch-selection, popover.background > contents.magnifier { border: 1px solid rgba(255, 255, 255, 0.1); }
popover > contents.background separator { margin: 3px; }
popover.background > contents separator { margin: 3px; }
popover > contents.background list separator { margin: 0px; }
popover.background > contents list separator { margin: 0px; }
/************* Notebooks * */
notebook box > header { padding: 1px; border-color: #cdc7c2; border-width: 1px; background-color: #e1dedb; }
@@ -1155,7 +1155,7 @@ row:selected switch slider:checked, row:selected switch slider { border-color: #
.view.content-view.check:active:not(list), iconview.content-view.check:active:not(list), .content-view .tile check:active:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: rgba(53, 132, 228, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; }
.view.content-view.check:backdrop:not(list), iconview.content-view.check:backdrop:not(list), .content-view .tile check:backdrop:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: rgba(141, 141, 141, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; }
.view.content-view.check:backdrop:not(list), iconview.content-view.check:backdrop:not(list), .content-view .tile check:backdrop:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: transparent; background-color: rgba(140, 140, 141, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: none; -gtk-icon-shadow: none; }
.view.content-view.check:checked:not(list), iconview.content-view.check:checked:not(list), .content-view .tile check:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: rgba(53, 132, 228, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; }
@@ -1163,7 +1163,7 @@ row:selected switch slider:checked, row:selected switch slider { border-color: #
.view.content-view.check:checked:active:not(list), iconview.content-view.check:checked:active:not(list), .content-view .tile check:checked:active:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: #eeeeec; background-color: rgba(53, 132, 228, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; }
.view.content-view.check:backdrop:checked:not(list), iconview.content-view.check:backdrop:checked:not(list), .content-view .tile check:backdrop:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: rgba(238, 238, 236, 0.8); background-color: rgba(141, 141, 141, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; }
.view.content-view.check:backdrop:checked:not(list), iconview.content-view.check:backdrop:checked:not(list), .content-view .tile check:backdrop:checked:not(list) { margin: 4px; min-width: 32px; min-height: 32px; color: rgba(238, 238, 236, 0.8); background-color: rgba(140, 140, 141, 0.95); border-radius: 5px; background-image: none; transition: 200ms; box-shadow: none; border-width: 0; -gtk-icon-source: -gtk-icontheme('object-select-symbolic'); -gtk-icon-shadow: none; }
checkbutton.text-button, radiobutton.text-button { padding: 2px 0; outline-offset: 0; }
@@ -2079,7 +2079,7 @@ popover.menu box.inline-buttons { border-radius: 5px; border-style: none; border
popover.menu box.circular-buttons { padding-bottom: 5px; }
popover.menu.background contents { background: white; }
popover.menu arrow, popover.menu.background contents { background-color: #ffffff; }
popover.menu.background separator { margin: 5px 0px; }

View File

@@ -827,7 +827,7 @@ summary = [
' Colord support: @0@'.format(get_option('colord')),
' Profiler: @0@'.format(get_option('profiler')),
' Introspection: @0@'.format(get_option('introspection')),
' Documentation: @0@'.format(get_option('documentation')),
' Documentation: @0@'.format(get_option('gtk_doc')),
' Man pages: @0@'.format(get_option('man-pages')),
' Build tests: @0@'.format(get_option('build-tests')),
' Install tests: @0@'.format(get_option('install-tests')),

View File

@@ -31,7 +31,7 @@ option('colord', type: 'combo', choices : ['yes', 'no', 'auto'], value : 'auto',
description : 'Build colord support for the CUPS printing backend')
# Documentation and introspection
option('documentation', type: 'boolean', value: 'false',
option('gtk_doc', type: 'boolean', value: 'false',
description : 'Build API reference and tools documentation')
option('man-pages', type: 'boolean', value: 'false',
description : 'Build man pages for installed tools')

View File

@@ -709,13 +709,7 @@ _post_send (GtkCupsRequest *request)
httpClearFields (request->http);
httpSetField (request->http, HTTP_FIELD_CONTENT_LENGTH, length);
httpSetField (request->http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
#ifdef HAVE_HTTPGETAUTHSTRING
httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString (request->http));
#else
#ifdef HAVE_HTTP_AUTHSTRING
httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, request->http->authstring);
#endif
#endif
if (httpPost (request->http, request->resource))
{
@@ -1198,13 +1192,7 @@ _get_send (GtkCupsRequest *request)
}
httpClearFields (request->http);
#ifdef HAVE_HTTPGETAUTHSTRING
httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString (request->http));
#else
#ifdef HAVE_HTTP_AUTHSTRING
httpSetField (request->http, HTTP_FIELD_AUTHORIZATION, request->http->authstring);
#endif
#endif
if (httpGet (request->http, request->resource))
{

View File

@@ -17,32 +17,8 @@ print_backends = ['file']
# Checks to see if we should compile with CUPS backend for GTK
enable_cups = enabled_print_backends.contains('cups')
if enable_cups
#cups_config = find_program('cups-config', required : true)
#if cups_config.found()
# FIXME: eek, see configure.ac (we're just not going to support non-standar prefix for now)
#endif
if cc.has_header('cups/cups.h')
# TODO: include_directories from cups-config
cups_major_version = cc.compute_int('CUPS_VERSION_MAJOR', prefix : '#include <cups/cups.h>')
cups_minor_version = cc.compute_int('CUPS_VERSION_MINOR', prefix : '#include <cups/cups.h>')
message('Found CUPS version: @0@.@1@'.format(cups_major_version, cups_minor_version))
if cups_major_version >= 2
if cc.compiles('#include <cups/http.h> \n http_t http; char *s = http.authstring;')
cdata.set('HAVE_HTTP_AUTHSTRING', 1,
description :'Define if cups http_t authstring field is accessible')
endif
libcups = cc.find_library('cups', required : true)
if libcups.found() and cc.has_function('httpGetAuthString', dependencies : libcups)
cdata.set('HAVE_HTTPGETAUTHSTRING', 1)
endif
print_backends += ['cups']
else
error('Need CUPS version >= 2.0')
endif
else
error('Cannot find CUPS headers in default prefix.')
endif
cups_dep = dependency('cups', version : '>=2.0', required: true)
print_backends += ['cups']
endif
# Checks to see if we should compile with cloudprint backend for GTK
@@ -101,7 +77,7 @@ if print_backends.contains('cups')
'gtkcupsutils.c',
'gtkcupssecretsutils.c',
c_args: printbackends_args,
dependencies: [libgtk_dep, libcups, colord_dep],
dependencies: [libgtk_dep, cups_dep, colord_dep],
install_dir: printbackends_install_dir,
install : true)
endif

View File

@@ -16,7 +16,7 @@ constraint_solver_simple (void)
gtk_constraint_solver_add_constraint (solver,
x, GTK_CONSTRAINT_RELATION_EQ, e,
GTK_CONSTRAINT_WEIGHT_REQUIRED);
GTK_CONSTRAINT_STRENGTH_REQUIRED);
double x_value = gtk_constraint_variable_get_value (x);
double y_value = gtk_constraint_variable_get_value (y);
@@ -39,8 +39,8 @@ constraint_solver_stay (void)
GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, "x", 5.0);
GtkConstraintVariable *y = gtk_constraint_solver_create_variable (solver, NULL, "y", 10.0);
gtk_constraint_solver_add_stay_variable (solver, x, GTK_CONSTRAINT_WEIGHT_WEAK);
gtk_constraint_solver_add_stay_variable (solver, y, GTK_CONSTRAINT_WEIGHT_WEAK);
gtk_constraint_solver_add_stay_variable (solver, x, GTK_CONSTRAINT_STRENGTH_WEAK);
gtk_constraint_solver_add_stay_variable (solver, y, GTK_CONSTRAINT_STRENGTH_WEAK);
double x_value = gtk_constraint_variable_get_value (x);
double y_value = gtk_constraint_variable_get_value (y);
@@ -64,7 +64,7 @@ constraint_solver_variable_geq_constant (void)
gtk_constraint_solver_add_constraint (solver,
x, GTK_CONSTRAINT_RELATION_GE, e,
GTK_CONSTRAINT_WEIGHT_REQUIRED);
GTK_CONSTRAINT_STRENGTH_REQUIRED);
double x_value = gtk_constraint_variable_get_value (x);
@@ -85,7 +85,7 @@ constraint_solver_variable_leq_constant (void)
gtk_constraint_solver_add_constraint (solver,
x, GTK_CONSTRAINT_RELATION_LE, e,
GTK_CONSTRAINT_WEIGHT_REQUIRED);
GTK_CONSTRAINT_STRENGTH_REQUIRED);
double x_value = gtk_constraint_variable_get_value (x);
@@ -106,7 +106,7 @@ constraint_solver_variable_eq_constant (void)
gtk_constraint_solver_add_constraint (solver,
x, GTK_CONSTRAINT_RELATION_EQ, e,
GTK_CONSTRAINT_WEIGHT_REQUIRED);
GTK_CONSTRAINT_STRENGTH_REQUIRED);
double x_value = gtk_constraint_variable_get_value (x);
@@ -133,11 +133,11 @@ constraint_solver_eq_with_stay (void)
gtk_constraint_expression_builder_term (&builder, width);
GtkConstraintExpression *right = gtk_constraint_expression_builder_finish (&builder);
gtk_constraint_solver_add_stay_variable (solver, width, GTK_CONSTRAINT_WEIGHT_WEAK);
gtk_constraint_solver_add_stay_variable (solver, right_min, GTK_CONSTRAINT_WEIGHT_WEAK);
gtk_constraint_solver_add_stay_variable (solver, width, GTK_CONSTRAINT_STRENGTH_WEAK);
gtk_constraint_solver_add_stay_variable (solver, right_min, GTK_CONSTRAINT_STRENGTH_WEAK);
gtk_constraint_solver_add_constraint (solver,
right_min, GTK_CONSTRAINT_RELATION_EQ, right,
GTK_CONSTRAINT_WEIGHT_REQUIRED);
GTK_CONSTRAINT_STRENGTH_REQUIRED);
double x_value = gtk_constraint_variable_get_value (x);
double width_value = gtk_constraint_variable_get_value (width);
@@ -165,22 +165,22 @@ constraint_solver_cassowary (void)
e = gtk_constraint_expression_new_from_variable (y);
gtk_constraint_solver_add_constraint (solver,
x, GTK_CONSTRAINT_RELATION_LE, e,
GTK_CONSTRAINT_WEIGHT_REQUIRED);
GTK_CONSTRAINT_STRENGTH_REQUIRED);
e = gtk_constraint_expression_plus_constant (gtk_constraint_expression_new_from_variable (x), 3.0);
gtk_constraint_solver_add_constraint (solver,
y, GTK_CONSTRAINT_RELATION_EQ, e,
GTK_CONSTRAINT_WEIGHT_REQUIRED);
GTK_CONSTRAINT_STRENGTH_REQUIRED);
e = gtk_constraint_expression_new (10.0);
gtk_constraint_solver_add_constraint (solver,
x, GTK_CONSTRAINT_RELATION_EQ, e,
GTK_CONSTRAINT_WEIGHT_WEAK);
GTK_CONSTRAINT_STRENGTH_WEAK);
e = gtk_constraint_expression_new (10.0);
gtk_constraint_solver_add_constraint (solver,
y, GTK_CONSTRAINT_RELATION_EQ, e,
GTK_CONSTRAINT_WEIGHT_WEAK);
GTK_CONSTRAINT_STRENGTH_WEAK);
double x_val = gtk_constraint_variable_get_value (x);
double y_val = gtk_constraint_variable_get_value (y);
@@ -205,11 +205,11 @@ constraint_solver_edit_var_required (void)
GtkConstraintSolver *solver = gtk_constraint_solver_new ();
GtkConstraintVariable *a = gtk_constraint_solver_create_variable (solver, NULL, "a", 0.0);
gtk_constraint_solver_add_stay_variable (solver, a, GTK_CONSTRAINT_WEIGHT_STRONG);
gtk_constraint_solver_add_stay_variable (solver, a, GTK_CONSTRAINT_STRENGTH_STRONG);
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 0.0, 0.001);
gtk_constraint_solver_add_edit_variable (solver, a, GTK_CONSTRAINT_WEIGHT_REQUIRED);
gtk_constraint_solver_add_edit_variable (solver, a, GTK_CONSTRAINT_STRENGTH_REQUIRED);
gtk_constraint_solver_begin_edit (solver);
gtk_constraint_solver_suggest_value (solver, a, 2.0);
gtk_constraint_solver_resolve (solver);
@@ -236,33 +236,45 @@ constraint_solver_edit_var_suggest (void)
GtkConstraintVariable *a = gtk_constraint_solver_create_variable (solver, NULL, "a", 0.0);
GtkConstraintVariable *b = gtk_constraint_solver_create_variable (solver, NULL, "b", 0.0);
gtk_constraint_solver_add_stay_variable (solver, a, GTK_CONSTRAINT_WEIGHT_STRONG);
gtk_constraint_solver_add_stay_variable (solver, a, GTK_CONSTRAINT_STRENGTH_STRONG);
GtkConstraintExpression *e = gtk_constraint_expression_new_from_variable (b);
gtk_constraint_solver_add_constraint (solver,
a, GTK_CONSTRAINT_RELATION_EQ, e,
GTK_CONSTRAINT_WEIGHT_REQUIRED);
GTK_CONSTRAINT_STRENGTH_REQUIRED);
gtk_constraint_solver_resolve (solver);
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 0.0, 0.001);
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (b), 0.0, 0.001);
gtk_constraint_solver_add_edit_variable (solver, a, GTK_CONSTRAINT_WEIGHT_REQUIRED);
gtk_constraint_solver_add_edit_variable (solver, a, GTK_CONSTRAINT_STRENGTH_REQUIRED);
gtk_constraint_solver_begin_edit (solver);
gtk_constraint_solver_suggest_value (solver, a, 2.0);
gtk_constraint_solver_resolve (solver);
g_test_message ("Check values after first edit");
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 2.0, 0.001);
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (b), 2.0, 0.001);
gtk_constraint_solver_suggest_value (solver, a, 10.0);
gtk_constraint_solver_resolve (solver);
g_test_message ("Check values after second edit");
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 10.0, 0.001);
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (b), 10.0, 0.001);
gtk_constraint_solver_suggest_value (solver, a, 12.0);
gtk_constraint_solver_resolve (solver);
g_test_message ("Check values after third edit");
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 12.0, 0.001);
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (b), 12.0, 0.001);
gtk_constraint_variable_unref (a);
gtk_constraint_variable_unref (b);
@@ -290,7 +302,7 @@ constraint_solver_paper (void)
expr = gtk_constraint_expression_builder_finish (&builder);
gtk_constraint_solver_add_constraint (solver,
middle, GTK_CONSTRAINT_RELATION_EQ, expr,
GTK_CONSTRAINT_WEIGHT_REQUIRED);
GTK_CONSTRAINT_STRENGTH_REQUIRED);
gtk_constraint_expression_builder_init (&builder, solver);
gtk_constraint_expression_builder_term (&builder, left);
@@ -299,17 +311,17 @@ constraint_solver_paper (void)
expr = gtk_constraint_expression_builder_finish (&builder);
gtk_constraint_solver_add_constraint (solver,
right, GTK_CONSTRAINT_RELATION_EQ, expr,
GTK_CONSTRAINT_WEIGHT_REQUIRED);
GTK_CONSTRAINT_STRENGTH_REQUIRED);
expr = gtk_constraint_expression_new (100.0);
gtk_constraint_solver_add_constraint (solver,
right, GTK_CONSTRAINT_RELATION_LE, expr,
GTK_CONSTRAINT_WEIGHT_REQUIRED);
GTK_CONSTRAINT_STRENGTH_REQUIRED);
expr = gtk_constraint_expression_new (0.0);
gtk_constraint_solver_add_constraint (solver,
left, GTK_CONSTRAINT_RELATION_GE, expr,
GTK_CONSTRAINT_WEIGHT_REQUIRED);
GTK_CONSTRAINT_STRENGTH_REQUIRED);
g_test_message ("Check constraints hold");
@@ -323,7 +335,7 @@ constraint_solver_paper (void)
g_assert_cmpfloat (gtk_constraint_variable_get_value (left), >=, 0.0);
gtk_constraint_variable_set_value (middle, 45.0);
gtk_constraint_solver_add_stay_variable (solver, middle, GTK_CONSTRAINT_WEIGHT_WEAK);
gtk_constraint_solver_add_stay_variable (solver, middle, GTK_CONSTRAINT_STRENGTH_WEAK);
g_test_message ("Check constraints hold after setting middle");

View File

@@ -300,6 +300,44 @@ test_submodel_add (void)
g_object_unref (flat);
}
static void
test_submodel_add2 (void)
{
GtkFlattenListModel *flat;
GListStore *model, *store[2];
model = g_list_store_new (G_TYPE_LIST_MODEL);
flat = new_model (model);
assert_model (flat, "");
assert_changes (flat, "");
store[0] = add_store (model, 1, 0, 0);
store[1] = add_store (model, 1, 0, 0);
store[2] = add_store (model, 1, 0, 0);
assert_model (flat, "");
assert_changes (flat, "");
add (store[0], 1);
assert_model (flat, "1");
assert_changes (flat, "+0");
add (store[1], 3);
assert_model (flat, "1 3");
assert_changes (flat, "+1");
add (store[0], 2);
assert_model (flat, "1 2 3");
assert_changes (flat, "+1");
add (store[1], 4);
assert_model (flat, "1 2 3 4");
assert_changes (flat, "+3");
g_object_unref (model);
g_object_unref (flat);
}
static void
test_model_remove (void)
{
@@ -365,6 +403,7 @@ main (int argc, char *argv[])
g_test_add_func ("/flattenlistmodel/model/add", test_model_add);
#if GLIB_CHECK_VERSION (2, 58, 0) /* g_list_store_splice() is broken before 2.58 */
g_test_add_func ("/flattenlistmodel/submodel/add", test_submodel_add);
g_test_add_func ("/flattenlistmodel/submodel/add2", test_submodel_add2);
g_test_add_func ("/flattenlistmodel/model/remove", test_model_remove);
g_test_add_func ("/flattenlistmodel/submodel/remove", test_submodel_remove);
#endif

681
testsuite/gtk/grid-layout.c Normal file
View File

@@ -0,0 +1,681 @@
/* Copyright (C) 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtk/gtk.h>
#define GTK_TYPE_GIZMO (gtk_gizmo_get_type ())
#define GTK_GIZMO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_GIZMO, GtkGizmo))
#define GTK_GIZMO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_GIZMO, GtkGizmoClass))
#define GTK_IS_GIZMO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_GIZMO))
#define GTK_IS_GIZMO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_GIZMO))
#define GTK_GIZMO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_GIZMO, GtkGizmoClass))
typedef struct _GtkGizmo GtkGizmo;
struct _GtkGizmo {
GtkWidget parent;
const char *name;
int min_width;
int min_height;
int nat_width;
int nat_height;
int width;
int height;
};
typedef GtkWidgetClass GtkGizmoClass;
G_DEFINE_TYPE (GtkGizmo, gtk_gizmo, GTK_TYPE_WIDGET);
static void
gtk_gizmo_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GtkGizmo *self = GTK_GIZMO (widget);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
*minimum = self->min_width;
*natural = self->nat_width;
}
else
{
*minimum = self->min_height;
*natural = self->nat_height;
}
}
static void
gtk_gizmo_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
GtkGizmo *self = GTK_GIZMO (widget);
self->width = width;
self->height = height;
}
static void
gtk_gizmo_class_init (GtkGizmoClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
widget_class->measure = gtk_gizmo_measure;
widget_class->size_allocate = gtk_gizmo_size_allocate;
}
static void
gtk_gizmo_init (GtkGizmo *self)
{
}
/* Create a grid with three children in row
*
* +--------+--------+--------+
* | child1 | child2 | child3 |
* +--------+--------+--------+
*
* Verify that
* - the layout has the expected min and nat sizes
* - the children get their nat width when the layout does
* - they all get the same height
*/
static void
test_simple_row (void)
{
GtkWidget *window;
GtkWidget *parent;
GtkLayoutManager *layout;
GtkGizmo *child1;
GtkGizmo *child2;
GtkGizmo *child3;
GtkLayoutChild *lc;
int minimum, natural;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
parent = g_object_new (GTK_TYPE_GIZMO, NULL);
gtk_container_add (GTK_CONTAINER (window), parent);
layout = gtk_grid_layout_new ();
gtk_widget_set_layout_manager (parent, layout);
child1 = g_object_new (GTK_TYPE_GIZMO, NULL);
child2 = g_object_new (GTK_TYPE_GIZMO, NULL);
child3 = g_object_new (GTK_TYPE_GIZMO, NULL);
child1->name = "child1";
child1->min_width = 10;
child1->min_height = 10;
child1->nat_width = 20;
child1->nat_height = 20;
child2->name = "child2";
child2->min_width = 20;
child2->min_height = 20;
child2->nat_width = 30;
child2->nat_height = 30;
child3->name = "child3";
child3->min_width = 30;
child3->min_height = 30;
child3->nat_width = 40;
child3->nat_height = 40;
gtk_widget_set_parent (GTK_WIDGET (child1), parent);
gtk_widget_set_parent (GTK_WIDGET (child2), parent);
gtk_widget_set_parent (GTK_WIDGET (child3), parent);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child1));
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child2));
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 1);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child3));
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 2);
#if 0
gtk_widget_show (window);
g_timeout_add (1000, (GSourceFunc)gtk_main_quit, NULL);
gtk_main ();
#endif
gtk_layout_manager_measure (layout,
parent,
GTK_ORIENTATION_HORIZONTAL,
-1,
&minimum,
&natural,
NULL,
NULL);
g_assert_cmpint (minimum, ==, 10 + 20 + 30);
g_assert_cmpint (natural, ==, 20 + 30 + 40);
gtk_layout_manager_measure (layout,
parent,
GTK_ORIENTATION_VERTICAL,
-1,
&minimum,
&natural,
NULL,
NULL);
g_assert_cmpint (minimum, ==, 30);
g_assert_cmpint (natural, ==, 40);
gtk_layout_manager_allocate (layout, parent, 90, 40, 0);
g_assert_cmpint (child1->width, ==, 20);
g_assert_cmpint (child2->width, ==, 30);
g_assert_cmpint (child3->width, ==, 40);
g_assert_cmpint (child1->height, ==, 40);
g_assert_cmpint (child2->height, ==, 40);
g_assert_cmpint (child3->height, ==, 40);
gtk_widget_unparent (GTK_WIDGET (child1));
gtk_widget_unparent (GTK_WIDGET (child2));
gtk_widget_unparent (GTK_WIDGET (child3));
gtk_widget_destroy (parent);
}
/* same as the previous test, with a column
*/
static void
test_simple_column (void)
{
GtkWidget *window;
GtkWidget *parent;
GtkLayoutManager *layout;
GtkGizmo *child1;
GtkGizmo *child2;
GtkGizmo *child3;
GtkLayoutChild *lc;
int minimum, natural;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
parent = g_object_new (GTK_TYPE_GIZMO, NULL);
gtk_container_add (GTK_CONTAINER (window), parent);
layout = gtk_grid_layout_new ();
gtk_widget_set_layout_manager (parent, layout);
child1 = g_object_new (GTK_TYPE_GIZMO, NULL);
child2 = g_object_new (GTK_TYPE_GIZMO, NULL);
child3 = g_object_new (GTK_TYPE_GIZMO, NULL);
child1->name = "child1";
child1->min_width = 10;
child1->min_height = 10;
child1->nat_width = 20;
child1->nat_height = 20;
child2->name = "child2";
child2->min_width = 20;
child2->min_height = 20;
child2->nat_width = 30;
child2->nat_height = 30;
child3->name = "child3";
child3->min_width = 30;
child3->min_height = 30;
child3->nat_width = 40;
child3->nat_height = 40;
gtk_widget_set_parent (GTK_WIDGET (child1), parent);
gtk_widget_set_parent (GTK_WIDGET (child2), parent);
gtk_widget_set_parent (GTK_WIDGET (child3), parent);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child1));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child2));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 1);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child3));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 2);
#if 0
gtk_widget_show (window);
g_timeout_add (1000, (GSourceFunc)gtk_main_quit, NULL);
gtk_main ();
#endif
gtk_layout_manager_measure (layout,
parent,
GTK_ORIENTATION_HORIZONTAL,
-1,
&minimum,
&natural,
NULL,
NULL);
g_assert_cmpint (minimum, ==, 30);
g_assert_cmpint (natural, ==, 40);
gtk_layout_manager_measure (layout,
parent,
GTK_ORIENTATION_VERTICAL,
-1,
&minimum,
&natural,
NULL,
NULL);
g_assert_cmpint (minimum, ==, 10 + 20 + 30);
g_assert_cmpint (natural, ==, 20 + 30 + 40);
gtk_layout_manager_allocate (layout, parent, 40, 90, 0);
g_assert_cmpint (child1->width, ==, 40);
g_assert_cmpint (child2->width, ==, 40);
g_assert_cmpint (child3->width, ==, 40);
g_assert_cmpint (child1->height, ==, 20);
g_assert_cmpint (child2->height, ==, 30);
g_assert_cmpint (child3->height, ==, 40);
gtk_widget_unparent (GTK_WIDGET (child1));
gtk_widget_unparent (GTK_WIDGET (child2));
gtk_widget_unparent (GTK_WIDGET (child3));
gtk_widget_destroy (parent);
}
/* Create a grid with spanning children
*
* +--------+-----------------+
* | child1 | child2 |
* +--------+--------+--------+
* | child3 | child4 |
* +-----------------+--------+
*
* Verify that
* - the layout has the expected min and nat sizes
* - the children get their nat width when the layout does
*/
static void
test_spans (void)
{
GtkWidget *window;
GtkWidget *parent;
GtkLayoutManager *layout;
GtkGizmo *child1;
GtkGizmo *child2;
GtkGizmo *child3;
GtkGizmo *child4;
GtkLayoutChild *lc;
int minimum, natural;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
parent = g_object_new (GTK_TYPE_GIZMO, NULL);
gtk_container_add (GTK_CONTAINER (window), parent);
layout = gtk_grid_layout_new ();
gtk_widget_set_layout_manager (parent, layout);
child1 = g_object_new (GTK_TYPE_GIZMO, NULL);
child2 = g_object_new (GTK_TYPE_GIZMO, NULL);
child3 = g_object_new (GTK_TYPE_GIZMO, NULL);
child4 = g_object_new (GTK_TYPE_GIZMO, NULL);
child1->name = "child1";
child1->min_width = 10;
child1->min_height = 10;
child1->nat_width = 20;
child1->nat_height = 20;
child2->name = "child2";
child2->min_width = 20;
child2->min_height = 20;
child2->nat_width = 30;
child2->nat_height = 30;
child3->name = "child3";
child3->min_width = 30;
child3->min_height = 30;
child3->nat_width = 40;
child3->nat_height = 40;
child4->name = "child4";
child4->min_width = 30;
child4->min_height = 30;
child4->nat_width = 40;
child4->nat_height = 40;
gtk_widget_set_parent (GTK_WIDGET (child1), parent);
gtk_widget_set_parent (GTK_WIDGET (child2), parent);
gtk_widget_set_parent (GTK_WIDGET (child3), parent);
gtk_widget_set_parent (GTK_WIDGET (child4), parent);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child1));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child2));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 1);
gtk_grid_layout_child_set_column_span (GTK_GRID_LAYOUT_CHILD (lc), 2);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child3));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 1);
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
gtk_grid_layout_child_set_column_span (GTK_GRID_LAYOUT_CHILD (lc), 2);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child4));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 1);
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 2);
#if 0
gtk_widget_show (window);
g_timeout_add (1000, (GSourceFunc)gtk_main_quit, NULL);
gtk_main ();
#endif
gtk_layout_manager_measure (layout,
parent,
GTK_ORIENTATION_HORIZONTAL,
-1,
&minimum,
&natural,
NULL,
NULL);
g_assert_cmpint (minimum, ==, 60);
g_assert_cmpint (natural, ==, 80);
gtk_layout_manager_measure (layout,
parent,
GTK_ORIENTATION_VERTICAL,
-1,
&minimum,
&natural,
NULL,
NULL);
g_assert_cmpint (minimum, ==, 50);
g_assert_cmpint (natural, ==, 70);
gtk_layout_manager_allocate (layout, parent, 80, 70, 0);
g_assert_cmpint (child1->width, ==, 30);
g_assert_cmpint (child2->width, ==, 50);
g_assert_cmpint (child3->width, ==, 40);
g_assert_cmpint (child4->width, ==, 40);
g_assert_cmpint (child1->height, ==, 30);
g_assert_cmpint (child2->height, ==, 30);
g_assert_cmpint (child3->height, ==, 40);
g_assert_cmpint (child4->height, ==, 40);
gtk_widget_unparent (GTK_WIDGET (child1));
gtk_widget_unparent (GTK_WIDGET (child2));
gtk_widget_unparent (GTK_WIDGET (child3));
gtk_widget_unparent (GTK_WIDGET (child4));
gtk_widget_destroy (parent);
}
/* Create a 2x2 homogeneous grid and verify
* all children get the same size.
*/
static void
test_homogeneous (void)
{
GtkWidget *window;
GtkWidget *parent;
GtkLayoutManager *layout;
GtkGizmo *child1;
GtkGizmo *child2;
GtkGizmo *child3;
GtkGizmo *child4;
GtkLayoutChild *lc;
int minimum, natural;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
parent = g_object_new (GTK_TYPE_GIZMO, NULL);
gtk_container_add (GTK_CONTAINER (window), parent);
layout = gtk_grid_layout_new ();
gtk_grid_layout_set_row_homogeneous (GTK_GRID_LAYOUT (layout), TRUE);
gtk_grid_layout_set_column_homogeneous (GTK_GRID_LAYOUT (layout), TRUE);
gtk_widget_set_layout_manager (parent, layout);
child1 = g_object_new (GTK_TYPE_GIZMO, NULL);
child2 = g_object_new (GTK_TYPE_GIZMO, NULL);
child3 = g_object_new (GTK_TYPE_GIZMO, NULL);
child4 = g_object_new (GTK_TYPE_GIZMO, NULL);
child1->name = "child1";
child1->min_width = 10;
child1->min_height = 10;
child1->nat_width = 20;
child1->nat_height = 20;
child2->name = "child2";
child2->min_width = 20;
child2->min_height = 20;
child2->nat_width = 30;
child2->nat_height = 30;
child3->name = "child3";
child3->min_width = 30;
child3->min_height = 30;
child3->nat_width = 40;
child3->nat_height = 40;
child4->name = "child4";
child4->min_width = 30;
child4->min_height = 30;
child4->nat_width = 40;
child4->nat_height = 40;
gtk_widget_set_parent (GTK_WIDGET (child1), parent);
gtk_widget_set_parent (GTK_WIDGET (child2), parent);
gtk_widget_set_parent (GTK_WIDGET (child3), parent);
gtk_widget_set_parent (GTK_WIDGET (child4), parent);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child1));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child2));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 1);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child3));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 1);
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child4));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 1);
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 1);
#if 0
gtk_widget_show (window);
g_timeout_add (1000, (GSourceFunc)gtk_main_quit, NULL);
gtk_main ();
#endif
gtk_layout_manager_measure (layout,
parent,
GTK_ORIENTATION_HORIZONTAL,
-1,
&minimum,
&natural,
NULL,
NULL);
g_assert_cmpint (minimum, ==, 60);
g_assert_cmpint (natural, ==, 80);
gtk_layout_manager_measure (layout,
parent,
GTK_ORIENTATION_VERTICAL,
-1,
&minimum,
&natural,
NULL,
NULL);
g_assert_cmpint (minimum, ==, 60);
g_assert_cmpint (natural, ==, 80);
gtk_layout_manager_allocate (layout, parent, 80, 80, 0);
g_assert_cmpint (child1->width, ==, 40);
g_assert_cmpint (child2->width, ==, 40);
g_assert_cmpint (child3->width, ==, 40);
g_assert_cmpint (child4->width, ==, 40);
g_assert_cmpint (child1->height, ==, 40);
g_assert_cmpint (child2->height, ==, 40);
g_assert_cmpint (child3->height, ==, 40);
g_assert_cmpint (child4->height, ==, 40);
gtk_widget_unparent (GTK_WIDGET (child1));
gtk_widget_unparent (GTK_WIDGET (child2));
gtk_widget_unparent (GTK_WIDGET (child3));
gtk_widget_unparent (GTK_WIDGET (child4));
gtk_widget_destroy (parent);
}
/* Create a layout with three children
*
* +--------+--------+
* | child1 | child2 |
* +--------+--------+
* | child3 |
* +-----------------+
*
* This is a layout that we also reproduce with
* constraints, for comparison. Among the contraints:
* - child1.width == child2.width
* - child1.height == child2.height == child3.height
*/
static void
test_simple_layout (void)
{
GtkWidget *window;
GtkWidget *parent;
GtkLayoutManager *layout;
GtkLayoutChild *lc;
GtkGizmo *child1;
GtkGizmo *child2;
GtkGizmo *child3;
int minimum, natural;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
parent = g_object_new (GTK_TYPE_GIZMO, NULL);
gtk_container_add (GTK_CONTAINER (window), parent);
layout = gtk_grid_layout_new ();
gtk_grid_layout_set_row_homogeneous (GTK_GRID_LAYOUT (layout), TRUE);
gtk_grid_layout_set_column_homogeneous (GTK_GRID_LAYOUT (layout), TRUE);
gtk_widget_set_layout_manager (parent, layout);
child1 = g_object_new (GTK_TYPE_GIZMO, NULL);
child2 = g_object_new (GTK_TYPE_GIZMO, NULL);
child3 = g_object_new (GTK_TYPE_GIZMO, NULL);
child1->name = "child1";
child1->min_width = 10;
child1->min_height = 10;
child1->nat_width = 50;
child1->nat_height = 50;
child2->name = "child2";
child2->min_width = 20;
child2->min_height = 20;
child2->nat_width = 50;
child2->nat_height = 50;
child3->name = "child3";
child3->min_width = 50;
child3->min_height = 10;
child3->nat_width = 50;
child3->nat_height = 50;
gtk_widget_set_parent (GTK_WIDGET (child1), parent);
gtk_widget_set_parent (GTK_WIDGET (child2), parent);
gtk_widget_set_parent (GTK_WIDGET (child3), parent);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child1));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child2));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 1);
lc = gtk_layout_manager_get_layout_child (layout, GTK_WIDGET (child3));
gtk_grid_layout_child_set_top_attach (GTK_GRID_LAYOUT_CHILD (lc), 1);
gtk_grid_layout_child_set_left_attach (GTK_GRID_LAYOUT_CHILD (lc), 0);
gtk_grid_layout_child_set_column_span (GTK_GRID_LAYOUT_CHILD (lc), 2);
gtk_layout_manager_measure (layout,
parent,
GTK_ORIENTATION_HORIZONTAL,
-1,
&minimum,
&natural,
NULL,
NULL);
g_assert_cmpint (minimum, ==, 50);
g_assert_cmpint (natural, ==, 100);
gtk_layout_manager_measure (layout,
parent,
GTK_ORIENTATION_VERTICAL,
-1,
&minimum,
&natural,
NULL,
NULL);
g_assert_cmpint (minimum, ==, 40);
g_assert_cmpint (natural, ==, 100);
gtk_layout_manager_allocate (layout, parent, 100, 100, 0);
g_assert_cmpint (child1->width, ==, 50);
g_assert_cmpint (child2->width, ==, 50);
g_assert_cmpint (child3->width, ==, 100);
g_assert_cmpint (child1->height, ==, 50);
g_assert_cmpint (child2->height, ==, 50);
g_assert_cmpint (child3->height, ==, 50);
gtk_widget_unparent (GTK_WIDGET (child1));
gtk_widget_unparent (GTK_WIDGET (child2));
gtk_widget_unparent (GTK_WIDGET (child3));
gtk_widget_destroy (parent);
}
int
main (int argc,
char *argv[])
{
gtk_test_init (&argc, &argv);
g_test_add_func ("/grid-layout/row", test_simple_row);
g_test_add_func ("/grid-layout/column", test_simple_column);
g_test_add_func ("/grid-layout/span", test_spans);
g_test_add_func ("/grid-layout/homogeneous", test_homogeneous);
g_test_add_func ("/grid-layout/simple", test_simple_layout);
return g_test_run();
}

View File

@@ -33,6 +33,7 @@ tests = [
['focus'],
['gestures'],
['grid'],
['grid-layout'],
['gtkmenu'],
['icontheme'],
['keyhash', ['../../gtk/gtkkeyhash.c', gtkresources, '../../gtk/gtkprivate.c'], gtk_cargs],