Compare commits

..

127 Commits

Author SHA1 Message Date
Matthias Clasen 303dcc667b gtk-demo: Add a few path benchmarks
The Tiger and Graph examples in the fishbowl test
path handling.
2022-04-08 16:44:29 -04:00
Matthias Clasen a73b6b4392 Add gsk_stroke_node_get_stroke_path
We will implement stroking by filling the stroke path.
2022-04-08 16:44:29 -04:00
Matthias Clasen a88dbb820b Add GskRoundedRectContour
The main advantage here is that we can avoid
going through the stroker for the common case
of rounded rectangles.
2022-04-08 16:44:29 -04:00
Matthias Clasen b61058cd22 Add a demo for path ops 2022-04-08 16:44:29 -04:00
Matthias Clasen 8b1d7fd622 Add some tests for pathops 2022-04-08 16:44:29 -04:00
Matthias Clasen 4e24f88482 path: Implement path ops
Implement boolean operations on paths.
2022-04-08 16:44:29 -04:00
Matthias Clasen 98c40daa5f path: Add gsk_path_transform
This is an obvious operation to want for paths.
2022-04-08 16:44:29 -04:00
Matthias Clasen def04f5df3 path: Add gsk_path_is_convex
Add a function to compute whether a path is convex.
2022-04-08 16:44:29 -04:00
Matthias Clasen 9709f20c53 path: Add gsk_path_get_flags
The flags contain some useful information.
2022-04-08 16:44:29 -04:00
Matthias Clasen 3661086dcc path: Add gsk_path_reverse
This is a natural operation, and useful for debugging things.
2022-04-08 16:44:29 -04:00
Matthias Clasen d71183bbfe curve: Limit recursion depth 2022-04-08 16:44:29 -04:00
Matthias Clasen 2430c55228 gtk-demo: Use gsk_path_builder_add_layout
We have an api now to hide the cairo use.
2022-04-08 16:44:29 -04:00
Matthias Clasen a8aa460330 pathbuilder: Add gsk_path_builder_add_layout
This api makes it easy to turn text into a path that
can be further manipulated.

The implementation currently goes via cairo.
2022-04-08 16:44:29 -04:00
Matthias Clasen b148c792ca Add an interactive path test
This one is for interactive exploring of svg paths.

You can enter an SVG path in the entry and hit Enter
to see how GSK renders it. If you click the button
in the headerbar, you can see what GTK thinks the
closest point, tangent and distance are wrt. to the
mouse position, and the bounding box of the path.

There's also stroke parameters to play with.
2022-04-08 16:44:29 -04:00
Matthias Clasen cc3b47cef6 pathmeasure: Add gsk_path_measure_get_curvature 2022-04-08 16:44:29 -04:00
Matthias Clasen 386a58f0f4 stroke: Make gsk_stroke_to_cairo public
It comes in handy, and does no harm.
2022-04-08 16:44:29 -04:00
Matthias Clasen 10cd4fc48c gtk-demo: Add a curve editor demo 2022-04-08 16:44:29 -04:00
Matthias Clasen 0debc3d891 path: Implement offsetting
Implement offsetting of paths by reusing the
infrastructure of the stroker.
2022-04-08 16:44:29 -04:00
Matthias Clasen f166ec5bc9 path: Add gsk_path_offset
Add a function that takes a path, and offsets it
by some distance, applying line-join parameters
as needed.

This commit just adds the api, the implementation
will be in the following commit.
2022-04-08 16:44:29 -04:00
Matthias Clasen 95c3a34cfb stroker: Implement arcs
Implement arced joins as specified in SVG2.
2022-04-08 16:44:29 -04:00
Matthias Clasen 3720429958 Add GSK_LINE_JOIN_ARCS
Implementation will follow.
2022-04-08 16:44:29 -04:00
Matthias Clasen 57904fcd6a Add another stroker test
Check that the outlines of random paths look as
expected. We currently have to exclude paths where
points get too close to each other.
2022-04-08 16:44:29 -04:00
Matthias Clasen 9620b5eb38 Add basic tests for strokes
Add tests to check that any point on a path is
always at most half the line-width away from the
stroke path with that line-width.
2022-04-08 16:44:29 -04:00
Matthias Clasen 9bb552d23c path: Implement stroking
Implement gsk_contour_default_add_stroke, which takes a contour
and stroke parameters, and adds contours to a path builder for
the outline that would be produced by stroking the path with these
parameters.

The current implementation does not try to handle short segments
in the vicinity of sharp joins in any special way, so there can
be some artifacts in that situation.
2022-04-08 16:44:29 -04:00
Matthias Clasen 188f78478c curve: Add some curve utilities
These apis will be used in the stroker.
2022-04-08 16:44:29 -04:00
Matthias Clasen 2b8fe62b55 contour: Special-case circles for strokes
The outline of a circle is just two circles.
2022-04-08 16:44:29 -04:00
Matthias Clasen 31fe02e449 contour: Special-case rects for strokes
In many cases, the outline of a rectangle is just
two rectangles.
2022-04-08 16:44:29 -04:00
Matthias Clasen 068838eac4 path: Add gsk_path_stroke
Add the plumbing that will let us do special-case stroking
for rectangles, circles and other special contours.

There is no implementation yet.
2022-04-08 16:44:29 -04:00
Matthias Clasen 81dae3e15f curve: Add gsk_curve_print
Useful for debugging.
2022-04-08 16:44:28 -04:00
Matthias Clasen e9a010eb67 curve: Add gsk_curve_get_curvature
This will be used in the stroker.
2022-04-08 16:44:28 -04:00
Matthias Clasen 282be569f6 curve: Add gsk_curve_get_normal
Its easy but thats no reason not to have this api.
2022-04-08 16:44:28 -04:00
Matthias Clasen f2069508cf Add a test for gsk_curve_offset
The stroker relies on offsetting.
This only tests a few very simple cases.
2022-04-08 16:44:28 -04:00
Matthias Clasen 56f587a5a3 Add a test for gsk_curve_reverse
The stroker relies on this working.
2022-04-08 16:44:28 -04:00
Matthias Clasen 64807abc59 Add a test for tangents of degenerate curves
The stroker relies on these to work.
2022-04-08 16:44:28 -04:00
Matthias Clasen 2cace6bada curve: Handle degenerate cases
Nothing prevents control points from being identical,
and if that happens, some of our constructions involving
tangents and normals break down. Handle these cases in
get_{start,end}_tangent and offset, for the case of
cubics.
2022-04-08 16:44:28 -04:00
Matthias Clasen b1363aadeb curve: Add gsk_curve_reverse
This will be used in stroking.
2022-04-08 16:44:28 -04:00
Matthias Clasen e44be94835 curve: Add gsk_curve_offset
This method creates an offset curve from an existing
curve by just moving the control points laterally.

This will be used in stroking.
2022-04-08 16:44:28 -04:00
Matthias Clasen ffc663b5c5 Add conic decomposition tests
We don't have good error bounds here, unfortunately.
2022-04-08 16:44:28 -04:00
Matthias Clasen fcf43c4012 path: support conic->curve in foreach 2022-04-08 16:44:28 -04:00
Matthias Clasen a9c36f8ba9 curve: Add gsk_curve_decompose_curve
This is mainly useful for decomposing a conic into
cubics. The criterion here for terminating the
subdivision is very improvised.
2022-04-08 16:44:28 -04:00
Matthias Clasen 72835f321f Add a performance test for curve eval
All curve types are equally fast here.
2022-04-08 16:44:28 -04:00
Matthias Clasen 8069495f76 Add a performance test for curve intersection
This shows how much more expensive curve
intersections are.
2022-04-08 16:44:28 -04:00
Matthias Clasen 6a51dfc929 Add curve split tests 2022-04-08 16:44:28 -04:00
Matthias Clasen 1fba399296 testsuite: Add special-case curve tests 2022-04-08 16:44:28 -04:00
Matthias Clasen 4d6c2108ac Add curve intersection tests
These tests check that gsk_curve_intersect finds
the intersections we want.
2022-04-08 16:44:28 -04:00
Matthias Clasen ac5c742df6 curve: Add gsk_curve_intersect
Add a way to find the intersections of two curves.
This will be used in stroking.
2022-04-08 16:44:28 -04:00
Matthias Clasen ee799830ef curve: Add gsk_curve_get_bounds
Add getters for bounding boxes of curves.
2022-04-08 16:44:28 -04:00
Matthias Clasen 7e9c94e599 Add a bounding box type
graphene_rect_t does not quite work for this purpose.
2022-04-08 16:44:28 -04:00
Matthias Clasen 9e2c689745 Only test conic weights between 1/20 and 20
The rest just give us no end of numeric trouble.
2022-04-08 16:44:28 -04:00
Benjamin Otte 94f93dbd2d path: Add gsk_path_builder_add_ellipse() 2022-04-08 16:44:28 -04:00
Benjamin Otte 846ae95818 path: Change semantics of gtk_path_builder_add_segment()
Allow start >= end to mean that the path continues at the beginning
after reaching the end until it reaches the point at @end.
2022-04-08 16:44:28 -04:00
Benjamin Otte c28fd1dbe6 pathmeasure: Add gsk_path_measure_is_closed () 2022-04-08 16:44:28 -04:00
Benjamin Otte 6021b76a6b pathmeasure: Add gsk_path_measure_restrict_to_contour() 2022-04-08 16:44:28 -04:00
Matthias Clasen 15541842e4 pathmeasure: Add gsk_path_measure_get_{path,tolerance}
These are just nice apis to have and avoid having to carry
these around as extra arguments in many places.

This was showing up as inconvenience in writing tests
for the measure apis.
2022-04-08 16:44:28 -04:00
Benjamin Otte 1dbfff9f2b gtk-demo: Use dashes in path-fill demo 2022-04-08 16:44:28 -04:00
Matthias Clasen 2418d67e23 gsk: Use stroke bounds in the stroke node
We can use gsk_path_get_stroke_bounds to get a
better estimate for the bounds of the stroke node.
2022-04-08 16:44:28 -04:00
Matthias Clasen 91193e807f path: Add gsk_path_get_stroke_bounds
A relatively cheap way to get bounds for the area
that would be affected by stroking a path.
2022-04-08 16:44:28 -04:00
Benjamin Otte d537df1f62 testsuite: Add tests for the dasher 2022-04-08 16:44:28 -04:00
Benjamin Otte 4a596fe5bf path: Add a foreach function that dashes a path 2022-04-08 16:44:28 -04:00
Benjamin Otte 27e7b97d28 path: Deal with non-uniformness of progress parameter
The progress is non-uniform, so simple translation of progress doesn't work.
So check if larger and smaller values inch closer towards minimal distance.
2022-04-08 16:44:28 -04:00
Benjamin Otte 95a34803cb path: Always decompose conics into at least 2 segments
Conics are evil in that their parameter skews towards the center, and if
it's a very flat conic (weight almost equal to 0), then we'd approximate
it with a single segment and not subdivide, which would cause the
parameter to be wildly off around 0.25 or 0.75.

And that would cause offset calculations to fail.
2022-04-08 16:44:28 -04:00
Matthias Clasen c3571c104d testsuite Add curve tangent tests 2022-04-08 16:44:28 -04:00
Benjamin Otte 451a629de1 testsuite: Add a test for the conic that got us segment() 2022-04-08 16:44:28 -04:00
Benjamin Otte c0e332f677 path: Add gsk_curve_segment()
Using split() twice with scaled t values does not work with conics.
2022-04-08 16:44:28 -04:00
Benjamin Otte 66edb0b5cd testsuite: Add a test for gsk_curve_decompose() 2022-04-08 16:44:28 -04:00
Benjamin Otte a430099e35 testuite: Add tests for gsk_curve_get_tangent() 2022-04-08 16:44:28 -04:00
Matthias Clasen 26aef58709 testuite: Add tests for gsk_curve_get_point()
Add a few tests for gsk_curve_get_point().

Since GskCurve is not public api, we add gskcurve.c
as source to the test binary.
2022-04-08 16:44:28 -04:00
Benjamin Otte d15f558769 curve: Split eval() into get_point() and get_tangent()
That's more in line with the get_start/end_point/tangent() functions.

Plus, those calls are independent and we usually want one or the other.
2022-04-08 16:44:28 -04:00
Matthias Clasen 0c2f43d1bd curve: Add gsk_curve_get_{start,end}_tangent
Add a way to get the tangents at the start and end of the curve.
This will be used in stroking.
2022-04-08 16:44:28 -04:00
Benjamin Otte 77d6bc9158 testsuite: Add conics to the random paths 2022-04-08 16:44:28 -04:00
Benjamin Otte ef120ef1a0 path: Add GskCurve
GskCurve is an abstraction for path operations. It's essentially a
collection of vfuncs per GskPathOperation.

GskStandardContour has been ported to use it where appropriate.
2022-04-08 16:44:28 -04:00
Benjamin Otte dcf0ba6920 path: Introduce gskpathop
A gskpathop is a pointer to a graphene_point_t* with the low bits used
to encode the GskPathOperation. It's an easy way to introduce API for
operations.

So far it's just used to replace GskStandardOperation.
2022-04-08 08:06:02 -04:00
Benjamin Otte 159fb16494 css: Replace border rendering code with GskPath 2022-04-08 08:06:02 -04:00
Benjamin Otte 7965c420bc pathbuilder: Add gsk_path_builder_add_rounded_rect()
It works, but does not use a custom contour yet.
2022-04-08 08:06:02 -04:00
Benjamin Otte 7b83101ed7 path: Add conic curves
So far this just adds the API, if you use it, you'll get lots of
g_warnings().

This will be fixed in future commits.
2022-04-08 08:06:02 -04:00
Benjamin Otte dd2036ea01 path: Rename to gtk_path_builder_add_segment()
It's about bulding paths, not about measuring them.
2022-04-08 08:06:02 -04:00
Matthias Clasen c66d61a55c path: Split contours into their own file
I'm not sure I want to keep all contours in one file,
but for now that's how it is.
2022-04-08 08:06:02 -04:00
Benjamin Otte e2b5e83812 path: Make all private contour APIs take a GskContour
... instead of a path, index tuple.
2022-04-08 08:06:02 -04:00
Matthias Clasen d773a36623 Add a nodeparser tests for fill and stroke nodes 2022-04-08 08:06:02 -04:00
Benjamin Otte a4374f41db stroke: Add support for dashes
... and hook it up in the node parser and for Cairo rendering.
2022-04-08 08:06:02 -04:00
Matthias Clasen 822cfb022f gsk: Implement parsing fill and stroke nodes
Make serialization and deserialization work for stroke and
fill nodes.
2022-04-08 08:06:02 -04:00
Benjamin Otte 95c823a377 path: Add flags to gsk_path_foreach()
This way we can default to the siplest possible foreach() output - like
cairo_copy_path_flat() decomposing everything into lines - and add flags
to get more and more fancy.

This will be useful to have conics automatically decomposed for Cairo
drawing or if we want to add more line types in the future.
2022-04-08 08:06:02 -04:00
Benjamin Otte 6949cfa14b testsuite: Add tests for in_fill()
Add a test for measure_in_fill. Also test some
special cases involving horizontal edges.
2022-04-08 08:06:02 -04:00
Matthias Clasen ccd1d6a0be pathmeasure: Implement gsk_path_measure_in_fill
Implement this in the obvious way, using the decomposed form
of standard contours. Since the decomposed form is part of the
measure object, this api moves from gsk_path_in_fill to
gsk_path_measure_in_fill.
2022-04-08 08:06:02 -04:00
Benjamin Otte 45c0851577 testsuite: Add a parsing test
This test includes an implementation of a gsk_path_equal() func with
a tolerance that is necessary because parsing does not always work
100% exactly due to floating point rounding, so we can't just
compare the to_string() output.
2022-04-08 08:06:02 -04:00
Matthias Clasen 37c1461a60 path: Special-case rects and circles
Write out the commands for rects and circles in a special
way, and add code in the parser to recognize this, so we
can successfully round-trip these through the SVG path format.

The special way - for people who want to use it for debugging -
for now is that we use uppercase "Z" to close standard paths, but
lowercase "z" to close our special paths.

A test is included, but the random path serializations should take care
of it, too.
2022-04-08 08:06:02 -04:00
Matthias Clasen 84162d8550 path: Fix serialization for circles
The svg A can not do a full circle, since it is a two point
parametrization - if the start and end point are the same,
it draws nothing. So, use two arcs.
2022-04-08 08:06:02 -04:00
Benjamin Otte 3f77813ce2 testsuite: Add librsvg path tests 2022-04-08 08:06:02 -04:00
Matthias Clasen b539e21528 path: Implement gsk_path_parse
Implement the SVG path syntax to read back the strings
that we generate when serializing paths. The tests for
this code are taken from librsvg.

This includes an elliptical arc implementation according
to the SVG spec. The code is mostly taken from librsvg,
but pretty directly follows the SVG spec implementation
notes. We don't export this, since the parametrization
is inconvenient. We do want an arc_to API, but
these are not the arcs we are looking for.
2022-04-08 08:06:02 -04:00
Matthias Clasen 00f0225712 path: Implement SVG arcs
This is elliptical arc implementation according to the SVG spec.
The code is mostly taken from librsvg, but pretty directly
follows the SVG spec implementation notes.

We don't export this, since the parametrization is inconvenient.
We do want an arc_to API, but these are not the arcs we are
looking for.

It will be used in parsing SVG path syntax.
2022-04-08 08:06:02 -04:00
Matthias Clasen 7aad5998c6 stroke: Add miter limit
Add a miter limit to GskStroke. This will be needed to
fully implement line joins.

Also introduce the GSK_LINE_JOIN_MITER_CLIP value,
following SVG 2.0. cairo does not have it, so translate
it to plain miter when using cairo.
2022-04-08 08:06:02 -04:00
Benjamin Otte a5fa6fded0 testsuite: Add relative path functions
They're making the paths slightly weirder, but they test public API, so
woohoo!
2022-04-08 08:06:02 -04:00
Benjamin Otte 845102fc22 pathbuilder: Add relative path commands
And gsk_path_builder_get_current_point().

They will be needed by the string parser.
2022-04-08 08:06:02 -04:00
Benjamin Otte d570e96a15 path: Add GSK_CIRCLE_POINT_INIT() to initialize points on the circle
This is just splitting out a commonly done operation into a macro.
2022-04-08 08:06:02 -04:00
Benjamin Otte 924f036667 pathbuilder: Redo semantics for starting curves
We now always have a "current point" which is either the last point an
operation was made to, or (0, 0) if no drawing operation has
been made yet.

Adding a contour of any kind to the builder will always update the
current point to that contour's end point.
2022-04-08 08:06:02 -04:00
Benjamin Otte e8750af295 gtk-demo: Show closest point in text-on-path demo 2022-04-08 08:06:02 -04:00
Benjamin Otte 4bcc4529da path: Split GskPathBuilder into its own file
... and add missing API docs.
2022-04-08 08:06:02 -04:00
Benjamin Otte 25582c8b32 testsuite: Add a test using get_point() and get_closest_point() 2022-04-08 08:06:02 -04:00
Benjamin Otte 8007e378c3 testsuite: Add a test for get_point() 2022-04-08 08:06:02 -04:00
Benjamin Otte 3dac5d2217 testsuite: Update create_random_path()
1. Allow specifying the max number of contours
2. Be smarter about creating the paths:
   With 10% chance, create a "weird" path like the empty one or only
   points or things like that.
   Otherwise create a bunch of contours, with 2/3 a standard contour,
   with 1/3 a predetermined one.
2022-04-08 08:06:02 -04:00
Benjamin Otte bcd90a884c gtk-demo: Add cute maze demo 2022-04-08 08:06:02 -04:00
Benjamin Otte d77f8c6ab9 testsuite: Add tests for gsk_path_measure_get_closest_point() 2022-04-08 08:06:02 -04:00
Benjamin Otte 3b8cbd10f8 pathmeasure: Add gsk_path_measure_get_closest_point()
... and gsk_path_measure_get_closest_point_full().

Those 2 functions allow finding the closest point
on a path to a given point.
2022-04-08 08:06:02 -04:00
Benjamin Otte d5f378bd0a spline: Use Skia's tolerance checks
This avoids measuring being too far off (it's still off, but it's less
than a percent now.
2022-04-08 08:06:02 -04:00
Benjamin Otte 895205894e testsuite: Add tests for gsk_path_measure_add_segment() 2022-04-08 08:06:02 -04:00
Benjamin Otte f23af85cb2 gtk-demo: Add a text-on-path demo 2022-04-08 08:06:02 -04:00
Benjamin Otte cdb528e566 gtk-demo: Add a path-fill demo 2022-04-07 22:37:56 -04:00
Benjamin Otte 7465f57a57 pathmeasure: Add gsk_path_measure_get_point()
Allows querying the coordinates and direction
of any specific point on a path.
2022-04-07 22:37:56 -04:00
Matthias Clasen d9b3589164 path: Add gsk_path_add_circle()
Adds a circle contour, too.
2022-04-07 22:37:56 -04:00
Benjamin Otte f1d8b96fd3 pathmeasure: Implement support for beziers
Instead of treating bezier curves as lines, we properly decompose them
into line segments now so that we can treat those as lines.
2022-04-07 22:37:56 -04:00
Benjamin Otte 19111abcdd path: Implement gsk_path_to_cairo() using foreach() 2022-04-07 22:37:56 -04:00
Benjamin Otte 32fb2667ff path: Add gsk_path_foreach() 2022-04-07 22:37:56 -04:00
Benjamin Otte e69a774da9 path: Collect flags
We don't need them yet, but maybe later.
2022-04-07 22:37:56 -04:00
Benjamin Otte adb0877a6b testsuite: Add path tests 2022-04-07 22:37:56 -04:00
Benjamin Otte ffb2744408 pathmeasure: Add gsk_path_measure_add_segment()
This allows chunking paths, weeee.
2022-04-07 22:37:56 -04:00
Benjamin Otte 8e073912e4 path: Add gsk_path_builder_add_path() 2022-04-07 22:37:56 -04:00
Benjamin Otte be3e7bbeb0 gsk: Add GskPathMeasure
An object to do measuring operations on paths - determining their
length, cutting off subpaths, things like that.
2022-04-07 22:37:56 -04:00
Benjamin Otte 9dfac7204f path: Change data structure for standard path
Instead of the Cairo method and imitating cairo_path_data_t, use the
Skia method and keep points and operations separate.

That way we get a points array that includes the starting point -
because it's always the end point of the previous operation.
2022-04-07 22:37:56 -04:00
Benjamin Otte 93798a0877 popover: Use fill and stroke nodes instead of Cairo
... to render the arrow.

The arrow should really be turned into a real thing - maybe an icon?
2022-04-07 22:37:56 -04:00
Benjamin Otte a0676cff0e snapshot: Add gtk_snapshot_push_stroke() 2022-04-07 22:37:56 -04:00
Benjamin Otte e501c81621 gsk: Add GskStrokeNode 2022-04-07 22:37:56 -04:00
Benjamin Otte b349519629 gsk: Add GskStroke
It's unused in this commit. This just prepares the new object.
2022-04-07 22:37:56 -04:00
Benjamin Otte 93d8b46a64 demos: Add a simple demo filling a path 2022-04-07 22:37:56 -04:00
Benjamin Otte 92d5dcb37e snapshot: Add gtk_snapshot_push_fill() 2022-04-07 22:37:56 -04:00
Benjamin Otte 5b16d333a6 gsk: Add GskFillNode
Take a rendernode as source and a GskPath and fill the region in the
path just like cairo_fill() would.
2022-04-07 22:37:56 -04:00
Benjamin Otte b3424bad52 gsk: Add GskPath 2022-04-07 22:37:56 -04:00
Matthias Clasen fb7f87618a Add a debug key for paths
Not used yet.
2022-04-07 22:37:56 -04:00
1008 changed files with 1066089 additions and 47556 deletions
+2 -4
View File
@@ -25,7 +25,7 @@ variables:
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true"
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled"
MESON_TEST_TIMEOUT_MULTIPLIER: 3
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v38"
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v36"
FLATPAK_IMAGE: "registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master"
.only-default:
@@ -58,7 +58,6 @@ style-check-diff:
- "${CI_PROJECT_DIR}/_build/report*.xml"
- "${CI_PROJECT_DIR}/_build/report*.html"
- "${CI_PROJECT_DIR}/_build/testsuite/reftests/output/*/*.png"
- "${CI_PROJECT_DIR}/_build/testsuite/reftests/output/*/*.node"
- "${CI_PROJECT_DIR}/_build/testsuite/tools/output/*/*"
- "${CI_PROJECT_DIR}/_build/testsuite/gsk/compare/*/*/*.png"
- "${CI_PROJECT_DIR}/_build/testsuite/css/output/*/*.syscap"
@@ -173,7 +172,7 @@ macos:
needs: []
before_script:
- bash .gitlab-ci/show-info-osx.sh
- pip3 install --user meson==0.60.3
- pip3 install --user meson==0.59
- pip3 install --user ninja
- export PATH=/Users/gitlabrunner/Library/Python/3.7/bin:$PATH
- export MESON_FORCE_BACKTRACE=1
@@ -346,7 +345,6 @@ reference:
- _reference
publish-docs:
image: fedora:latest
stage: publish
needs: ['reference']
script:
-3
View File
@@ -14,9 +14,6 @@ Each Docker image has a tag composed of two parts:
See the [container registry][registry] for the available images for each
branch, as well as their available versions.
Note that using `latest` as version number will overwrite the most
recently uploaded image in the registry.
### Checklist for Updating a CI image
- [ ] Update the `${image}.Dockerfile` file with the dependencies
+2 -1
View File
@@ -1,4 +1,4 @@
FROM fedora:36
FROM fedora:34
RUN dnf -y install \
adwaita-icon-theme \
@@ -87,6 +87,7 @@ RUN dnf -y install \
python3-wheel \
redhat-rpm-config \
sassc \
systemtap-sdt-devel \
vulkan-devel \
wayland-devel \
wayland-protocols-devel \
-4
View File
@@ -185,8 +185,6 @@ ul.images li {
<li><img alt="ref" src="{{ failure.image_data.ref }}" /></li>
<li><img alt="out" src="{{ failure.image_data.out }}" /></li>
<li><img alt="diff" src="{{ failure.image_data.diff }}" /></li>
<li><a href="{{ failure.image_data.refnode }}">ref node</a></li>
<li><a href="{{ failure.image_data.outnode }}">out node</a></li>
</ul>
{% endif %}
</li>
@@ -313,8 +311,6 @@ for line in args.infile:
image_data = {
'ref': os.path.join(args.reftest_output_dir, '{}.ref.png'.format(basename)),
'out': os.path.join(args.reftest_output_dir, '{}.out.png'.format(basename)),
'refnode': os.path.join(args.reftest_output_dir, '{}.ref.node'.format(basename)),
'outnode': os.path.join(args.reftest_output_dir, '{}.out.node'.format(basename)),
'diff': os.path.join(args.reftest_output_dir, '{}.diff.png'.format(basename)),
}
+1 -1
View File
@@ -5,7 +5,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliar
@echo on
:: FIXME: make warnings fatal
pip3 install --upgrade --user meson==0.60.3 || goto :error
pip3 install --upgrade --user meson==0.59 || goto :error
meson -Ddebug=false -Dmedia-gstreamer=disabled _build || goto :error
ninja -C _build || goto :error
+1 -1
View File
@@ -28,7 +28,7 @@ pacman --noconfirm -S --needed \
mingw-w64-$MSYS2_ARCH-graphene \
mingw-w64-$MSYS2_ARCH-json-glib \
mingw-w64-$MSYS2_ARCH-libepoxy \
mingw-w64-$MSYS2_ARCH-pango2 \
mingw-w64-$MSYS2_ARCH-pango \
mingw-w64-$MSYS2_ARCH-fribidi \
mingw-w64-$MSYS2_ARCH-gst-plugins-bad-libs \
mingw-w64-$MSYS2_ARCH-shared-mime-info \
-150
View File
@@ -1,153 +1,3 @@
Overview of Changes in 4.7.0, 07-05-2022
========================================
* GtkTextView:
- Reduce overdraws
* GtkViewport:
- Default scroll-to-focus to TRUE
* GtkText:
- Stop blinking when we lose focus
* GtkSearchEntry:
- Make search delay configurable
* GtkPopoverMenu:
- Fix RTL positioning of buttons
* GtkLabel:
- Fix focus keynav with links
* GtkFileChooser:
- Prevent undesirable completion popups
- Fix a corner case in save mode
- Keep the portal filechooser alive long enough
* GtkCheckButton:
- Allow setting a custom child
* GtkEditableLabel:
- Make the :editing property writable
* GtkColumnView:
- Various optimizations to improve scrolling performance
* GtkTreeStore:
- Allow populating tree stores from ui files
* GtkBoxLayout:
- Avoid infinite loops
* CSS:
- Optimize reordering within the same parent
* Emoji:
- Update to CLDR v40 / Unicode 14
- Add more locales
* Input:
- Add scroll unit handling
- Handle display changes in GtkIMMultiContext
- Always populate GDK_AXIS_X/Y in event history
- Don't crash for large compose tables
* Accessibility:
- Fix a crash at start when orca is running
* Theme:
- Refresh icons
- Fix selection in vertical spin buttons
- Fix selection in editable labels
* gdk:
- Optimize pixel format conversions
- Use EGL_KHR_swap_buffers_with_damage for NVidia
* gsk:
- Handle large viewports
- Prepare texture libraries for glyphy rendering
- Don't leak big glyphs in the glyph cache
- Align offscreen rendering with th pixel grid
- Check for half-float support before using it
* Wayland:
- Use xdg-activation protocol
- Fix text caret coordinates
- Fix on-screen keyboard activation
* MacOS:
- Fix sluggish and reversed scrolling
- Improve monitor detection
- Event handling fixes
- Fix keyboard input on popovers
- Support OpenGL-based video playback
- Suport fullscreen
- Improve native filechoooser size allocation
- Use CALayer and IOSurface for rendering
- Use a per-monitor CVDisplayLink
- Fix kinetic scrolling
- Improve window placement
- Improve multi-monitor handling
- Start applications in the foreground
- Fix cursor blink time
* Windows:
- Fix preedit window placement on HiDPI
* Tools:
- gtk4-builder-tool: Don't require a display for all commands
- gtk4-builder-tool: Add a screenshot command
- gtk4-node-editor: Install this utility
* Debugging:
- inspector: Show more application data
- inspector: Allow viewing PangoAttrList properties
* Documentation:
- Use the gtk-builder-tool to generate screenshots
* Build:
- Fix cross-compilation
- Fix build on aarch64
- Fix build with gcc 12
* Translation updates
Basque
Brazilian Portuguese
British English
Catalan
Chinese (China)
Chinese (Taiwan)
Croatian
Czech
Danish
Finnish
Galician
Georgian
German
Hebrew
Hungarian
Indonesian
Italian
Kazakh
Korean
Latvian
Lithuanian
Norwegian Bokmål
Persian
Polish
Portuguese
Russian
Serbian
Slovak
Slovenian
Spanish
Swedish
Turkish
Ukrainian
Overview of Changes in 4.6.1, 11-02-2022
========================================
-303
View File
@@ -1,303 +0,0 @@
#include "fontcolors.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
#include "rangeedit.h"
enum {
PROP_FONT_MAP = 1,
PROP_FONT_DESC,
PROP_PALETTE,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _FontColors
{
GtkWidget parent;
GtkGrid *label;
GtkGrid *grid;
Pango2FontDescription *font_desc;
GSimpleAction *reset_action;
gboolean has_colors;
char *palette;
GtkCheckButton *default_check;
Pango2FontMap *font_map;
};
struct _FontColorsClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (FontColors, font_colors, GTK_TYPE_WIDGET);
static Pango2Font *
get_font (FontColors *self)
{
Pango2Context *context;
Pango2Font *font;
context = pango2_context_new_with_font_map (self->font_map);
font = pango2_context_load_font (context, self->font_desc);
g_object_unref (context);
return font;
}
static void
palette_changed (GtkCheckButton *button,
FontColors *self)
{
g_free (self->palette);
self->palette = g_strdup ((const char *) g_object_get_data (G_OBJECT (button), "palette"));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PALETTE]);
}
static void
update_colors (FontColors *self)
{
Pango2Font *font;
hb_font_t *hb_font;
hb_face_t *hb_face;
GtkWidget *child;
GtkWidget *check;
unsigned int n_colors;
hb_color_t *colors;
GtkWidget *box;
g_object_ref (self->label);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->grid))))
gtk_grid_remove (self->grid, child);
gtk_grid_attach (self->grid, GTK_WIDGET (self->label), 0, -4, 2, 1);
g_object_unref (self->label);
self->default_check = NULL;
font = get_font (self);
hb_font = pango2_font_get_hb_font (font);
hb_face = hb_font_get_face (hb_font);
self->has_colors = hb_ot_color_has_palettes (hb_face);
gtk_widget_set_visible (GTK_WIDGET (self), self->has_colors);
if (!self->has_colors)
{
g_simple_action_set_enabled (self->reset_action, FALSE);
return;
}
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
gtk_grid_attach (self->grid, box, 0, -3, 2, 1);
check = gtk_check_button_new_with_label ("Default");
g_object_set_data (G_OBJECT (check), "palette", (gpointer)"default");
if (g_strcmp0 ("default", self->palette) == 0)
gtk_check_button_set_active (GTK_CHECK_BUTTON (check), TRUE);
g_signal_connect (check, "toggled", G_CALLBACK (palette_changed), self);
gtk_box_append (GTK_BOX (box), check);
self->default_check = GTK_CHECK_BUTTON (check);
check = gtk_check_button_new_with_label ("Light");
g_object_set_data (G_OBJECT (check), "palette", (gpointer)"light");
if (g_strcmp0 ("light", self->palette) == 0)
gtk_check_button_set_active (GTK_CHECK_BUTTON (check), TRUE);
g_signal_connect (check, "toggled", G_CALLBACK (palette_changed), self);
gtk_check_button_set_group (GTK_CHECK_BUTTON (check), self->default_check);
gtk_box_append (GTK_BOX (box), check);
check = gtk_check_button_new_with_label ("Dark");
g_object_set_data (G_OBJECT (check), "palette", (gpointer)"dark");
if (g_strcmp0 ("dark", self->palette) == 0)
gtk_check_button_set_active (GTK_CHECK_BUTTON (check), TRUE);
g_signal_connect (check, "toggled", G_CALLBACK (palette_changed), self);
gtk_check_button_set_group (GTK_CHECK_BUTTON (check), self->default_check);
gtk_box_append (GTK_BOX (box), check);
for (int i = 0; i < hb_ot_color_palette_get_count (hb_face); i++)
{
char *id = g_strdup_printf ("palette%d", i);
char *label = g_strdup_printf ("Palette %d", i);
GtkWidget *palette;
check = gtk_check_button_new_with_label (label);
g_object_set_data_full (G_OBJECT (check), "palette", id, g_free);
if (g_strcmp0 (id, self->palette) == 0)
gtk_check_button_set_active (GTK_CHECK_BUTTON (check), TRUE);
g_signal_connect (check, "toggled", G_CALLBACK (palette_changed), self);
gtk_check_button_set_group (GTK_CHECK_BUTTON (check), self->default_check);
gtk_grid_attach (self->grid, check, 0, i, 1, 1);
n_colors = hb_ot_color_palette_get_colors (hb_face, i, 0, NULL, NULL);
colors = g_new (hb_color_t, n_colors);
n_colors = hb_ot_color_palette_get_colors (hb_face, i, 0, &n_colors, colors);
palette = gtk_grid_new ();
gtk_widget_set_valign (palette, GTK_ALIGN_CENTER);
gtk_grid_attach (self->grid, palette, 1, i, 1, 1);
/* HACK - defeat first-child/last-child theming */
gtk_grid_attach (GTK_GRID (palette), gtk_picture_new (), -1, 0, 1, 1);
for (int k = 0; k < n_colors; k++)
{
GtkWidget *swatch;
swatch = g_object_new (g_type_from_name ("GtkColorSwatch"),
"rgba", &(GdkRGBA){ hb_color_get_red (colors[k])/255.,
hb_color_get_green (colors[k])/255.,
hb_color_get_blue (colors[k])/255.,
hb_color_get_alpha (colors[k])/255.},
"selectable", FALSE,
"has-menu", FALSE,
"can-drag", FALSE,
"width-request", 16,
"height-request", 16,
NULL);
gtk_grid_attach (GTK_GRID (palette), swatch, k % 6, k / 6, 1, 1);
}
/* HACK - defeat first-child/last-child theming */
gtk_grid_attach (GTK_GRID (palette), gtk_picture_new (), 6, 0, 1, 1);
}
}
static void
reset (GSimpleAction *action,
GVariant *parameter,
FontColors *self)
{
g_free (self->palette);
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
if (self->has_colors)
gtk_check_button_set_active (self->default_check, TRUE);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PALETTE]);
g_simple_action_set_enabled (self->reset_action, FALSE);
}
static void
font_colors_init (FontColors *self)
{
self->font_map = g_object_ref (pango2_font_map_get_default ());
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
gtk_widget_init_template (GTK_WIDGET (self));
self->reset_action = g_simple_action_new ("reset", NULL);
g_simple_action_set_enabled (self->reset_action, FALSE);
g_signal_connect (self->reset_action, "activate", G_CALLBACK (reset), self);
}
static void
font_colors_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), FONT_COLORS_TYPE);
G_OBJECT_CLASS (font_colors_parent_class)->dispose (object);
}
static void
font_colors_finalize (GObject *object)
{
FontColors *self = FONT_COLORS (object);
g_clear_pointer (&self->font_desc, pango2_font_description_free);
g_free (self->palette);
g_clear_object (&self->font_map);
G_OBJECT_CLASS (font_colors_parent_class)->finalize (object);
}
static void
font_colors_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
FontColors *self = FONT_COLORS (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_set_object (&self->font_map, g_value_get_object (value));
break;
case PROP_FONT_DESC:
pango2_font_description_free (self->font_desc);
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
update_colors (self);
}
static void
font_colors_get_property (GObject *object,
unsigned int prop_id,
GValue *value,
GParamSpec *pspec)
{
FontColors *self = FONT_COLORS (object);
switch (prop_id)
{
case PROP_PALETTE:
g_value_set_string (value, self->palette);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_colors_class_init (FontColorsClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = font_colors_dispose;
object_class->finalize = font_colors_finalize;
object_class->get_property = font_colors_get_property;
object_class->set_property = font_colors_set_property;
properties[PROP_FONT_MAP] =
g_param_spec_object ("font-map", "", "",
PANGO2_TYPE_FONT_MAP,
G_PARAM_READWRITE);
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", "", "",
PANGO2_TYPE_FONT_DESCRIPTION,
G_PARAM_WRITABLE);
properties[PROP_PALETTE] =
g_param_spec_string ("palette", "", "",
PANGO2_COLOR_PALETTE_DEFAULT,
G_PARAM_READABLE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/fontcolors.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontColors, grid);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontColors, label);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontcolors");
}
GAction *
font_colors_get_reset_action (FontColors *self)
{
return G_ACTION (self->reset_action);
}
-15
View File
@@ -1,15 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define FONT_COLORS_TYPE (font_colors_get_type ())
#define FONT_COLORS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_COLORS_TYPE, FontColors))
typedef struct _FontColors FontColors;
typedef struct _FontColorsClass FontColorsClass;
GType font_colors_get_type (void);
GAction * font_colors_get_reset_action (FontColors *self);
-25
View File
@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="FontColors" parent="GtkWidget">
<property name="layout-manager"><object class="GtkBinLayout"/></property>
<child>
<object class="GtkGrid" id="grid">
<child>
<object class="GtkLabel" id="label">
<property name="label" translatable="yes">Colors</property>
<property name="margin-bottom">10</property>
<property name="xalign">0</property>
<style>
<class name="heading"/>
</style>
<layout>
<property name="row">-2</property>
<property name="column">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>
-257
View File
@@ -1,257 +0,0 @@
#include "fontcontrols.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
#include "rangeedit.h"
enum {
PROP_SIZE = 1,
PROP_LETTERSPACING,
PROP_LINE_HEIGHT,
PROP_FOREGROUND,
PROP_BACKGROUND,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _FontControls
{
GtkWidget parent;
GtkAdjustment *size_adjustment;
GtkAdjustment *letterspacing_adjustment;
GtkAdjustment *line_height_adjustment;
GtkColorButton *foreground;
GtkColorButton *background;
GSimpleAction *reset_action;
};
struct _FontControlsClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(FontControls, font_controls, GTK_TYPE_WIDGET);
static void
size_changed (GtkAdjustment *adjustment,
FontControls *self)
{
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SIZE]);
g_simple_action_set_enabled (self->reset_action, TRUE);
}
static void
letterspacing_changed (GtkAdjustment *adjustment,
FontControls *self)
{
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LETTERSPACING]);
g_simple_action_set_enabled (self->reset_action, TRUE);
}
static void
line_height_changed (GtkAdjustment *adjustment,
FontControls *self)
{
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LINE_HEIGHT]);
g_simple_action_set_enabled (self->reset_action, TRUE);
}
static void
color_set (GtkColorButton *button,
GParamSpec *pspec,
FontControls *self)
{
if (button == self->foreground)
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FOREGROUND]);
else
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BACKGROUND]);
g_simple_action_set_enabled (self->reset_action, TRUE);
}
static void
swap_colors (GtkButton *button,
FontControls *self)
{
GdkRGBA fg;
GdkRGBA bg;
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (self->foreground), &fg);
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (self->background), &bg);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (self->foreground), &bg);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (self->background), &fg);
}
static void
reset (GSimpleAction *action,
GVariant *parameter,
FontControls *self)
{
gtk_adjustment_set_value (self->size_adjustment, 12.);
gtk_adjustment_set_value (self->letterspacing_adjustment, 0.);
gtk_adjustment_set_value (self->line_height_adjustment, 1.);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (self->foreground), &(GdkRGBA){0., 0., 0., 1.0 });
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (self->background), &(GdkRGBA){1., 1., 1., 1.0 });
g_simple_action_set_enabled (self->reset_action, FALSE);
}
static void
font_controls_init (FontControls *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
self->reset_action = g_simple_action_new ("reset", NULL);
g_simple_action_set_enabled (self->reset_action, FALSE);
g_signal_connect (self->reset_action, "activate", G_CALLBACK (reset), self);
}
static void
font_controls_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), FONT_CONTROLS_TYPE);
G_OBJECT_CLASS (font_controls_parent_class)->dispose (object);
}
static void
font_controls_finalize (GObject *object)
{
//FontControls *self = FONT_CONTROLS (object);
G_OBJECT_CLASS (font_controls_parent_class)->finalize (object);
}
static void
font_controls_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
FontControls *self = FONT_CONTROLS (object);
switch (prop_id)
{
case PROP_SIZE:
gtk_adjustment_set_value (self->size_adjustment, g_value_get_float (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_controls_get_property (GObject *object,
unsigned int prop_id,
GValue *value,
GParamSpec *pspec)
{
FontControls *self = FONT_CONTROLS (object);
switch (prop_id)
{
case PROP_SIZE:
g_value_set_float (value, gtk_adjustment_get_value (self->size_adjustment));
break;
case PROP_LETTERSPACING:
g_value_set_int (value, (int) gtk_adjustment_get_value (self->letterspacing_adjustment));
break;
case PROP_LINE_HEIGHT:
g_value_set_float (value, gtk_adjustment_get_value (self->line_height_adjustment));
break;
case PROP_FOREGROUND:
{
GdkRGBA rgba;
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (self->foreground), &rgba);
g_value_set_boxed (value, &rgba);
}
break;
case PROP_BACKGROUND:
{
GdkRGBA rgba;
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (self->background), &rgba);
g_value_set_boxed (value, &rgba);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_controls_class_init (FontControlsClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
g_type_ensure (RANGE_EDIT_TYPE);
object_class->dispose = font_controls_dispose;
object_class->finalize = font_controls_finalize;
object_class->get_property = font_controls_get_property;
object_class->set_property = font_controls_set_property;
properties[PROP_SIZE] =
g_param_spec_float ("size", "", "",
0., 100., 12.,
G_PARAM_READABLE);
properties[PROP_LETTERSPACING] =
g_param_spec_int ("letterspacing", "", "",
-G_MAXINT, G_MAXINT, 0,
G_PARAM_READABLE);
properties[PROP_LINE_HEIGHT] =
g_param_spec_float ("line-height", "", "",
0., 100., 1.,
G_PARAM_READABLE);
properties[PROP_FOREGROUND] =
g_param_spec_boxed ("foreground", "", "",
GDK_TYPE_RGBA,
G_PARAM_READABLE);
properties[PROP_BACKGROUND] =
g_param_spec_boxed ("background", "", "",
GDK_TYPE_RGBA,
G_PARAM_READABLE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/fontcontrols.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, size_adjustment);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, letterspacing_adjustment);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, line_height_adjustment);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, foreground);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, background);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), size_changed);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), letterspacing_changed);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), line_height_changed);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), color_set);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), swap_colors);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontcontrols");
}
FontControls *
font_controls_new (void)
{
return g_object_new (FONT_CONTROLS_TYPE, NULL);
}
GAction *
font_controls_get_reset_action (FontControls *self)
{
return G_ACTION (self->reset_action);
}
-16
View File
@@ -1,16 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define FONT_CONTROLS_TYPE (font_controls_get_type ())
#define FONT_CONTROLS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_CONTROLS_TYPE, FontControls))
typedef struct _FontControls FontControls;
typedef struct _FontControlsClass FontControlsClass;
GType font_controls_get_type (void);
FontControls * font_controls_new (void);
GAction * font_controls_get_reset_action (FontControls *self);
-173
View File
@@ -1,173 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="FontControls" parent="GtkWidget">
<property name="layout-manager"><object class="GtkGridLayout"/></property>
<child>
<object class="GtkLabel">
<property name="label">Size</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="RangeEdit">
<property name="hexpand">1</property>
<property name="width-request">160</property>
<property name="valign">baseline</property>
<property name="adjustment">
<object class="GtkAdjustment" id="size_adjustment">
<property name="lower">7</property>
<property name="upper">100</property>
<property name="value">14</property>
<property name="step_increment">0.5</property>
<property name="page_increment">10</property>
<signal name="value-changed" handler="size_changed"/>
</object>
</property>
<property name="default-value">12</property>
<property name="n-chars">5</property>
<layout>
<property name="column">1</property>
<property name="row">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Letterspacing</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="RangeEdit">
<property name="hexpand">1</property>
<property name="width-request">160</property>
<property name="valign">baseline</property>
<property name="adjustment">
<object class="GtkAdjustment" id="letterspacing_adjustment">
<property name="lower">-1024</property>
<property name="upper">8192</property>
<property name="value">0</property>
<property name="step_increment">1</property>
<property name="page_increment">512</property>
<signal name="value-changed" handler="letterspacing_changed"/>
</object>
</property>
<property name="default-value">0</property>
<property name="n-chars">5</property>
<layout>
<property name="column">1</property>
<property name="row">1</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Line Height</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="RangeEdit">
<property name="hexpand">1</property>
<property name="width-request">160</property>
<property name="valign">baseline</property>
<property name="adjustment">
<object class="GtkAdjustment" id="line_height_adjustment">
<property name="lower">0.75</property>
<property name="upper">2.5</property>
<property name="value">1.0</property>
<property name="step_increment">0.1</property>
<property name="page_increment">1</property>
<signal name="value-changed" handler="line_height_changed"/>
</object>
</property>
<property name="default-value">1</property>
<property name="n-chars">5</property>
<layout>
<property name="column">1</property>
<property name="row">2</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Foreground</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkColorButton" id="foreground">
<property name="rgba">black</property>
<signal name="notify::rgba" handler="color_set"/>
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Background</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkColorButton" id="background">
<property name="rgba">white</property>
<signal name="notify::rgba" handler="color_set"/>
<layout>
<property name="column">1</property>
<property name="row">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton">
<property name="icon-name">object-flip-vertical-symbolic</property>
<property name="halign">start</property>
<property name="valign">center</property>
<style>
<class name="circular"/>
</style>
<signal name="clicked" handler="swap_colors"/>
<layout>
<property name="column">2</property>
<property name="row">3</property>
<property name="row-span">2</property>
</layout>
</object>
</child>
</template>
</interface>
-43
View File
@@ -1,43 +0,0 @@
box.sidebar {
padding: 20px;
border-spacing: 20px;
}
fontcontrols {
border-spacing: 10px;
}
fontvariations > grid {
border-spacing: 10px;
}
fontcolors > grid {
border-spacing: 10px;
}
samplechooser {
border-spacing: 10px;
}
plainview .content {
padding: 20px;
}
waterfallview .content {
padding: 20px;
}
styleview .content {
padding: 20px;
}
glyphsview .content {
padding: 20px;
}
infoview .content {
padding: 20px;
border-spacing: 10px;
}
gridview > child {
padding: 0;
}
glyphview {
padding: 0;
border: 0.6px solid gray;
}
.viewcontrols {
padding: 20px;
border-spacing: 10px;
}
@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gtk/fontexplorer">
<file preprocess="xml-stripblanks">fontcolors.ui</file>
<file preprocess="xml-stripblanks">fontcontrols.ui</file>
<file preprocess="xml-stripblanks">fontexplorerwin.ui</file>
<file preprocess="xml-stripblanks">fontfeatures.ui</file>
<file preprocess="xml-stripblanks">fontvariations.ui</file>
<file preprocess="xml-stripblanks">glyphsview.ui</file>
<file preprocess="xml-stripblanks">infoview.ui</file>
<file preprocess="xml-stripblanks">plainview.ui</file>
<file preprocess="xml-stripblanks">rangeedit.ui</file>
<file preprocess="xml-stripblanks">samplechooser.ui</file>
<file preprocess="xml-stripblanks">sampleeditor.ui</file>
<file preprocess="xml-stripblanks">styleview.ui</file>
<file preprocess="xml-stripblanks">waterfallview.ui</file>
<file>fontexplorer.css</file>
</gresource>
</gresources>
-186
View File
@@ -1,186 +0,0 @@
#include "config.h"
#include "fontexplorerapp.h"
#include <gtk/gtk.h>
#include "fontexplorerwin.h"
#include "demo_conf.h"
struct _FontExplorerApp
{
GtkApplication parent;
};
struct _FontExplorerAppClass
{
GtkApplicationClass parent_class;
};
G_DEFINE_TYPE(FontExplorerApp, font_explorer_app, GTK_TYPE_APPLICATION);
static void
font_explorer_app_init (FontExplorerApp *app)
{
}
static void
quit_activated (GSimpleAction *action,
GVariant *parameter,
gpointer app)
{
g_application_quit (G_APPLICATION (app));
}
static void
inspector_activated (GSimpleAction *action,
GVariant *parameter,
gpointer app)
{
gtk_window_set_interactive_debugging (TRUE);
}
static void
about_activated (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkApplication *app = user_data;
const char *authors[] = {
"The GTK Team",
NULL
};
char *icon_theme;
char *version;
GString *s;
char *os_name;
char *os_version;
g_object_get (gtk_settings_get_default (),
"gtk-icon-theme-name", &icon_theme,
NULL);
s = g_string_new ("");
os_name = g_get_os_info (G_OS_INFO_KEY_NAME);
os_version = g_get_os_info (G_OS_INFO_KEY_VERSION_ID);
if (os_name && os_version)
g_string_append_printf (s, "OS\t%s %s\n\n", os_name, os_version);
g_string_append (s, "System libraries\n");
g_string_append_printf (s, "\tGLib\t%d.%d.%d\n",
glib_major_version,
glib_minor_version,
glib_micro_version);
g_string_append_printf (s, "\tPango2\t%s\n",
pango2_version_string ());
g_string_append_printf (s, "\tGTK \t%d.%d.%d\n",
gtk_get_major_version (),
gtk_get_minor_version (),
gtk_get_micro_version ());
g_string_append_printf (s, "\nIcon theme\n\t%s", icon_theme);
version = g_strdup_printf ("%s%s%s\nRunning against GTK %d.%d.%d",
PACKAGE_VERSION,
g_strcmp0 (PROFILE, "devel") == 0 ? "-" : "",
g_strcmp0 (PROFILE, "devel") == 0 ? VCS_TAG : "",
gtk_get_major_version (),
gtk_get_minor_version (),
gtk_get_micro_version ());
gtk_show_about_dialog (GTK_WINDOW (gtk_application_get_active_window (app)),
"program-name", g_strcmp0 (PROFILE, "devel") == 0
? "GTK Font Explorer (Development)"
: "GTK Font Explorer",
"version", version,
"copyright", "© 1997—2021 The GTK Team",
"license-type", GTK_LICENSE_LGPL_2_1,
"website", "http://www.gtk.org",
"comments", "Program to explore font features",
"authors", authors,
"logo-icon-name", "org.gtk.FontExplorer",
"title", "About GTK Font Explorer",
"system-information", s->str,
NULL);
g_string_free (s, TRUE);
g_free (version);
g_free (icon_theme);
g_free (os_name);
g_free (os_version);
}
static GActionEntry app_entries[] =
{
{ "quit", quit_activated, NULL, NULL, NULL },
{ "inspector", inspector_activated, NULL, NULL, NULL },
{ "about", about_activated, NULL, NULL, NULL }
};
static void
font_explorer_app_startup (GApplication *app)
{
const char *quit_accels[2] = { "<Ctrl>Q", NULL };
GtkCssProvider *provider;
G_APPLICATION_CLASS (font_explorer_app_parent_class)->startup (app);
g_action_map_add_action_entries (G_ACTION_MAP (app),
app_entries, G_N_ELEMENTS (app_entries),
app);
gtk_application_set_accels_for_action (GTK_APPLICATION (app),
"app.quit",
quit_accels);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/org/gtk/fontexplorer/fontexplorer.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
static void
font_explorer_app_activate (GApplication *app)
{
FontExplorerWindow *win;
win = font_explorer_window_new (FONT_EXPLORER_APP (app));
if (g_strcmp0 (PROFILE, "devel") == 0)
gtk_widget_add_css_class (GTK_WIDGET (win), "devel");
gtk_window_present (GTK_WINDOW (win));
}
static void
font_explorer_app_open (GApplication *app,
GFile **files,
int n_files,
const char *hint)
{
FontExplorerWindow *win;
int i;
for (i = 0; i < n_files; i++)
{
win = font_explorer_window_new (FONT_EXPLORER_APP (app));
font_explorer_window_load (win, files[i]);
gtk_window_present (GTK_WINDOW (win));
}
}
static void
font_explorer_app_class_init (FontExplorerAppClass *class)
{
G_APPLICATION_CLASS (class)->startup = font_explorer_app_startup;
G_APPLICATION_CLASS (class)->activate = font_explorer_app_activate;
G_APPLICATION_CLASS (class)->open = font_explorer_app_open;
}
FontExplorerApp *
font_explorer_app_new (void)
{
return g_object_new (FONT_EXPLORER_APP_TYPE,
"application-id", "org.gtk.FontExplorer",
"flags", G_APPLICATION_HANDLES_OPEN,
NULL);
}
-15
View File
@@ -1,15 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define FONT_EXPLORER_APP_TYPE (font_explorer_app_get_type ())
#define FONT_EXPLORER_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_EXPLORER_APP_TYPE, FontExplorerApp))
typedef struct _FontExplorerApp FontExplorerApp;
typedef struct _FontExplorerAppClass FontExplorerAppClass;
GType font_explorer_app_get_type (void);
FontExplorerApp * font_explorer_app_new (void);
-269
View File
@@ -1,269 +0,0 @@
#include "fontexplorerwin.h"
#include <gtk/gtk.h>
#include <string.h>
#include "fontcolors.h"
#include "fontcontrols.h"
#include "fontexplorerapp.h"
#include "fontfeatures.h"
#include "fontvariations.h"
#include "glyphsview.h"
#include "infoview.h"
#include "plainview.h"
#include "samplechooser.h"
#include "sampleeditor.h"
#include "styleview.h"
#include "waterfallview.h"
struct _FontExplorerWindow
{
GtkApplicationWindow parent;
Pango2FontMap *font_map;
GtkFontButton *fontbutton;
GtkLabel *path;
FontControls *controls;
FontFeatures *features;
FontVariations *variations;
FontColors *colors;
GtkStack *stack;
GtkToggleButton *plain_toggle;
GtkToggleButton *waterfall_toggle;
GtkToggleButton *style_toggle;
GtkToggleButton *glyphs_toggle;
GtkToggleButton *info_toggle;
GtkToggleButton *edit_toggle;
};
struct _FontExplorerWindowClass
{
GtkApplicationWindowClass parent_class;
};
enum {
PROP_FONT_MAP = 1,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
G_DEFINE_TYPE(FontExplorerWindow, font_explorer_window, GTK_TYPE_APPLICATION_WINDOW);
static void
reset (GSimpleAction *action,
GVariant *parameter,
FontExplorerWindow *self)
{
g_action_activate (font_controls_get_reset_action (self->controls), NULL);
g_action_activate (font_features_get_reset_action (self->features), NULL);
g_action_activate (font_variations_get_reset_action (self->variations), NULL);
g_action_activate (font_colors_get_reset_action (self->colors), NULL);
}
static void
update_reset (GSimpleAction *action,
GParamSpec *pspec,
FontExplorerWindow *self)
{
gboolean enabled;
GAction *reset_action;
enabled = g_action_get_enabled (font_controls_get_reset_action (self->controls)) ||
g_action_get_enabled (font_features_get_reset_action (self->features)) ||
g_action_get_enabled (font_variations_get_reset_action (self->variations)) ||
g_action_get_enabled (font_colors_get_reset_action (self->colors));
reset_action = g_action_map_lookup_action (G_ACTION_MAP (self), "reset");
g_simple_action_set_enabled (G_SIMPLE_ACTION (reset_action), enabled);
}
static void
font_explorer_window_init (FontExplorerWindow *self)
{
GSimpleAction *reset_action;
self->font_map = g_object_ref (pango2_font_map_get_default ());
gtk_widget_init_template (GTK_WIDGET (self));
reset_action = g_simple_action_new ("reset", NULL);
g_signal_connect (reset_action, "activate", G_CALLBACK (reset), self);
g_signal_connect (font_controls_get_reset_action (self->controls),
"notify::enabled", G_CALLBACK (update_reset), self);
g_signal_connect (font_variations_get_reset_action (self->variations),
"notify::enabled", G_CALLBACK (update_reset), self);
g_signal_connect (font_colors_get_reset_action (self->colors),
"notify::enabled", G_CALLBACK (update_reset), self);
g_signal_connect (font_features_get_reset_action (self->features),
"notify::enabled", G_CALLBACK (update_reset), self);
g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (reset_action));
update_reset (NULL, NULL, self);
}
static void
update_view (GtkToggleButton *button,
FontExplorerWindow *self)
{
if (gtk_toggle_button_get_active (self->edit_toggle))
gtk_stack_set_visible_child_name (self->stack, "edit");
else if (gtk_toggle_button_get_active (self->plain_toggle))
gtk_stack_set_visible_child_name (self->stack, "plain");
else if (gtk_toggle_button_get_active (self->waterfall_toggle))
gtk_stack_set_visible_child_name (self->stack, "waterfall");
else if (gtk_toggle_button_get_active (self->style_toggle))
gtk_stack_set_visible_child_name (self->stack, "style");
else if (gtk_toggle_button_get_active (self->glyphs_toggle))
gtk_stack_set_visible_child_name (self->stack, "glyphs");
else if (gtk_toggle_button_get_active (self->info_toggle))
gtk_stack_set_visible_child_name (self->stack, "info");
}
static void
font_explorer_window_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
FontExplorerWindow *self = FONT_EXPLORER_WINDOW (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_set_object (&self->font_map, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_explorer_window_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
FontExplorerWindow *self = FONT_EXPLORER_WINDOW (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_value_set_object (value, self->font_map);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_explorer_window_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), FONT_EXPLORER_WINDOW_TYPE);
G_OBJECT_CLASS (font_explorer_window_parent_class)->dispose (object);
}
static void
font_explorer_window_finalize (GObject *object)
{
FontExplorerWindow *self = FONT_EXPLORER_WINDOW (object);
g_clear_object (&self->font_map);
G_OBJECT_CLASS (font_explorer_window_parent_class)->finalize (object);
}
static void
font_explorer_window_class_init (FontExplorerWindowClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
g_type_ensure (FONT_COLORS_TYPE);
g_type_ensure (FONT_CONTROLS_TYPE);
g_type_ensure (FONT_FEATURES_TYPE);
g_type_ensure (FONT_VARIATIONS_TYPE);
g_type_ensure (GLYPHS_VIEW_TYPE);
g_type_ensure (INFO_VIEW_TYPE);
g_type_ensure (PLAIN_VIEW_TYPE);
g_type_ensure (SAMPLE_CHOOSER_TYPE);
g_type_ensure (SAMPLE_EDITOR_TYPE);
g_type_ensure (STYLE_VIEW_TYPE);
g_type_ensure (WATERFALL_VIEW_TYPE);
object_class->set_property = font_explorer_window_set_property;
object_class->get_property = font_explorer_window_get_property;
object_class->dispose = font_explorer_window_dispose;
object_class->finalize = font_explorer_window_finalize;
properties[PROP_FONT_MAP] =
g_param_spec_object ("font-map", "", "",
PANGO2_TYPE_FONT_MAP,
G_PARAM_READWRITE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/fontexplorerwin.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, fontbutton);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, path);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, controls);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, variations);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, colors);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, features);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, stack);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, plain_toggle);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, waterfall_toggle);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, style_toggle);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, glyphs_toggle);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, info_toggle);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, edit_toggle);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), update_view);
}
FontExplorerWindow *
font_explorer_window_new (FontExplorerApp *app)
{
return g_object_new (FONT_EXPLORER_WINDOW_TYPE, "application", app, NULL);
}
void
font_explorer_window_load (FontExplorerWindow *self,
GFile *file)
{
const char *path;
Pango2FontMap *map;
Pango2HbFace *face;
Pango2FontDescription *desc;
char *basename;
path = g_file_peek_path (file);
basename = g_path_get_basename (path);
face = pango2_hb_face_new_from_file (path, 0, -2, NULL, NULL);
desc = pango2_font_face_describe (PANGO2_FONT_FACE (face));
map = pango2_font_map_new ();
pango2_font_map_add_face (map, PANGO2_FONT_FACE (face));
pango2_font_map_set_fallback (map, pango2_font_map_get_default ());
g_set_object (&self->font_map, map);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FONT_MAP]);
g_object_unref (map);
gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (self->fontbutton), desc);
gtk_widget_hide (GTK_WIDGET (self->fontbutton));
gtk_widget_show (GTK_WIDGET (self->path));
gtk_label_set_label (self->path, basename);
pango2_font_description_free (desc);
g_free (basename);
}
-18
View File
@@ -1,18 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#include "fontexplorerapp.h"
#define FONT_EXPLORER_WINDOW_TYPE (font_explorer_window_get_type ())
#define FONT_EXPLORER_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_EXPLORER_WINDOW_TYPE, FontExplorerWindow))
typedef struct _FontExplorerWindow FontExplorerWindow;
typedef struct _FontExplorerWindowClass FontExplorerWindowClass;
GType font_explorer_window_get_type (void);
FontExplorerWindow * font_explorer_window_new (FontExplorerApp *app);
void font_explorer_window_load (FontExplorerWindow *self,
GFile *file);
-252
View File
@@ -1,252 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="gear_menu">
<section>
<item>
<attribute name="label" translatable="yes">_Inspector</attribute>
<attribute name="action">app.inspector</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_About GTK Font Explorer</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
</menu>
<template class="FontExplorerWindow" parent="GtkApplicationWindow">
<property name="title" translatable="yes">Font Explorer</property>
<property name="default-width">1024</property>
<property name="default-height">768</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<child>
<object class="GtkButton" id="reset">
<property name="receives-default">1</property>
<property name="tooltip-text">Reset</property>
<property name="icon-name">view-refresh-symbolic</property>
<property name="action-name">win.reset</property>
</object>
</child>
<child type="title">
<object class="GtkBox">
<property name="orientation">horizontal</property>
<style>
<class name="linked"/>
</style>
<child>
<object class="GtkToggleButton" id="plain_toggle">
<property name="label">Plain</property>
<property name="active">1</property>
<signal name="toggled" handler="update_view"/>
</object>
</child>
<child>
<object class="GtkToggleButton" id="waterfall_toggle">
<property name="label">Waterfall</property>
<property name="group">plain_toggle</property>
<signal name="toggled" handler="update_view"/>
</object>
</child>
<child>
<object class="GtkToggleButton" id="style_toggle">
<property name="label">Styles</property>
<property name="group">plain_toggle</property>
<property name="sensitive" bind-source="styleview" bind-property="has-styles" bind-flags="sync-create"/>
<signal name="toggled" handler="update_view"/>
</object>
</child>
<child>
<object class="GtkToggleButton" id="glyphs_toggle">
<property name="label">Glyphs</property>
<property name="group">plain_toggle</property>
<signal name="toggled" handler="update_view"/>
</object>
</child>
<child>
<object class="GtkToggleButton" id="info_toggle">
<property name="label">Info</property>
<property name="group">plain_toggle</property>
<signal name="toggled" handler="update_view"/>
</object>
</child>
</object>
</child>
<child type="end">
<object class="GtkMenuButton" id="gear_menu_button">
<property name="focus-on-click">0</property>
<property name="valign">center</property>
<property name="menu-model">gear_menu</property>
<property name="icon-name">open-menu-symbolic</property>
</object>
</child>
<child type="end">
<object class="GtkToggleButton" id="edit_toggle">
<property name="hexpand">1</property>
<property name="halign">end</property>
<property name="icon-name">document-edit-symbolic</property>
<property name="tooltip-text" translatable="yes">Edit the sample</property>
<signal name="toggled" handler="update_view"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<style>
<class name="sidebar"/>
</style>
<child>
<object class="GtkFontButton" id="fontbutton">
<property name="level">family|style</property>
</object>
</child>
<child>
<object class="GtkLabel" id="path">
<property name="visible">0</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="FontControls" id="controls">
</object>
</child>
<child>
<object class="SampleChooser" id="samplechooser"/>
</child>
<child>
<object class="FontVariations" id="variations">
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
</object>
</child>
<child>
<object class="FontFeatures" id="features">
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
<property name="language" bind-source="fontbutton" bind-flags="sync-create"/>
</object>
</child>
<child>
<object class="FontColors" id="colors">
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="hexpand">1</property>
<child>
<object class="GtkStackPage">
<property name="name">plain</property>
<property name="child">
<object class="PlainView">
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
<property name="size" bind-source="controls" bind-flags="sync-create"/>
<property name="letterspacing" bind-source="controls" bind-flags="sync-create"/>
<property name="line-height" bind-source="controls" bind-flags="sync-create"/>
<property name="foreground" bind-source="controls" bind-flags="sync-create"/>
<property name="background" bind-source="controls" bind-flags="sync-create"/>
<property name="sample-text" bind-source="sampleeditor" bind-flags="sync-create"/>
<property name="features" bind-source="features" bind-flags="sync-create"/>
<property name="variations" bind-source="variations" bind-flags="sync-create"/>
<property name="palette" bind-source="colors" bind-flags="sync-create"/>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">waterfall</property>
<property name="child">
<object class="WaterfallView">
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
<property name="size" bind-source="controls" bind-flags="sync-create"/>
<property name="letterspacing" bind-source="controls" bind-flags="sync-create"/>
<property name="line-height" bind-source="controls" bind-flags="sync-create"/>
<property name="foreground" bind-source="controls" bind-flags="sync-create"/>
<property name="background" bind-source="controls" bind-flags="sync-create"/>
<property name="sample-text" bind-source="sampleeditor" bind-flags="sync-create"/>
<property name="features" bind-source="features" bind-flags="sync-create"/>
<property name="variations" bind-source="variations" bind-flags="sync-create"/>
<property name="palette" bind-source="colors" bind-flags="sync-create"/>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">style</property>
<property name="child">
<object class="StyleView" id="styleview">
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
<property name="size" bind-source="controls" bind-flags="sync-create"/>
<property name="letterspacing" bind-source="controls" bind-flags="sync-create"/>
<property name="line-height" bind-source="controls" bind-flags="sync-create"/>
<property name="foreground" bind-source="controls" bind-flags="sync-create"/>
<property name="background" bind-source="controls" bind-flags="sync-create"/>
<property name="sample-text" bind-source="sampleeditor" bind-flags="sync-create"/>
<property name="features" bind-source="features" bind-flags="sync-create"/>
<property name="variations" bind-source="variations" bind-flags="sync-create"/>
<property name="palette" bind-source="colors" bind-flags="sync-create"/>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">glyphs</property>
<property name="child">
<object class="GlyphsView">
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
<property name="variations" bind-source="variations" bind-flags="sync-create"/>
<property name="palette" bind-source="colors" bind-flags="sync-create"/>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">info</property>
<property name="child">
<object class="InfoView">
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
<property name="size" bind-source="controls" bind-flags="sync-create"/>
<property name="variations" bind-source="variations" bind-flags="sync-create"/>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">edit</property>
<property name="child">
<object class="SampleEditor" id="sampleeditor">
<property name="sample-text" bind-source="samplechooser" bind-flags="sync-create"/>
<property name="editing" bind-source="edit_toggle" bind-property="active" bind-flags="sync-create"/>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>
-744
View File
@@ -1,744 +0,0 @@
#include "fontfeatures.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
#include <glib/gi18n.h>
#include "open-type-layout.h"
#include "language-names.h"
enum {
PROP_FONT_MAP = 1,
PROP_FONT_DESC,
PROP_LANGUAGE,
PROP_FEATURES,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
typedef struct {
unsigned int tag;
const char *name;
GtkWidget *feat;
} FeatureItem;
struct _FontFeatures
{
GtkWidget parent;
GtkGrid *label;
GtkGrid *grid;
Pango2FontDescription *font_desc;
GSimpleAction *reset_action;
Pango2Language *lang;
GList *feature_items;
Pango2FontMap *font_map;
};
struct _FontFeaturesClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(FontFeatures, font_features, GTK_TYPE_WIDGET);
static Pango2Font *
get_font (FontFeatures *self)
{
Pango2Context *context;
Pango2Font *font;
context = pango2_context_new_with_font_map (self->font_map);
font = pango2_context_load_font (context, self->font_desc);
g_object_unref (context);
return font;
}
static gboolean
is_ssNN (const char *buf)
{
return g_str_has_prefix (buf, "ss") && g_ascii_isdigit (buf[2]) && g_ascii_isdigit (buf[3]);
}
static gboolean
is_cvNN (const char *buf)
{
return g_str_has_prefix (buf, "cv") && g_ascii_isdigit (buf[2]) && g_ascii_isdigit (buf[3]);
}
static char *
get_feature_display_name (unsigned int tag)
{
int i;
static char buf[5] = { 0, };
if (tag == HB_TAG ('x', 'x', 'x', 'x'))
return g_strdup (_("Default"));
hb_tag_to_string (tag, buf);
if (is_ssNN (buf))
{
int num = (buf[2] - '0') * 10 + (buf[3] - '0');
return g_strdup_printf (g_dpgettext2 (NULL, "OpenType layout", "Stylistic Set %d"), num);
}
else if (is_cvNN (buf))
{
int num = (buf[2] - '0') * 10 + (buf[3] - '0');
return g_strdup_printf (g_dpgettext2 (NULL, "OpenType layout", "Character Variant %d"), num);
}
for (i = 0; i < G_N_ELEMENTS (open_type_layout_features); i++)
{
if (tag == open_type_layout_features[i].tag)
return g_strdup (g_dpgettext2 (NULL, "OpenType layout", open_type_layout_features[i].name));
}
g_warning ("unknown OpenType layout feature tag: %s", buf);
return g_strdup (buf);
}
static void
update_feature_label (FontFeatures *self,
FeatureItem *item,
hb_font_t *hb_font,
hb_tag_t script_tag,
hb_tag_t lang_tag)
{
hb_face_t *hb_face;
unsigned int script_index, lang_index, feature_index;
hb_ot_name_id_t id;
unsigned int len;
char *label;
char name[5] = { 0, };
hb_face = hb_font_get_face (hb_font);
hb_tag_to_string (item->tag, name);
if (!is_ssNN (name) && !is_cvNN (name))
return;
hb_ot_layout_table_find_script (hb_face, HB_OT_TAG_GSUB, script_tag, &script_index);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
hb_ot_layout_script_find_language (hb_face, HB_OT_TAG_GSUB, script_index, lang_tag, &lang_index);
G_GNUC_END_IGNORE_DEPRECATIONS
if (hb_ot_layout_language_find_feature (hb_face, HB_OT_TAG_GSUB, script_index, lang_index, item->tag, &feature_index) &&
hb_ot_layout_feature_get_name_ids (hb_face, HB_OT_TAG_GSUB, feature_index, &id, NULL, NULL, NULL, NULL))
{
len = hb_ot_name_get_utf8 (hb_face, id, HB_LANGUAGE_INVALID, NULL, NULL);
len++;
label = g_new (char, len);
hb_ot_name_get_utf8 (hb_face, id, HB_LANGUAGE_INVALID, &len, label);
gtk_check_button_set_label (GTK_CHECK_BUTTON (item->feat), label);
g_free (label);
}
else
{
label = get_feature_display_name (item->tag);
gtk_check_button_set_label (GTK_CHECK_BUTTON (item->feat), label);
g_free (label);
}
}
static void
set_inconsistent (GtkCheckButton *button,
gboolean inconsistent)
{
gtk_check_button_set_inconsistent (GTK_CHECK_BUTTON (button), inconsistent);
gtk_widget_set_opacity (gtk_widget_get_first_child (GTK_WIDGET (button)), inconsistent ? 0.0 : 1.0);
}
static void
find_language_and_script (FontFeatures *self,
hb_face_t *hb_face,
hb_tag_t *lang_tag,
hb_tag_t *script_tag)
{
int i, j, k;
hb_tag_t scripts[80];
unsigned int n_scripts;
unsigned int count;
hb_tag_t table[2] = { HB_OT_TAG_GSUB, HB_OT_TAG_GPOS };
hb_language_t lang;
const char *langname, *p;
langname = pango2_language_to_string (self->lang);
p = strchr (langname, '-');
lang = hb_language_from_string (langname, p ? p - langname : -1);
n_scripts = 0;
for (i = 0; i < 2; i++)
{
count = G_N_ELEMENTS (scripts);
hb_ot_layout_table_get_script_tags (hb_face, table[i], n_scripts, &count, scripts);
n_scripts += count;
}
for (j = 0; j < n_scripts; j++)
{
hb_tag_t languages[80];
unsigned int n_languages;
n_languages = 0;
for (i = 0; i < 2; i++)
{
count = G_N_ELEMENTS (languages);
hb_ot_layout_script_get_language_tags (hb_face, table[i], j, n_languages, &count, languages);
n_languages += count;
}
for (k = 0; k < n_languages; k++)
{
if (lang == hb_ot_tag_to_language (languages[k]))
{
*script_tag = scripts[j];
*lang_tag = languages[k];
return;
}
}
}
*lang_tag = HB_OT_TAG_DEFAULT_LANGUAGE;
*script_tag = HB_OT_TAG_DEFAULT_SCRIPT;
}
static void
hide_feature_maybe (FeatureItem *item,
gboolean has_feature)
{
gtk_widget_set_visible (item->feat, has_feature);
if (has_feature)
gtk_widget_set_visible (gtk_widget_get_parent (item->feat), TRUE);
}
/* Make features insensitive if the font/langsys does not have them,
* and reset all others to their initial value
*/
static void
update_features (FontFeatures *self)
{
guint script_index, lang_index;
hb_tag_t lang_tag;
hb_tag_t script_tag;
Pango2Font *font;
hb_font_t *hb_font;
hb_face_t *hb_face;
font = get_font (self);
hb_font = pango2_font_get_hb_font (font);
hb_face = hb_font_get_face (hb_font);
{
hb_tag_t table[2] = { HB_OT_TAG_GSUB, HB_OT_TAG_GPOS };
hb_tag_t features[256];
unsigned int count;
unsigned int n_features = 0;
find_language_and_script (self, hb_face, &lang_tag, &script_tag);
/* Collect all features */
for (int i = 0; i < 2; i++)
{
hb_ot_layout_table_find_script (hb_face,
table[i],
script_tag,
&script_index);
hb_ot_layout_script_select_language (hb_face,
table[i],
script_index,
1,
&lang_tag,
&lang_index);
count = G_N_ELEMENTS (features);
hb_ot_layout_language_get_feature_tags (hb_face,
table[i],
script_index,
lang_index,
n_features,
&count,
features);
n_features += count;
}
/* Update all the features */
for (GList *l = self->feature_items; l; l = l->next)
{
FeatureItem *item = l->data;
gboolean has_feature = FALSE;
for (int j = 0; j < n_features; j++)
{
if (item->tag == features[j])
{
has_feature = TRUE;
break;
}
}
update_feature_label (self, item, hb_font, script_tag, lang_tag);
hide_feature_maybe (item, has_feature);
if (GTK_IS_CHECK_BUTTON (item->feat))
{
GtkWidget *def = GTK_WIDGET (g_object_get_data (G_OBJECT (item->feat), "default"));
if (def)
{
gtk_widget_show (def);
gtk_widget_show (gtk_widget_get_parent (def));
gtk_check_button_set_active (GTK_CHECK_BUTTON (def), TRUE);
}
else
set_inconsistent (GTK_CHECK_BUTTON (item->feat), TRUE);
}
}
}
/* Hide empty groups */
for (GList *l = self->feature_items; l; l = l->next)
{
FeatureItem *item = l->data;
GtkWidget *box;
box = gtk_widget_get_parent (item->feat);
if (gtk_widget_get_visible (box))
{
GtkWidget *c;
int count;
count = 0;
for (c = gtk_widget_get_first_child (box); c; c = gtk_widget_get_next_sibling (c))
{
if (gtk_widget_get_visible (c))
count++;
}
if (count == 1)
gtk_widget_hide (box);
else if (count == 2 &&
item->tag == HB_TAG ('x', 'x', 'x', 'x'))
gtk_widget_hide (box);
}
}
}
static void
script_changed (GtkComboBox *combo,
FontFeatures *self)
{
update_features (self);
}
static char *
get_features (FontFeatures *self)
{
GString *s;
char buf[128];
s = g_string_new ("");
for (GList *l = self->feature_items; l; l = l->next)
{
FeatureItem *item = l->data;
if (!gtk_widget_is_sensitive (item->feat))
continue;
if (GTK_IS_CHECK_BUTTON (item->feat) && g_object_get_data (G_OBJECT (item->feat), "default"))
{
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (item->feat)) &&
item->tag != HB_TAG ('x', 'x', 'x', 'x'))
{
hb_feature_to_string (&(hb_feature_t) { item->tag, 1, 0, -1 }, buf, sizeof (buf));
if (s->len > 0)
g_string_append_c (s, ',');
g_string_append (s, buf);
}
}
else if (GTK_IS_CHECK_BUTTON (item->feat))
{
guint32 value;
if (gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (item->feat)))
continue;
value = gtk_check_button_get_active (GTK_CHECK_BUTTON (item->feat));
hb_feature_to_string (&(hb_feature_t) { item->tag, value, 0, -1 }, buf, sizeof (buf));
if (s->len > 0)
g_string_append_c (s, ',');
g_string_append (s, buf);
}
}
return g_string_free (s, FALSE);
}
static void
update_display (FontFeatures *self)
{
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FEATURES]);
g_simple_action_set_enabled (self->reset_action, TRUE);
}
static GtkWidget *
make_title_label (const char *title)
{
GtkWidget *label;
label = gtk_label_new (title);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_widget_set_halign (label, GTK_ALIGN_START);
g_object_set (label, "margin-top", 10, "margin-bottom", 10, NULL);
gtk_widget_add_css_class (label, "heading");
return label;
}
static void
feat_toggled_cb (GtkCheckButton *check_button,
gpointer data)
{
set_inconsistent (check_button, FALSE);
}
static void
feat_pressed (GtkGestureClick *gesture,
int n_press,
double x,
double y,
GtkWidget *feat)
{
const guint button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
if (button == GDK_BUTTON_PRIMARY)
{
g_signal_handlers_block_by_func (feat, feat_pressed, NULL);
if (gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (feat)))
{
set_inconsistent (GTK_CHECK_BUTTON (feat), FALSE);
gtk_check_button_set_active (GTK_CHECK_BUTTON (feat), TRUE);
}
g_signal_handlers_unblock_by_func (feat, feat_pressed, NULL);
}
else if (button == GDK_BUTTON_SECONDARY)
{
gboolean inconsistent = gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (feat));
set_inconsistent (GTK_CHECK_BUTTON (feat), !inconsistent);
}
}
static void
add_check_group (FontFeatures *self,
const char *title,
const char **tags,
unsigned int n_tags,
int row)
{
GtkWidget *group;
int i;
group = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_halign (group, GTK_ALIGN_START);
gtk_box_append (GTK_BOX (group), make_title_label (title));
for (i = 0; i < n_tags; i++)
{
unsigned int tag;
GtkWidget *feat;
FeatureItem *item;
GtkGesture *gesture;
char *name;
tag = hb_tag_from_string (tags[i], -1);
name = get_feature_display_name (tag);
feat = gtk_check_button_new_with_label (name);
g_free (name);
set_inconsistent (GTK_CHECK_BUTTON (feat), TRUE);
g_signal_connect_swapped (feat, "notify::active", G_CALLBACK (update_display), self);
g_signal_connect_swapped (feat, "notify::inconsistent", G_CALLBACK (update_display), self);
g_signal_connect (feat, "toggled", G_CALLBACK (feat_toggled_cb), NULL);
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
g_signal_connect (gesture, "pressed", G_CALLBACK (feat_pressed), feat);
gtk_widget_add_controller (feat, GTK_EVENT_CONTROLLER (gesture));
gtk_box_append (GTK_BOX (group), feat);
item = g_new (FeatureItem, 1);
item->name = tags[i];
item->tag = tag;
item->feat = feat;
self->feature_items = g_list_prepend (self->feature_items, item);
}
gtk_grid_attach (self->grid, group, 0, row, 2, 1);
}
static void
add_radio_group (FontFeatures *self,
const char *title,
const char **tags,
unsigned int n_tags,
int row)
{
GtkWidget *group;
int i;
GtkWidget *group_button = NULL;
group = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_halign (group, GTK_ALIGN_START);
gtk_box_append (GTK_BOX (group), make_title_label (title));
for (i = 0; i < n_tags; i++)
{
unsigned int tag;
GtkWidget *feat;
FeatureItem *item;
char *name;
tag = hb_tag_from_string (tags[i], -1);
name = get_feature_display_name (tag);
feat = gtk_check_button_new_with_label (name ? name : _("Default"));
g_free (name);
if (group_button == NULL)
group_button = feat;
else
gtk_check_button_set_group (GTK_CHECK_BUTTON (feat), GTK_CHECK_BUTTON (group_button));
g_signal_connect_swapped (feat, "notify::active", G_CALLBACK (update_display), self);
g_object_set_data (G_OBJECT (feat), "default", group_button);
gtk_box_append (GTK_BOX (group), feat);
item = g_new (FeatureItem, 1);
item->name = tags[i];
item->tag = tag;
item->feat = feat;
self->feature_items = g_list_prepend (self->feature_items, item);
}
gtk_grid_attach (self->grid, group, 0, row, 2, 1);
}
static void
setup_features (FontFeatures *self)
{
const char *kerning[] = { "kern" };
const char *ligatures[] = { "liga", "dlig", "hlig", "clig", "rlig" };
const char *letter_case[] = {
"smcp", "c2sc", "pcap", "c2pc", "unic", "cpsp", "case"
};
const char *number_case[] = { "xxxx", "lnum", "onum" };
const char *number_spacing[] = { "xxxx", "pnum", "tnum" };
const char *fractions[] = { "xxxx", "frac", "afrc" };
const char *num_extras[] = { "zero", "nalt", "sinf" };
const char *char_alt[] = {
"swsh", "cswh", "locl", "calt", "falt", "hist",
"salt", "jalt", "titl", "rand", "subs", "sups",
"ordn", "ltra", "ltrm", "rtla", "rtlm", "rclt"
};
const char *pos_alt[] = {
"init", "medi", "med2", "fina", "fin2", "fin3", "isol"
};
const char *width_var[] = {
"fwid", "hwid", "halt", "pwid", "palt", "twid", "qwid"
};
const char *style_alt[] = {
"ss01", "ss02", "ss03", "ss04", "ss05", "ss06",
"ss07", "ss08", "ss09", "ss10", "ss11", "ss12",
"ss13", "ss14", "ss15", "ss16", "ss17", "ss18",
"ss19", "ss20"
};
const char *char_var[] = {
"cv01", "cv02", "cv03", "cv04", "cv05", "cv06",
"cv07", "cv08", "cv09", "cv10", "cv11", "cv12",
"cv13", "cv14", "cv15", "cv16", "cv17", "cv18",
"cv19", "cv20"
};
const char *math[] = { "dtls", "flac", "mgrk", "ssty" };
const char *bounds[] = { "opbd", "lfbd", "rtbd" };
int row = 0;
add_check_group (self, _("Kerning"), kerning, G_N_ELEMENTS (kerning), row++);
add_check_group (self, _("Ligatures"), ligatures, G_N_ELEMENTS (ligatures), row++);
add_check_group (self, _("Letter Case"), letter_case, G_N_ELEMENTS (letter_case), row++);
add_radio_group (self, _("Number Case"), number_case, G_N_ELEMENTS (number_case), row++);
add_radio_group (self, _("Number Spacing"), number_spacing, G_N_ELEMENTS (number_spacing), row++);
add_radio_group (self, _("Fractions"), fractions, G_N_ELEMENTS (fractions), row++);
add_check_group (self, _("Numeric Extras"), num_extras, G_N_ELEMENTS (num_extras), row++);
add_check_group (self, _("Character Alternatives"), char_alt, G_N_ELEMENTS (char_alt), row++);
add_check_group (self, _("Positional Alternatives"), pos_alt, G_N_ELEMENTS (pos_alt), row++);
add_check_group (self, _("Width Variants"), width_var, G_N_ELEMENTS (width_var), row++);
add_check_group (self, _("Alternative Stylistic Sets"), style_alt, G_N_ELEMENTS (style_alt), row++);
add_check_group (self, _("Character Variants"), char_var, G_N_ELEMENTS (char_var), row++);
add_check_group (self, _("Mathematical"), math, G_N_ELEMENTS (math), row++);
add_check_group (self, _("Optical Bounds"), bounds, G_N_ELEMENTS (bounds), row++);
self->feature_items = g_list_reverse (self->feature_items);
}
static void
reset (GSimpleAction *action,
GVariant *parameter,
FontFeatures *self)
{
update_features (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FEATURES]);
g_simple_action_set_enabled (self->reset_action, FALSE);
}
static void
font_features_init (FontFeatures *self)
{
self->font_map = g_object_ref (pango2_font_map_get_default ());
gtk_widget_init_template (GTK_WIDGET (self));
self->font_desc = pango2_font_description_from_string ("sans 12");
self->lang = pango2_language_get_default ();
setup_features (self);
self->reset_action = g_simple_action_new ("reset", NULL);
g_simple_action_set_enabled (self->reset_action, FALSE);
g_signal_connect (self->reset_action, "activate", G_CALLBACK (reset), self);
}
static void
font_features_dispose (GObject *object)
{
FontFeatures *self = FONT_FEATURES (object);
gtk_widget_clear_template (GTK_WIDGET (object), FONT_FEATURES_TYPE);
g_list_free_full (self->feature_items, g_free);
G_OBJECT_CLASS (font_features_parent_class)->dispose (object);
}
static void
font_features_finalize (GObject *object)
{
FontFeatures *self = FONT_FEATURES (object);
g_clear_pointer (&self->font_desc, pango2_font_description_free);
g_clear_object (&self->font_map);
G_OBJECT_CLASS (font_features_parent_class)->finalize (object);
}
static void
font_features_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
FontFeatures *self = FONT_FEATURES (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_set_object (&self->font_map, g_value_get_object (value));
break;
case PROP_FONT_DESC:
pango2_font_description_free (self->font_desc);
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
break;
case PROP_LANGUAGE:
self->lang = pango2_language_from_string (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
update_features (self);
}
static void
font_features_get_property (GObject *object,
unsigned int prop_id,
GValue *value,
GParamSpec *pspec)
{
FontFeatures *self = FONT_FEATURES (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_value_set_object (value, self->font_map);
break;
case PROP_FEATURES:
g_value_take_string (value, get_features (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_features_class_init (FontFeaturesClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = font_features_dispose;
object_class->finalize = font_features_finalize;
object_class->get_property = font_features_get_property;
object_class->set_property = font_features_set_property;
properties[PROP_FONT_MAP] =
g_param_spec_object ("font-map", "", "",
PANGO2_TYPE_FONT_MAP,
G_PARAM_READWRITE);
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", "", "",
PANGO2_TYPE_FONT_DESCRIPTION,
G_PARAM_WRITABLE);
properties[PROP_LANGUAGE] =
g_param_spec_string ("language", "", "",
"en",
G_PARAM_WRITABLE);
properties[PROP_FEATURES] =
g_param_spec_string ("features", "", "",
"",
G_PARAM_READABLE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/fontfeatures.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontFeatures, grid);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontFeatures, label);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), script_changed);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontfeatures");
}
GAction *
font_features_get_reset_action (FontFeatures *self)
{
return G_ACTION (self->reset_action);
}
-15
View File
@@ -1,15 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define FONT_FEATURES_TYPE (font_features_get_type ())
#define FONT_FEATURES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_FEATURES_TYPE, FontFeatures))
typedef struct _FontFeatures FontFeatures;
typedef struct _FontFeaturesClass FontFeaturesClass;
GType font_features_get_type (void);
GAction * font_features_get_reset_action (FontFeatures *self);
-25
View File
@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="FontFeatures" parent="GtkWidget">
<property name="layout-manager"><object class="GtkBinLayout"/></property>
<child>
<object class="GtkGrid" id="grid">
<child>
<object class="GtkLabel" id="label">
<property name="label" translatable="yes">Features</property>
<property name="margin-bottom">10</property>
<property name="xalign">0</property>
<style>
<class name="heading"/>
</style>
<layout>
<property name="row">-1</property>
<property name="column">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>
-508
View File
@@ -1,508 +0,0 @@
#include "fontvariations.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
#include "rangeedit.h"
enum {
PROP_FONT_MAP = 1,
PROP_FONT_DESC,
PROP_VARIATIONS,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _FontVariations
{
GtkWidget parent;
GtkGrid *label;
GtkGrid *grid;
Pango2FontDescription *font_desc;
GSimpleAction *reset_action;
gboolean has_variations;
GtkWidget *instance_combo;
GHashTable *axes;
GHashTable *instances;
Pango2FontMap *font_map;
};
struct _FontVariationsClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(FontVariations, font_variations, GTK_TYPE_WIDGET);
static Pango2Font *
get_font (FontVariations *self)
{
Pango2Context *context;
Pango2Font *font;
context = pango2_context_new_with_font_map (self->font_map);
font = pango2_context_load_font (context, self->font_desc);
g_object_unref (context);
return font;
}
typedef struct {
guint32 tag;
GtkAdjustment *adjustment;
double default_value;
} Axis;
static guint
axes_hash (gconstpointer v)
{
const Axis *p = v;
return p->tag;
}
static gboolean
axes_equal (gconstpointer v1, gconstpointer v2)
{
const Axis *p1 = v1;
const Axis *p2 = v2;
return p1->tag == p2->tag;
}
static void
unset_instance (GtkAdjustment *adjustment,
FontVariations *self)
{
if (self->instance_combo)
gtk_combo_box_set_active (GTK_COMBO_BOX (self->instance_combo), 0);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VARIATIONS]);
g_simple_action_set_enabled (self->reset_action, TRUE);
}
static void
add_axis (FontVariations *self,
hb_face_t *hb_face,
hb_ot_var_axis_info_t *ax,
int i)
{
GtkWidget *axis_label;
GtkWidget *axis_scale;
GtkAdjustment *adjustment;
Axis *axis;
char name[20];
unsigned int name_len = 20;
hb_ot_name_get_utf8 (hb_face, ax->name_id, HB_LANGUAGE_INVALID, &name_len, name);
axis_label = gtk_label_new (name);
gtk_widget_set_halign (axis_label, GTK_ALIGN_START);
gtk_widget_set_valign (axis_label, GTK_ALIGN_BASELINE);
gtk_grid_attach (self->grid, axis_label, 0, i, 1, 1);
adjustment = gtk_adjustment_new (ax->default_value, ax->min_value, ax->max_value,
1.0, 10.0, 0.0);
axis_scale = g_object_new (RANGE_EDIT_TYPE,
"adjustment", adjustment,
"default-value", ax->default_value,
"n-chars", 5,
"hexpand", TRUE,
"halign", GTK_ALIGN_FILL,
"valign", GTK_ALIGN_BASELINE,
NULL);
gtk_grid_attach (self->grid, axis_scale, 1, i, 1, 1);
axis = g_new0 (Axis, 1);
axis->tag = ax->tag;
axis->adjustment = adjustment;
axis->default_value = ax->default_value;
g_hash_table_add (self->axes, axis);
g_signal_connect (adjustment, "value-changed", G_CALLBACK (unset_instance), self);
}
typedef struct {
char *name;
unsigned int index;
} Instance;
static guint
instance_hash (gconstpointer v)
{
const Instance *p = v;
return g_str_hash (p->name);
}
static gboolean
instance_equal (gconstpointer v1, gconstpointer v2)
{
const Instance *p1 = v1;
const Instance *p2 = v2;
return g_str_equal (p1->name, p2->name);
}
static void
free_instance (gpointer data)
{
Instance *instance = data;
g_free (instance->name);
g_free (instance);
}
static void
add_instance (FontVariations *self,
hb_face_t *face,
unsigned int index,
GtkWidget *combo,
int pos)
{
Instance *instance;
hb_ot_name_id_t name_id;
char name[20];
unsigned int name_len = 20;
instance = g_new0 (Instance, 1);
name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, index);
hb_ot_name_get_utf8 (face, name_id, HB_LANGUAGE_INVALID, &name_len, name);
instance->name = g_strdup (name);
instance->index = index;
g_hash_table_add (self->instances, instance);
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), instance->name);
}
static void
instance_changed (GtkComboBox *combo,
FontVariations *self)
{
char *text;
Instance *instance;
Instance ikey;
int i;
unsigned int coords_length;
float *coords = NULL;
hb_ot_var_axis_info_t *ai = NULL;
unsigned int n_axes;
Pango2Font *font = NULL;
hb_font_t *hb_font;
hb_face_t *hb_face;
text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (combo));
if (text[0] == '\0')
goto out;
ikey.name = text;
instance = g_hash_table_lookup (self->instances, &ikey);
if (!instance)
{
g_print ("did not find instance %s\n", text);
goto out;
}
font = get_font (self);
hb_font = pango2_font_get_hb_font (font);
hb_face = hb_font_get_face (hb_font);
n_axes = hb_ot_var_get_axis_infos (hb_face, 0, NULL, NULL);
ai = g_new (hb_ot_var_axis_info_t, n_axes);
hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, ai);
coords = g_new (float, n_axes);
hb_ot_var_named_instance_get_design_coords (hb_face,
instance->index,
&coords_length,
coords);
for (i = 0; i < n_axes; i++)
{
Axis *axis;
Axis akey;
double value;
value = coords[ai[i].axis_index];
akey.tag = ai[i].tag;
axis = g_hash_table_lookup (self->axes, &akey);
if (axis)
{
g_signal_handlers_block_by_func (axis->adjustment, unset_instance, self);
gtk_adjustment_set_value (axis->adjustment, value);
g_signal_handlers_unblock_by_func (axis->adjustment, unset_instance, self);
}
}
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VARIATIONS]);
g_simple_action_set_enabled (self->reset_action, TRUE);
out:
g_free (text);
g_clear_object (&font);
g_free (ai);
g_free (coords);
}
static void
update_variations (FontVariations *self)
{
GtkWidget *child;
Pango2Font *font;
hb_font_t *hb_font;
hb_face_t *hb_face;
unsigned int n_axes;
hb_ot_var_axis_info_t *ai = NULL;
int i;
font = get_font (self);
hb_font = pango2_font_get_hb_font (font);
hb_face = hb_font_get_face (hb_font);
g_object_ref (self->label);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->grid))))
gtk_grid_remove (self->grid, child);
gtk_grid_attach (self->grid, GTK_WIDGET (self->label), 0, -2, 2, 1);
g_object_unref (self->label);
self->instance_combo = NULL;
g_hash_table_remove_all (self->axes);
g_hash_table_remove_all (self->instances);
n_axes = hb_ot_var_get_axis_infos (hb_face, 0, NULL, NULL);
self->has_variations = n_axes > 0;
gtk_widget_set_visible (GTK_WIDGET (self), self->has_variations);
if (!self->has_variations)
{
g_simple_action_set_enabled (self->reset_action, FALSE);
return;
}
if (hb_ot_var_get_named_instance_count (hb_face) > 0)
{
GtkWidget *label;
GtkWidget *combo;
label = gtk_label_new ("Instance");
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
gtk_grid_attach (self->grid, label, 0, -1, 1, 1);
combo = gtk_combo_box_text_new ();
gtk_widget_set_halign (combo, GTK_ALIGN_START);
gtk_widget_set_valign (combo, GTK_ALIGN_BASELINE);
gtk_widget_set_hexpand (combo, TRUE);
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "");
for (i = 0; i < hb_ot_var_get_named_instance_count (hb_face); i++)
add_instance (self, hb_face, i, combo, i);
gtk_grid_attach (GTK_GRID (self->grid), combo, 1, -1, 1, 1);
g_signal_connect (combo, "changed", G_CALLBACK (instance_changed), self);
self->instance_combo = combo;
}
ai = g_new (hb_ot_var_axis_info_t, n_axes);
hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, ai);
for (i = 0; i < n_axes; i++)
add_axis (self, hb_face, &ai[i], i);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VARIATIONS]);
g_clear_object (&font);
g_free (ai);
}
static char *
get_variations (FontVariations *self)
{
GHashTableIter iter;
Axis *axis;
char buf[G_ASCII_DTOSTR_BUF_SIZE];
const char *sep = "";
GString *s;
if (!self->has_variations)
return g_strdup ("");
s = g_string_new ("");
g_hash_table_iter_init (&iter, self->axes);
while (g_hash_table_iter_next (&iter, (gpointer *)NULL, (gpointer *)&axis))
{
char tag[5];
double value;
hb_tag_to_string (axis->tag, tag);
tag[4] = '\0';
value = gtk_adjustment_get_value (axis->adjustment);
g_string_append_printf (s, "%s%s=%s", sep, tag, g_ascii_dtostr (buf, sizeof (buf), value));
sep = ",";
}
return g_string_free (s, FALSE);
}
static void
reset (GSimpleAction *action,
GVariant *parameter,
FontVariations *self)
{
GHashTableIter iter;
Axis *axis;
if (self->instance_combo)
gtk_combo_box_set_active (GTK_COMBO_BOX (self->instance_combo), 0);
g_hash_table_iter_init (&iter, self->axes);
while (g_hash_table_iter_next (&iter, (gpointer *)NULL, (gpointer *)&axis))
{
g_signal_handlers_block_by_func (axis->adjustment, unset_instance, self);
gtk_adjustment_set_value (axis->adjustment, axis->default_value);
g_signal_handlers_unblock_by_func (axis->adjustment, unset_instance, self);
}
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VARIATIONS]);
g_simple_action_set_enabled (self->reset_action, FALSE);
}
static void
font_variations_init (FontVariations *self)
{
self->font_map = g_object_ref (pango2_font_map_get_default ());
gtk_widget_init_template (GTK_WIDGET (self));
self->reset_action = g_simple_action_new ("reset", NULL);
g_simple_action_set_enabled (self->reset_action, FALSE);
g_signal_connect (self->reset_action, "activate", G_CALLBACK (reset), self);
self->instances = g_hash_table_new_full (instance_hash, instance_equal,
NULL, free_instance);
self->axes = g_hash_table_new_full (axes_hash, axes_equal,
NULL, g_free);
}
static void
font_variations_dispose (GObject *object)
{
FontVariations *self = FONT_VARIATIONS (object);
gtk_widget_clear_template (GTK_WIDGET (object), FONT_VARIATIONS_TYPE);
g_hash_table_unref (self->instances);
g_hash_table_unref (self->axes);
G_OBJECT_CLASS (font_variations_parent_class)->dispose (object);
}
static void
font_variations_finalize (GObject *object)
{
FontVariations *self = FONT_VARIATIONS (object);
g_clear_pointer (&self->font_desc, pango2_font_description_free);
g_clear_object (&self->font_map);
G_OBJECT_CLASS (font_variations_parent_class)->finalize (object);
}
static void
font_variations_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
FontVariations *self = FONT_VARIATIONS (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_set_object (&self->font_map, g_value_get_object (value));
break;
case PROP_FONT_DESC:
pango2_font_description_free (self->font_desc);
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
update_variations (self);
}
static void
font_variations_get_property (GObject *object,
unsigned int prop_id,
GValue *value,
GParamSpec *pspec)
{
FontVariations *self = FONT_VARIATIONS (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_value_set_object (value, self->font_map);
break;
case PROP_VARIATIONS:
g_value_take_string (value, get_variations (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
font_variations_class_init (FontVariationsClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = font_variations_dispose;
object_class->finalize = font_variations_finalize;
object_class->get_property = font_variations_get_property;
object_class->set_property = font_variations_set_property;
properties[PROP_FONT_MAP] =
g_param_spec_object ("font-map", "", "",
PANGO2_TYPE_FONT_MAP,
G_PARAM_READWRITE);
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", "", "",
PANGO2_TYPE_FONT_DESCRIPTION,
G_PARAM_WRITABLE);
properties[PROP_VARIATIONS] =
g_param_spec_string ("variations", "", "",
"",
G_PARAM_READABLE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/fontvariations.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontVariations, grid);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontVariations, label);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontvariations");
}
GAction *
font_variations_get_reset_action (FontVariations *self)
{
return G_ACTION (self->reset_action);
}
-15
View File
@@ -1,15 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define FONT_VARIATIONS_TYPE (font_variations_get_type ())
#define FONT_VARIATIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_VARIATIONS_TYPE, FontVariations))
typedef struct _FontVariations FontVariations;
typedef struct _FontVariationsClass FontVariationsClass;
GType font_variations_get_type (void);
GAction * font_variations_get_reset_action (FontVariations *self);
-25
View File
@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="FontVariations" parent="GtkWidget">
<property name="layout-manager"><object class="GtkBinLayout"/></property>
<child>
<object class="GtkGrid" id="grid">
<child>
<object class="GtkLabel" id="label">
<property name="label" translatable="yes">Variations</property>
<property name="margin-bottom">10</property>
<property name="xalign">0</property>
<style>
<class name="heading"/>
</style>
<layout>
<property name="row">-2</property>
<property name="column">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>
-56
View File
@@ -1,56 +0,0 @@
#include "glyphitem.h"
struct _GlyphItem {
GObject parent;
Pango2Font *font;
hb_codepoint_t glyph;
};
struct _GlyphItemClass {
GObjectClass parent_class;
};
G_DEFINE_TYPE (GlyphItem, glyph_item, G_TYPE_OBJECT)
static void
glyph_item_init (GlyphItem *self)
{
}
static void
glyph_item_finalize (GObject *object)
{
GlyphItem *item = GLYPH_ITEM (object);
g_object_unref (item->font);
G_OBJECT_CLASS (glyph_item_parent_class)->finalize (object);
}
static void
glyph_item_class_init (GlyphItemClass *class)
{
G_OBJECT_CLASS (class)->finalize = glyph_item_finalize;
}
GlyphItem *
glyph_item_new (Pango2Font *font,
hb_codepoint_t glyph)
{
GlyphItem *item = g_object_new (GLYPH_ITEM_TYPE, NULL);
item->font = g_object_ref (font);
item->glyph = glyph;
return item;
}
Pango2Font *
glyph_item_get_font (GlyphItem *item)
{
return item->font;
}
hb_codepoint_t
glyph_item_get_glyph (GlyphItem *item)
{
return item->glyph;
}
-17
View File
@@ -1,17 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define GLYPH_ITEM_TYPE (glyph_item_get_type ())
#define GLYPH_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPH_ITEM_TYPE, GlyphItem))
typedef struct _GlyphItem GlyphItem;
typedef struct _GlyphItemClass GlyphItemClass;
GType glyph_item_get_type (void);
GlyphItem * glyph_item_new (Pango2Font *font,
hb_codepoint_t glyph);
hb_codepoint_t glyph_item_get_glyph (GlyphItem *item);
Pango2Font * glyph_item_get_font (GlyphItem *item);
-97
View File
@@ -1,97 +0,0 @@
#include "glyphmodel.h"
#include "glyphitem.h"
struct _GlyphModel {
GObject parent;
Pango2Font *font;
unsigned int num_glyphs;
GlyphItem **glyphs;
};
struct _GlyphModelClass {
GObjectClass parent_class;
};
static GType
glyph_model_get_item_type (GListModel *model)
{
return GLYPH_ITEM_TYPE;
}
static guint
glyph_model_get_n_items (GListModel *model)
{
GlyphModel *self = GLYPH_MODEL (model);
return self->num_glyphs;
}
static gpointer
glyph_model_get_item (GListModel *model,
guint position)
{
GlyphModel *self = GLYPH_MODEL (model);
if (position >= self->num_glyphs)
return NULL;
if (self->glyphs[position] == NULL)
self->glyphs[position] = glyph_item_new (self->font, position);
return g_object_ref (self->glyphs[position]);
}
static void
glyph_model_list_model_init (GListModelInterface *iface)
{
iface->get_item_type = glyph_model_get_item_type;
iface->get_n_items = glyph_model_get_n_items;
iface->get_item = glyph_model_get_item;
}
G_DEFINE_TYPE_WITH_CODE (GlyphModel, glyph_model, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, glyph_model_list_model_init))
static void
glyph_model_init (GlyphModel *self)
{
}
static void
glyph_model_finalize (GObject *object)
{
GlyphModel *self = GLYPH_MODEL (object);
g_object_unref (self->font);
for (int i = 0; i < self->num_glyphs; i++)
{
if (self->glyphs[i])
g_object_unref (self->glyphs[i]);
}
g_free (self->glyphs);
G_OBJECT_CLASS (glyph_model_parent_class)->finalize (object);
}
static void
glyph_model_class_init (GlyphModelClass *class)
{
G_OBJECT_CLASS (class)->finalize = glyph_model_finalize;
}
GlyphModel *
glyph_model_new (Pango2Font *font)
{
GlyphModel *self;
hb_face_t *hb_face;
self = g_object_new (GLYPH_MODEL_TYPE, NULL);
self->font = g_object_ref (font);
hb_face = pango2_hb_face_get_hb_face (PANGO2_HB_FACE (pango2_font_get_face (font)));
self->num_glyphs = hb_face_get_glyph_count (hb_face);
self->glyphs = g_new0 (GlyphItem *, self->num_glyphs);
return self;
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define GLYPH_MODEL_TYPE (glyph_model_get_type ())
#define GLYPH_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPH_MODEL_TYPE, GlyphModel))
typedef struct _GlyphModel GlyphModel;
typedef struct _GlyphModelClass GlyphModelClass;
GType glyph_model_get_type (void);
GlyphModel * glyph_model_new (Pango2Font *font);
-239
View File
@@ -1,239 +0,0 @@
#include "glyphsview.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
#include "glyphitem.h"
#include "glyphmodel.h"
#include "glyphview.h"
enum {
PROP_FONT_MAP = 1,
PROP_FONT_DESC,
PROP_VARIATIONS,
PROP_PALETTE,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _GlyphsView
{
GtkWidget parent;
Pango2FontMap *font_map;
GtkGridView *glyphs;
Pango2FontDescription *font_desc;
char *variations;
char *palette;
GQuark palette_quark;
};
struct _GlyphsViewClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(GlyphsView, glyphs_view, GTK_TYPE_WIDGET);
static void
glyphs_view_init (GlyphsView *self)
{
self->font_map = g_object_ref (pango2_font_map_get_default ());
self->font_desc = pango2_font_description_from_string ("sans 12");
self->variations = g_strdup ("");
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
self->palette_quark = g_quark_from_string (self->palette);
gtk_widget_set_layout_manager (GTK_WIDGET (self),
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
gtk_widget_init_template (GTK_WIDGET (self));
}
static void
glyphs_view_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), GLYPHS_VIEW_TYPE);
G_OBJECT_CLASS (glyphs_view_parent_class)->dispose (object);
}
static void
glyphs_view_finalize (GObject *object)
{
GlyphsView *self = GLYPHS_VIEW (object);
g_clear_object (&self->font_map);
pango2_font_description_free (self->font_desc);
g_free (self->variations);
g_free (self->palette);
G_OBJECT_CLASS (glyphs_view_parent_class)->finalize (object);
}
static Pango2Font *
get_font (GlyphsView *self,
int size)
{
Pango2Context *context;
Pango2FontDescription *desc;
Pango2Font *font;
context = pango2_context_new_with_font_map (self->font_map);
desc = pango2_font_description_copy_static (self->font_desc);
pango2_font_description_set_variations (desc, self->variations);
pango2_font_description_set_size (desc, size);
font = pango2_context_load_font (context, desc);
pango2_font_description_free (desc);
g_object_unref (context);
return font;
}
static void
update_glyph_model (GlyphsView *self)
{
Pango2Font *font = get_font (self, 60 * PANGO2_SCALE);
GlyphModel *gm;
GtkSelectionModel *model;
gm = glyph_model_new (font);
model = GTK_SELECTION_MODEL (gtk_no_selection_new (G_LIST_MODEL (gm)));
gtk_grid_view_set_model (self->glyphs, model);
g_object_unref (model);
g_object_unref (font);
}
static void
setup_glyph (GtkSignalListItemFactory *factory,
GObject *listitem)
{
gtk_list_item_set_child (GTK_LIST_ITEM (listitem), GTK_WIDGET (glyph_view_new ()));
}
static void
bind_glyph (GtkSignalListItemFactory *factory,
GObject *listitem,
GlyphsView *self)
{
GlyphView *view;
GObject *item;
view = GLYPH_VIEW (gtk_list_item_get_child (GTK_LIST_ITEM (listitem)));
item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem));
glyph_view_set_font (view, glyph_item_get_font (GLYPH_ITEM (item)));
glyph_view_set_glyph (view, glyph_item_get_glyph (GLYPH_ITEM (item)));
glyph_view_set_palette (view, self->palette_quark);
}
static void
glyphs_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GlyphsView *self = GLYPHS_VIEW (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_set_object (&self->font_map, g_value_get_object (value));
break;
case PROP_FONT_DESC:
pango2_font_description_free (self->font_desc);
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
break;
case PROP_VARIATIONS:
g_free (self->variations);
self->variations = g_strdup (g_value_get_string (value));
break;
case PROP_PALETTE:
g_free (self->palette);
self->palette = g_strdup (g_value_get_string (value));
self->palette_quark = g_quark_from_string (self->palette);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
update_glyph_model (self);
}
static void
glyphs_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GlyphsView *self = GLYPHS_VIEW (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_value_set_object (value, self->font_map);
break;
case PROP_FONT_DESC:
g_value_set_boxed (value, self->font_desc);
break;
case PROP_VARIATIONS:
g_value_set_string (value, self->variations);
break;
case PROP_PALETTE:
g_value_set_string (value, self->palette);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
glyphs_view_class_init (GlyphsViewClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = glyphs_view_dispose;
object_class->finalize = glyphs_view_finalize;
object_class->get_property = glyphs_view_get_property;
object_class->set_property = glyphs_view_set_property;
properties[PROP_FONT_MAP] =
g_param_spec_object ("font-map", "", "",
PANGO2_TYPE_FONT_MAP,
G_PARAM_READWRITE);
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", "", "",
PANGO2_TYPE_FONT_DESCRIPTION,
G_PARAM_READWRITE);
properties[PROP_VARIATIONS] =
g_param_spec_string ("variations", "", "",
"",
G_PARAM_READWRITE);
properties[PROP_PALETTE] =
g_param_spec_string ("palette", "", "",
PANGO2_COLOR_PALETTE_DEFAULT,
G_PARAM_READWRITE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/glyphsview.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), GlyphsView, glyphs);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), setup_glyph);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), bind_glyph);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "glyphsview");
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define GLYPHS_VIEW_TYPE (glyphs_view_get_type ())
#define GLYPHS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPHS_VIEW_TYPE, GlyphsView))
typedef struct _GlyphsView GlyphsView;
typedef struct _GlyphsViewClass GlyphsViewClass;
GType glyphs_view_get_type (void);
-29
View File
@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GlyphsView" parent="GtkWidget">
<style>
<class name="view"/>
</style>
<child>
<object class="GtkScrolledWindow">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<child>
<object class="GtkGridView" id="glyphs">
<style>
<class name="content"/>
</style>
<property name="factory">
<object class="GtkSignalListItemFactory">
<signal name="setup" handler="setup_glyph"/>
<signal name="bind" handler="bind_glyph"/>
</object>
</property>
</object>
</child>
</object>
</child>
</template>
</interface>
-321
View File
@@ -1,321 +0,0 @@
#include "glyphview.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
struct _GlyphView
{
GtkWidget parent;
Pango2Font *font;
GQuark palette;
int palette_index;
hb_codepoint_t glyph;
int n_layers;
int layer;
};
struct _GlyphViewClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(GlyphView, glyph_view, GTK_TYPE_WIDGET);
static void
click_cb (GtkGestureClick *gesture,
int n_press,
double x,
double y,
GlyphView *self)
{
if (self->n_layers == 0)
return;
self->layer++;
if (self->layer == self->n_layers)
self->layer = -1;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
glyph_view_init (GlyphView *self)
{
GtkGesture *click;
self->n_layers = 0;
self->layer = -1;
click = gtk_gesture_click_new ();
g_signal_connect (click, "pressed", G_CALLBACK (click_cb), self);
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (click));
}
static void
glyph_view_dispose (GObject *object)
{
GlyphView *self = GLYPH_VIEW (object);
g_clear_object (&self->font);
G_OBJECT_CLASS (glyph_view_parent_class)->dispose (object);
}
static void
glyph_view_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GlyphView *self = GLYPH_VIEW (widget);
Pango2GlyphString *glyphs;
Pango2Rectangle ink, logical;
cairo_t *cr;
int width, height;
char name[80];
pango2_font_get_glyph_extents (self->font, self->glyph, &ink, &logical);
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height));
glyphs = pango2_glyph_string_new ();
pango2_glyph_string_set_size (glyphs, 1);
glyphs->glyphs[0].geometry.width = ink.width;
glyphs->glyphs[0].geometry.x_offset = ink.x;
glyphs->glyphs[0].geometry.y_offset = -ink.y;
if (self->layer == -1)
{
glyphs->glyphs[0].glyph = self->glyph;
cairo_set_source_rgb (cr, 0, 0, 0);
}
else
{
hb_face_t *face = hb_font_get_face (pango2_font_get_hb_font (self->font));
hb_ot_color_layer_t *layers;
unsigned int count;
layers = g_newa (hb_ot_color_layer_t, self->n_layers);
count = self->n_layers;
hb_ot_color_glyph_get_layers (face,
self->glyph,
0,
&count,
layers);
glyphs->glyphs[0].glyph = layers[self->layer].glyph;
if (layers[self->layer].color_index == 0xffff)
{
cairo_set_source_rgb (cr, 0, 0, 0);
}
else
{
hb_color_t *colors;
unsigned int n_colors;
hb_color_t color;
n_colors = hb_ot_color_palette_get_colors (face,
self->palette_index,
0,
NULL,
NULL);
colors = g_newa (hb_color_t, n_colors);
hb_ot_color_palette_get_colors (face,
self->palette_index,
0,
&n_colors,
colors);
color = colors[layers[self->layer].color_index];
cairo_set_source_rgba (cr, hb_color_get_red (color)/255.,
hb_color_get_green (color)/255.,
hb_color_get_blue (color)/255.,
hb_color_get_alpha (color)/255.);
}
}
cairo_move_to (cr, (width - logical.width/1024.)/2, (height - logical.height/1024.)/2);
pango2_cairo_show_color_glyph_string (cr, self->font, self->palette, glyphs);
{
Pango2Layout *layout;
Pango2FontDescription *desc;
char gid[20];
hb_font_t *hb_font;
hb_face_t *hb_face;
g_snprintf (gid, sizeof (gid), "%d", self->glyph);
layout = gtk_widget_create_pango_layout (widget, gid);
desc = pango2_font_description_from_string ("Cantarell 8");
pango2_layout_set_font_description (layout, desc);
pango2_font_description_free (desc);
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (5, 5));
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,0.7});
gtk_snapshot_restore (snapshot);
hb_font = pango2_font_get_hb_font (self->font);
hb_face = hb_font_get_face (hb_font);
if (hb_ot_layout_has_glyph_classes (hb_face))
{
hb_ot_layout_glyph_class_t class;
const char *class_names[] = {
NULL, "Base", "Ligature", "Mark", "Component"
};
int w, h;
class = hb_ot_layout_get_glyph_class (hb_face, self->glyph);
if (class != HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED)
{
pango2_layout_set_text (layout, class_names[class], -1);
pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width - w/1024. - 5, 5));
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,.7});
gtk_snapshot_restore (snapshot);
}
}
if (hb_font_get_glyph_name (hb_font, self->glyph, name, sizeof (name)))
{
int w, h;
pango2_layout_set_text (layout, name, -1);
pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (5, height - h/1024. - 5));
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,.7});
gtk_snapshot_restore (snapshot);
}
if (self->n_layers > 0)
{
char buf[128];
int w, h;
if (self->layer == -1)
g_snprintf (buf, sizeof (buf), "%d Layers", self->n_layers);
else
g_snprintf (buf, sizeof (buf), "Layer %d", self->layer);
pango2_layout_set_text (layout, buf, -1);
pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
gtk_snapshot_save (snapshot);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width - w/1024. - 5, height - h/1024. - 5));
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,.7});
gtk_snapshot_restore (snapshot);
}
g_object_unref (layout);
}
}
static void
glyph_view_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GlyphView *self = GLYPH_VIEW (widget);
Pango2Rectangle ink, logical;
pango2_font_get_glyph_extents (self->font, self->glyph, &ink, &logical);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
*minimum = *natural = 2 * logical.width / PANGO2_SCALE;
else
*minimum = *natural = 2 * logical.height / PANGO2_SCALE;
}
static void
glyph_view_class_init (GlyphViewClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = glyph_view_dispose;
widget_class->snapshot = glyph_view_snapshot;
widget_class->measure = glyph_view_measure;
gtk_widget_class_set_css_name (widget_class, "glyphview");
}
GlyphView *
glyph_view_new (void)
{
return g_object_new (GLYPH_VIEW_TYPE, NULL);
}
void
glyph_view_set_font (GlyphView *self,
Pango2Font *font)
{
if (g_set_object (&self->font, font))
gtk_widget_queue_resize (GTK_WIDGET (self));
}
static unsigned int
find_palette_index_by_flag (hb_face_t *hbface,
hb_ot_color_palette_flags_t flag)
{
unsigned int n_palettes;
n_palettes = hb_ot_color_palette_get_count (hbface);
for (unsigned int i = 0; i < n_palettes; i++)
{
if (hb_ot_color_palette_get_flags (hbface, i) & flag)
return i;
}
return 0;
}
void
glyph_view_set_palette (GlyphView *self,
GQuark palette)
{
if (self->palette == palette)
return;
self->palette = palette;
if (palette == g_quark_from_string (PANGO2_COLOR_PALETTE_DEFAULT))
self->palette_index = 0;
else if (palette == g_quark_from_string (PANGO2_COLOR_PALETTE_LIGHT))
self->palette_index = find_palette_index_by_flag (hb_font_get_face (pango2_font_get_hb_font (self->font)), HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND);
else if (palette == g_quark_from_string (PANGO2_COLOR_PALETTE_DARK))
self->palette_index = find_palette_index_by_flag (hb_font_get_face (pango2_font_get_hb_font (self->font)), HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND);
else
{
const char *str = g_quark_to_string (palette);
char *endp;
if (g_str_has_prefix (str, "palette"))
self->palette_index = g_ascii_strtoll (str + strlen ("palette"), &endp, 10);
}
gtk_widget_queue_resize (GTK_WIDGET (self));
}
void
glyph_view_set_glyph (GlyphView *self,
hb_codepoint_t glyph)
{
if (self->glyph == glyph)
return;
self->glyph = glyph;
self->n_layers = hb_ot_color_glyph_get_layers (hb_font_get_face (pango2_font_get_hb_font (self->font)), glyph, 0, NULL, NULL);
self->layer = -1;
gtk_widget_queue_resize (GTK_WIDGET (self));
}
-21
View File
@@ -1,21 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define GLYPH_VIEW_TYPE (glyph_view_get_type ())
#define GLYPH_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPH_VIEW_TYPE, GlyphView))
typedef struct _GlyphView GlyphView;
typedef struct _GlyphViewClass GlyphViewClass;
GType glyph_view_get_type (void);
GlyphView * glyph_view_new (void);
void glyph_view_set_font (GlyphView *view,
Pango2Font *font);
void glyph_view_set_palette (GlyphView *view,
GQuark palette);
void glyph_view_set_glyph (GlyphView *view,
hb_codepoint_t glyph);
-423
View File
@@ -1,423 +0,0 @@
#include "infoview.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
enum {
PROP_FONT_MAP = 1,
PROP_FONT_DESC,
PROP_SIZE,
PROP_VARIATIONS,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _InfoView
{
GtkWidget parent;
GtkGrid *info;
Pango2FontMap *font_map;
Pango2FontDescription *font_desc;
float size;
char *variations;
};
struct _InfoViewClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(InfoView, info_view, GTK_TYPE_WIDGET);
static void
info_view_init (InfoView *self)
{
self->font_map = g_object_ref (pango2_font_map_get_default ());
self->font_desc = pango2_font_description_from_string ("sans 12");
self->size = 12.;
self->variations = g_strdup ("");
gtk_widget_set_layout_manager (GTK_WIDGET (self),
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
gtk_widget_init_template (GTK_WIDGET (self));
}
static void
info_view_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), INFO_VIEW_TYPE);
G_OBJECT_CLASS (info_view_parent_class)->dispose (object);
}
static void
info_view_finalize (GObject *object)
{
InfoView *self = INFO_VIEW (object);
g_clear_object (&self->font_map);
pango2_font_description_free (self->font_desc);
g_free (self->variations);
G_OBJECT_CLASS (info_view_parent_class)->finalize (object);
}
static Pango2Font *
get_font (InfoView *self,
int size)
{
Pango2Context *context;
Pango2FontDescription *desc;
Pango2Font *font;
context = pango2_context_new_with_font_map (self->font_map);
desc = pango2_font_description_copy_static (self->font_desc);
pango2_font_description_set_variations (desc, self->variations);
pango2_font_description_set_size (desc, size);
font = pango2_context_load_font (context, desc);
pango2_font_description_free (desc);
g_object_unref (context);
return font;
}
static GtkWidget *
make_title_label (const char *title)
{
GtkWidget *label;
label = gtk_label_new (title);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_widget_set_halign (label, GTK_ALIGN_START);
g_object_set (label, "margin-top", 10, "margin-bottom", 10, NULL);
gtk_widget_add_css_class (label, "heading");
return label;
}
static void
add_misc_line (InfoView *self,
const char *title,
const char *value,
int row)
{
GtkWidget *label;
label = gtk_label_new (title);
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_START);
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (self->info, label, 0, row, 1, 1);
label = gtk_label_new (value);
gtk_widget_set_halign (label, GTK_ALIGN_END);
gtk_widget_set_valign (label, GTK_ALIGN_START);
gtk_label_set_xalign (GTK_LABEL (label), 1);
gtk_label_set_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_width_chars (GTK_LABEL (label), 40);
gtk_label_set_max_width_chars (GTK_LABEL (label), 40);
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
gtk_grid_attach (self->info, label, 1, row, 1, 1);
}
static void
add_info_line (InfoView *self,
hb_face_t *face,
hb_ot_name_id_t name_id,
const char *title,
int row)
{
char info[256];
unsigned int len = sizeof (info);
if (hb_ot_name_get_utf8 (face, name_id, HB_LANGUAGE_INVALID, &len, info) > 0)
add_misc_line (self, title, info, row);
}
static void
add_metrics_line (InfoView *self,
hb_font_t *font,
hb_ot_metrics_tag_t metrics_tag,
const char *title,
int row)
{
hb_position_t pos;
if (hb_ot_metrics_get_position (font, metrics_tag, &pos))
{
char buf[128];
g_snprintf (buf, sizeof (buf), "%d", pos);
add_misc_line (self, title, buf, row);
}
}
static void
add_style_line (InfoView *self,
hb_font_t *font,
hb_style_tag_t style_tag,
const char *title,
int row)
{
float value;
char buf[16];
value = hb_style_get_value (font, style_tag);
g_snprintf (buf, sizeof (buf), "%.2f", value);
add_misc_line (self, title, buf, row);
}
static void
update_info (InfoView *self)
{
GtkWidget *child;
int size = pango2_font_description_get_size (self->font_desc);
Pango2Font *pango_font = get_font (self, MAX (size, 10 * PANGO2_SCALE));
hb_font_t *font1 = pango2_font_get_hb_font (pango_font);
hb_face_t *face = hb_font_get_face (font1);
hb_font_t *font = hb_font_create_sub_font (font1);
int row = 0;
char buf[128];
unsigned int count;
GString *s;
hb_tag_t *tables;
const char *path;
hb_font_set_scale (font, hb_face_get_upem (face), hb_face_get_upem (face));
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->info))) != NULL)
gtk_widget_unparent (child);
gtk_grid_attach (self->info, make_title_label ("General Info"), 0, row++, 2, 1);
path = pango2_hb_face_get_file (PANGO2_HB_FACE (pango2_font_get_face (pango_font)));
if (path)
add_misc_line (self, "File ", path, row++);
add_info_line (self, face, HB_OT_NAME_ID_FONT_FAMILY, "Font Family Name", row++);
add_info_line (self, face, HB_OT_NAME_ID_FONT_SUBFAMILY, "Font Subfamily Name", row++);
add_info_line (self, face, HB_OT_NAME_ID_UNIQUE_ID, "Unique Font Identifier", row++);
add_info_line (self, face, HB_OT_NAME_ID_FULL_NAME, "Full Name", row++);
add_info_line (self, face, HB_OT_NAME_ID_VERSION_STRING, "Version", row++);
add_info_line (self, face, HB_OT_NAME_ID_POSTSCRIPT_NAME, "Postscript Name", row++);
add_info_line (self, face, HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY, "Typographic Family Name", row++);
add_info_line (self, face, HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY, "Typographic Subfamily Name", row++);
add_info_line (self, face, HB_OT_NAME_ID_MANUFACTURER, "Vendor ID", row++);
add_info_line (self, face, HB_OT_NAME_ID_DESIGNER, "Designer", row++);
add_info_line (self, face, HB_OT_NAME_ID_DESCRIPTION, "Description", row++);
add_info_line (self, face, HB_OT_NAME_ID_COPYRIGHT, "Copyright", row++);
gtk_grid_attach (self->info, make_title_label ("Metrics"), 0, row++, 2, 1);
g_snprintf (buf, sizeof (buf), "%d", hb_face_get_upem (face));
add_misc_line (self, "Units per Em", buf, row++);
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, "Ascender", row++);
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, "Descender", row++);
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, "Line Gap", row++);
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE, "Caret Rise", row++);
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN, "Caret Run", row++);
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET, "Caret Offset", row++);
add_metrics_line (self, font, HB_OT_METRICS_TAG_X_HEIGHT, "x Height", row++);
add_metrics_line (self, font, HB_OT_METRICS_TAG_CAP_HEIGHT, "Cap Height", row++);
add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_SIZE, "Strikeout Size", row++);
add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_OFFSET, "Strikeout Offset", row++);
add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_SIZE, "Underline Size", row++);
add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_OFFSET, "Underline Offset", row++);
gtk_grid_attach (self->info, make_title_label ("Style"), 0, row++, 2, 1);
add_style_line (self, font, HB_STYLE_TAG_ITALIC, "Italic", row++);
add_style_line (self, font, HB_STYLE_TAG_OPTICAL_SIZE, "Optical Size", row++);
add_style_line (self, font, HB_STYLE_TAG_SLANT_ANGLE, "Slant Angle", row++);
add_style_line (self, font, HB_STYLE_TAG_WIDTH, "Width", row++);
add_style_line (self, font, HB_STYLE_TAG_WEIGHT, "Weight", row++);
gtk_grid_attach (self->info, make_title_label ("Miscellaneous"), 0, row++, 2, 1);
count = hb_face_get_glyph_count (face);
g_snprintf (buf, sizeof (buf), "%d", count);
add_misc_line (self, "Glyph Count", buf, row++);
if (hb_ot_var_get_axis_count (face) > 0)
{
s = g_string_new ("");
hb_ot_var_axis_info_t *axes;
axes = g_newa (hb_ot_var_axis_info_t, hb_ot_var_get_axis_count (face));
count = hb_ot_var_get_axis_count (face);
hb_ot_var_get_axis_infos (face, 0, &count, axes);
for (int i = 0; i < count; i++)
{
char name[256];
unsigned int len;
len = sizeof (buf);
hb_ot_name_get_utf8 (face, axes[i].name_id, HB_LANGUAGE_INVALID, &len, name);
if (s->len > 0)
g_string_append (s, ", ");
g_string_append (s, name);
}
add_misc_line (self, "Axes", s->str, row++);
g_string_free (s, TRUE);
}
if (hb_ot_var_get_named_instance_count (face) > 0)
{
s = g_string_new ("");
for (int i = 0; i < hb_ot_var_get_named_instance_count (face); i++)
{
hb_ot_name_id_t name_id;
char name[256];
unsigned int len;
name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, i);
len = sizeof (buf);
hb_ot_name_get_utf8 (face, name_id, HB_LANGUAGE_INVALID, &len, name);
if (s->len > 0)
g_string_append (s, ", ");
g_string_append (s, name);
}
add_misc_line (self, "Named Instances", s->str, row++);
g_string_free (s, TRUE);
}
s = g_string_new ("");
count = hb_face_get_table_tags (face, 0, NULL, NULL);
tables = g_newa (hb_tag_t, count);
hb_face_get_table_tags (face, 0, &count, tables);
for (int i = 0; i < count; i++)
{
memset (buf, 0, sizeof (buf));
hb_tag_to_string (tables[i], buf);
if (s->len > 0)
g_string_append (s, ", ");
g_string_append (s, buf);
}
add_misc_line (self, "Tables", s->str, row++);
g_string_free (s, TRUE);
s = g_string_new ("");
if (hb_ot_color_has_palettes (face))
g_string_append_printf (s, "%s", "Palettes");
if (hb_ot_color_has_layers (face))
g_string_append_printf (s, "%s%s", s->len > 0 ? ", " : "", "Layers");
if (hb_ot_color_has_svg (face))
g_string_append_printf (s, "%s%s", s->len > 0 ? ", " : "", "SVG");
if (hb_ot_color_has_png (face))
g_string_append_printf (s, "%s%s", s->len > 0 ? ", " : "", "PNG");
if (s->len > 0)
add_misc_line (self, "Color", s->str, row++);
g_string_free (s, TRUE);
hb_font_destroy (font);
}
static void
info_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
InfoView *self = INFO_VIEW (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_set_object (&self->font_map, g_value_get_object (value));
break;
case PROP_FONT_DESC:
pango2_font_description_free (self->font_desc);
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
break;
case PROP_SIZE:
self->size = g_value_get_float (value);
break;
case PROP_VARIATIONS:
g_free (self->variations);
self->variations = g_strdup (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
update_info (self);
}
static void
info_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
InfoView *self = INFO_VIEW (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_value_set_object (value, self->font_map);
break;
case PROP_FONT_DESC:
g_value_set_boxed (value, self->font_desc);
break;
case PROP_SIZE:
g_value_set_float (value, self->size);
break;
case PROP_VARIATIONS:
g_value_set_string (value, self->variations);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
info_view_class_init (InfoViewClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = info_view_dispose;
object_class->finalize = info_view_finalize;
object_class->get_property = info_view_get_property;
object_class->set_property = info_view_set_property;
properties[PROP_FONT_MAP] =
g_param_spec_object ("font-map", "", "",
PANGO2_TYPE_FONT_MAP,
G_PARAM_READWRITE);
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", "", "",
PANGO2_TYPE_FONT_DESCRIPTION,
G_PARAM_READWRITE);
properties[PROP_SIZE] =
g_param_spec_float ("size", "", "",
0., 100., 12.,
G_PARAM_READWRITE);
properties[PROP_VARIATIONS] =
g_param_spec_string ("variations", "", "",
"",
G_PARAM_READWRITE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/infoview.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), InfoView, info);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "infoview");
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define INFO_VIEW_TYPE (info_view_get_type ())
#define INFO_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INFO_VIEW_TYPE, InfoView))
typedef struct _InfoView InfoView;
typedef struct _InfoViewClass InfoViewClass;
GType info_view_get_type (void);
-23
View File
@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="InfoView" parent="GtkWidget">
<style>
<class name="view"/>
</style>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>
<object class="GtkGrid" id="info">
<style>
<class name="content"/>
</style>
</object>
</child>
</object>
</child>
</template>
</interface>
-334
View File
@@ -1,334 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <errno.h>
#include <locale.h>
#include <sys/stat.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <hb-ot.h>
#include "language-names.h"
#ifdef G_OS_WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#ifndef ISO_CODES_PREFIX
#define ISO_CODES_PREFIX "/usr"
#endif
#define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes"
#define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale"
#endif
static GHashTable *language_map;
#ifdef G_OS_WIN32
/* if we are using native Windows use native Windows API for language names */
static BOOL CALLBACK
get_win32_all_locales_scripts (LPWSTR locale_w, DWORD flags, LPARAM param)
{
wchar_t *langname_w = NULL;
wchar_t locale_abbrev_w[9];
gchar *langname, *locale_abbrev, *locale, *p;
gint i;
const LCTYPE iso639_lctypes[] = { LOCALE_SISO639LANGNAME, LOCALE_SISO639LANGNAME2 };
GHashTable *ht_scripts_langs = (GHashTable *) param;
Pango2Language *lang;
gint langname_size, locale_abbrev_size;
langname_size = GetLocaleInfoEx (locale_w, LOCALE_SLOCALIZEDDISPLAYNAME, langname_w, 0);
if (langname_size == 0)
return FALSE;
langname_w = g_new0 (wchar_t, langname_size);
if (langname_size == 0)
return FALSE;
GetLocaleInfoEx (locale_w, LOCALE_SLOCALIZEDDISPLAYNAME, langname_w, langname_size);
langname = g_utf16_to_utf8 (langname_w, -1, NULL, NULL, NULL);
locale = g_utf16_to_utf8 (locale_w, -1, NULL, NULL, NULL);
p = strchr (locale, '-');
lang = pango2_language_from_string (locale);
if (g_hash_table_lookup (ht_scripts_langs, lang) == NULL)
g_hash_table_insert (ht_scripts_langs, lang, langname);
/*
* Track 3+-letter ISO639-2/3 language codes as well (these have a max length of 9 including terminating NUL)
* ISO639-2: iso639_lctypes[0] = LOCALE_SISO639LANGNAME
* ISO639-3: iso639_lctypes[1] = LOCALE_SISO639LANGNAME2
*/
for (i = 0; i < 2; i++)
{
locale_abbrev_size = GetLocaleInfoEx (locale_w, iso639_lctypes[i], locale_abbrev_w, 0);
if (locale_abbrev_size > 0)
{
GetLocaleInfoEx (locale_w, iso639_lctypes[i], locale_abbrev_w, locale_abbrev_size);
locale_abbrev = g_utf16_to_utf8 (locale_abbrev_w, -1, NULL, NULL, NULL);
lang = pango2_language_from_string (locale_abbrev);
if (g_hash_table_lookup (ht_scripts_langs, lang) == NULL)
g_hash_table_insert (ht_scripts_langs, lang, langname);
g_free (locale_abbrev);
}
}
g_free (locale);
g_free (langname_w);
return TRUE;
}
#else /* non-Windows */
static char *
get_first_item_in_semicolon_list (const char *list)
{
char **items;
char *item;
items = g_strsplit (list, "; ", 2);
item = g_strdup (items[0]);
g_strfreev (items);
return item;
}
static char *
capitalize_utf8_string (const char *str)
{
char first[8] = { 0 };
if (!str)
return NULL;
g_unichar_to_utf8 (g_unichar_totitle (g_utf8_get_char (str)), first);
return g_strconcat (first, g_utf8_offset_to_pointer (str, 1), NULL);
}
static char *
get_display_name (const char *language)
{
const char *translated;
char *tmp;
char *name;
translated = dgettext ("iso_639", language);
tmp = get_first_item_in_semicolon_list (translated);
name = capitalize_utf8_string (tmp);
g_free (tmp);
return name;
}
static void
languages_parse_start_tag (GMarkupParseContext *ctx,
const char *element_name,
const char **attr_names,
const char **attr_values,
gpointer user_data,
GError **error)
{
const char *ccode_longB;
const char *ccode_longT;
const char *ccode;
const char *ccode_id;
const char *lang_name;
char *display_name;
const char *long_names[] = {
"Dogri",
"Greek, Modern",
"Interlingua",
"Konkani",
"Tonga",
"Turkish, Ottoman",
};
int i;
if (!(g_str_equal (element_name, "iso_639_entry") ||
g_str_equal (element_name, "iso_639_3_entry")) ||
attr_names == NULL ||
attr_values == NULL)
return;
ccode = NULL;
ccode_longB = NULL;
ccode_longT = NULL;
ccode_id = NULL;
lang_name = NULL;
while (*attr_names && *attr_values)
{
if (g_str_equal (*attr_names, "iso_639_1_code"))
{
if (**attr_values)
{
if (strlen (*attr_values) != 2)
return;
ccode = *attr_values;
}
}
else if (g_str_equal (*attr_names, "iso_639_2B_code"))
{
if (**attr_values)
{
if (strlen (*attr_values) != 3)
return;
ccode_longB = *attr_values;
}
}
else if (g_str_equal (*attr_names, "iso_639_2T_code"))
{
if (**attr_values)
{
if (strlen (*attr_values) != 3)
return;
ccode_longT = *attr_values;
}
}
else if (g_str_equal (*attr_names, "id"))
{
if (**attr_values)
{
if (strlen (*attr_values) != 2 &&
strlen (*attr_values) != 3)
return;
ccode_id = *attr_values;
}
}
else if (g_str_equal (*attr_names, "name"))
{
lang_name = *attr_values;
}
++attr_names;
++attr_values;
}
if (lang_name == NULL)
return;
display_name = get_display_name (lang_name);
/* Fix up some egregious names */
for (i = 0; i < G_N_ELEMENTS (long_names); i++)
{
if (g_str_has_prefix (display_name, long_names[i]))
display_name[strlen (long_names[i])] = '\0';
}
if (ccode != NULL)
g_hash_table_insert (language_map,
pango2_language_from_string (ccode),
g_strdup (display_name));
if (ccode_longB != NULL)
g_hash_table_insert (language_map,
pango2_language_from_string (ccode_longB),
g_strdup (display_name));
if (ccode_longT != NULL)
g_hash_table_insert (language_map,
pango2_language_from_string (ccode_longT),
g_strdup (display_name));
if (ccode_id != NULL)
g_hash_table_insert (language_map,
pango2_language_from_string (ccode_id),
g_strdup (display_name));
g_free (display_name);
}
static void
languages_variant_init (const char *variant)
{
gboolean res;
gsize buf_len;
char *buf;
char *filename;
GError *error;
bindtextdomain (variant, ISO_CODES_LOCALESDIR);
bind_textdomain_codeset (variant, "UTF-8");
error = NULL;
filename = g_strconcat (ISO_CODES_DATADIR, "/", variant, ".xml", NULL);
res = g_file_get_contents (filename, &buf, &buf_len, &error);
if (res)
{
GMarkupParseContext *ctx = NULL;
GMarkupParser parser = { languages_parse_start_tag, NULL, NULL, NULL, NULL };
ctx = g_markup_parse_context_new (&parser, 0, NULL, NULL);
res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
g_free (ctx);
if (!res)
{
g_warning ("Failed to parse '%s': %s\n", filename, error->message);
g_error_free (error);
}
}
else
{
g_warning ("Failed to load '%s': %s\n", filename, error->message);
g_error_free (error);
}
g_free (filename);
g_free (buf);
}
#endif
static void
languages_init (void)
{
if (language_map)
return;
language_map = g_hash_table_new_full (NULL, NULL, NULL, g_free);
#ifdef G_OS_WIN32
g_return_if_fail (EnumSystemLocalesEx (&get_win32_all_locales_scripts, LOCALE_ALL, (LPARAM) language_map, NULL));
#else
languages_variant_init ("iso_639");
languages_variant_init ("iso_639_3");
#endif
}
const char *
get_language_name (Pango2Language *language)
{
languages_init ();
return (const char *) g_hash_table_lookup (language_map, language);
}
const char *
get_language_name_for_tag (guint32 tag)
{
hb_language_t lang;
const char *s;
lang = hb_ot_tag_to_language (tag);
s = hb_language_to_string (lang);
return get_language_name (pango2_language_from_string (s));
}
-13
View File
@@ -1,13 +0,0 @@
#ifndef LANGUAGE_NAMES_H
#define LANGUAGE_NAMES_H
#include <pango2/pango.h>
G_BEGIN_DECLS
const char * get_language_name (Pango2Language *language);
const char * get_language_name_for_tag (guint32 tag);
G_END_DECLS
#endif
-9
View File
@@ -1,9 +0,0 @@
#include <gtk/gtk.h>
#include <fontexplorerapp.h>
int
main (int argc, char *argv[])
{
return g_application_run (G_APPLICATION (font_explorer_app_new ()), argc, argv);
}
-35
View File
@@ -1,35 +0,0 @@
fontexplorer_sources = [
'fontcolors.c',
'fontcontrols.c',
'fontexplorerapp.c',
'fontexplorerwin.c',
'fontfeatures.c',
'fontvariations.c',
'glyphitem.c',
'glyphmodel.c',
'glyphsview.c',
'glyphview.c',
'infoview.c',
'language-names.c',
'main.c',
'plainview.c',
'rangeedit.c',
'samplechooser.c',
'sampleeditor.c',
'styleview.c',
'waterfallview.c',
]
fontexplorer_resources = gnome.compile_resources('fontexplorer_resources',
'fontexplorer.gresource.xml',
source_dir: '.',
)
executable('gtk4-font-explorer',
sources: [fontexplorer_sources, fontexplorer_resources],
c_args: common_cflags,
dependencies: [ libgtk_dep, demo_conf_h ],
include_directories: confinc,
link_args: extra_demo_ldflags,
install: true,
)
-343
View File
@@ -1,343 +0,0 @@
#include "plainview.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
#include "glyphitem.h"
#include "glyphmodel.h"
#include "glyphview.h"
enum {
PROP_FONT_MAP = 1,
PROP_FONT_DESC,
PROP_SIZE,
PROP_LETTERSPACING,
PROP_LINE_HEIGHT,
PROP_FOREGROUND,
PROP_BACKGROUND,
PROP_VARIATIONS,
PROP_FEATURES,
PROP_PALETTE,
PROP_SAMPLE_TEXT,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _PlainView
{
GtkWidget parent;
GtkLabel *content;
GtkScrolledWindow *swin;
Pango2FontMap *font_map;
Pango2FontDescription *font_desc;
float size;
char *variations;
char *features;
char *palette;
GQuark palette_quark;
int letterspacing;
float line_height;
GdkRGBA foreground;
GdkRGBA background;
GtkCssProvider *bg_provider;
char *sample_text;
};
struct _PlainViewClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(PlainView, plain_view, GTK_TYPE_WIDGET);
static void
plain_view_init (PlainView *self)
{
self->font_map = g_object_ref (pango2_font_map_get_default ());
self->font_desc = pango2_font_description_from_string ("sans 12");
self->size = 12.;
self->letterspacing = 0;
self->line_height = 1.;
self->variations = g_strdup ("");
self->features = g_strdup ("");
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
self->palette_quark = g_quark_from_string (self->palette);
self->foreground = (GdkRGBA){0., 0., 0., 1. };
self->background = (GdkRGBA){1., 1., 1., 1. };
self->sample_text = g_strdup ("Some sample text is better than other sample text");
gtk_widget_set_layout_manager (GTK_WIDGET (self),
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
gtk_widget_init_template (GTK_WIDGET (self));
self->bg_provider = gtk_css_provider_new ();
gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (self->content)),
GTK_STYLE_PROVIDER (self->bg_provider), 800);
}
static void
plain_view_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), PLAIN_VIEW_TYPE);
G_OBJECT_CLASS (plain_view_parent_class)->dispose (object);
}
static void
plain_view_finalize (GObject *object)
{
PlainView *self = PLAIN_VIEW (object);
g_clear_object (&self->font_map);
pango2_font_description_free (self->font_desc);
g_free (self->variations);
g_free (self->features);
g_free (self->palette);
G_OBJECT_CLASS (plain_view_parent_class)->finalize (object);
}
static void
update_view (PlainView *self)
{
Pango2FontDescription *desc;
Pango2AttrList *attrs;
char *fg, *bg, *css;
desc = pango2_font_description_copy_static (self->font_desc);
pango2_font_description_set_size (desc, 12 * PANGO2_SCALE);
pango2_font_description_set_variations (desc, self->variations);
attrs = pango2_attr_list_new ();
pango2_attr_list_insert (attrs, pango2_attr_font_desc_new (desc));
pango2_attr_list_insert (attrs, pango2_attr_size_new (self->size * PANGO2_SCALE));
pango2_attr_list_insert (attrs, pango2_attr_letter_spacing_new (self->letterspacing));
pango2_attr_list_insert (attrs, pango2_attr_line_height_new (self->line_height));
pango2_attr_list_insert (attrs, pango2_attr_foreground_new (&(Pango2Color){65535 * self->foreground.red,
65535 * self->foreground.green,
65535 * self->foreground.blue,
65535 * self->foreground.alpha}));
pango2_attr_list_insert (attrs, pango2_attr_font_features_new (self->features));
pango2_attr_list_insert (attrs, pango2_attr_palette_new (self->palette));
pango2_font_description_free (desc);
gtk_label_set_label (self->content, self->sample_text);
gtk_label_set_attributes (self->content, attrs);
pango2_attr_list_unref (attrs);
fg = gdk_rgba_to_string (&self->foreground);
bg = gdk_rgba_to_string (&self->background);
css = g_strdup_printf (".content { caret-color: %s; background-color: %s; }", fg, bg);
gtk_css_provider_load_from_data (self->bg_provider, css, strlen (css));
g_free (css);
g_free (fg);
g_free (bg);
}
static void
plain_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
PlainView *self = PLAIN_VIEW (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_set_object (&self->font_map, g_value_get_object (value));
gtk_widget_set_font_map (GTK_WIDGET (self->content), self->font_map);
break;
case PROP_FONT_DESC:
pango2_font_description_free (self->font_desc);
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
break;
case PROP_SIZE:
self->size = g_value_get_float (value);
break;
case PROP_LETTERSPACING:
self->letterspacing = g_value_get_int (value);
break;
case PROP_LINE_HEIGHT:
self->line_height = g_value_get_float (value);
break;
case PROP_FOREGROUND:
self->foreground = *(GdkRGBA *)g_value_get_boxed (value);
break;
case PROP_BACKGROUND:
self->background = *(GdkRGBA *)g_value_get_boxed (value);
break;
case PROP_VARIATIONS:
g_free (self->variations);
self->variations = g_strdup (g_value_get_string (value));
break;
case PROP_FEATURES:
g_free (self->features);
self->features = g_strdup (g_value_get_string (value));
break;
case PROP_PALETTE:
g_free (self->palette);
self->palette = g_strdup (g_value_get_string (value));
self->palette_quark = g_quark_from_string (self->palette);
break;
case PROP_SAMPLE_TEXT:
g_free (self->sample_text);
self->sample_text = g_strdup (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
update_view (self);
}
static void
plain_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
PlainView *self = PLAIN_VIEW (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_value_set_object (value, self->font_map);
break;
case PROP_FONT_DESC:
g_value_set_boxed (value, self->font_desc);
break;
case PROP_SIZE:
g_value_set_float (value, self->size);
break;
case PROP_LETTERSPACING:
g_value_set_int (value, self->letterspacing);
break;
case PROP_LINE_HEIGHT:
g_value_set_float (value, self->line_height);
break;
case PROP_FOREGROUND:
g_value_set_boxed (value, &self->foreground);
break;
case PROP_BACKGROUND:
g_value_set_boxed (value, &self->background);
break;
case PROP_VARIATIONS:
g_value_set_string (value, self->variations);
break;
case PROP_FEATURES:
g_value_set_string (value, self->features);
break;
case PROP_PALETTE:
g_value_set_string (value, self->palette);
break;
case PROP_SAMPLE_TEXT:
g_value_set_string (value, self->sample_text);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
plain_view_class_init (PlainViewClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = plain_view_dispose;
object_class->finalize = plain_view_finalize;
object_class->get_property = plain_view_get_property;
object_class->set_property = plain_view_set_property;
properties[PROP_FONT_MAP] =
g_param_spec_object ("font-map", "", "",
PANGO2_TYPE_FONT_MAP,
G_PARAM_READWRITE);
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", "", "",
PANGO2_TYPE_FONT_DESCRIPTION,
G_PARAM_READWRITE);
properties[PROP_SIZE] =
g_param_spec_float ("size", "", "",
0., 100., 12.,
G_PARAM_READWRITE);
properties[PROP_LETTERSPACING] =
g_param_spec_int ("letterspacing", "", "",
-G_MAXINT, G_MAXINT, 0,
G_PARAM_READWRITE);
properties[PROP_LINE_HEIGHT] =
g_param_spec_float ("line-height", "", "",
0., 100., 1.,
G_PARAM_READWRITE);
properties[PROP_FOREGROUND] =
g_param_spec_boxed ("foreground", "", "",
GDK_TYPE_RGBA,
G_PARAM_READWRITE);
properties[PROP_BACKGROUND] =
g_param_spec_boxed ("background", "", "",
GDK_TYPE_RGBA,
G_PARAM_READWRITE);
properties[PROP_VARIATIONS] =
g_param_spec_string ("variations", "", "",
"",
G_PARAM_READWRITE);
properties[PROP_FEATURES] =
g_param_spec_string ("features", "", "",
"",
G_PARAM_READWRITE);
properties[PROP_PALETTE] =
g_param_spec_string ("palette", "", "",
PANGO2_COLOR_PALETTE_DEFAULT,
G_PARAM_READWRITE);
properties[PROP_SAMPLE_TEXT] =
g_param_spec_string ("sample-text", "", "",
"",
G_PARAM_READWRITE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/plainview.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), PlainView, swin);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), PlainView, content);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "plainview");
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define PLAIN_VIEW_TYPE (plain_view_get_type ())
#define PLAIN_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLAIN_VIEW_TYPE, PlainView))
typedef struct _PlainView PlainView;
typedef struct _PlainViewClass PlainViewClass;
GType plain_view_get_type (void);
-32
View File
@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="PlainView" parent="GtkWidget">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>
<object class="GtkScrolledWindow" id="swin">
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<style>
<class name="view"/>
</style>
<child>
<object class="GtkLabel" id="content">
<property name="label">Content</property>
<property name="wrap">1</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="halign">fill</property>
<property name="valign">fill</property>
<style>
<class name="content"/>
</style>
</object>
</child>
</object>
</child>
</template>
</interface>
-174
View File
@@ -1,174 +0,0 @@
#include "rangeedit.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
enum {
PROP_ADJUSTMENT = 1,
PROP_DEFAULT_VALUE,
PROP_N_CHARS,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _RangeEdit
{
GtkWidget parent;
GtkAdjustment *adjustment;
GtkScale *scale;
GtkEntry *entry;
double default_value;
int n_chars;
};
struct _RangeEditClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (RangeEdit, range_edit, GTK_TYPE_WIDGET);
static void
range_edit_init (RangeEdit *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
}
static void
range_edit_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), RANGE_EDIT_TYPE);
G_OBJECT_CLASS (range_edit_parent_class)->dispose (object);
}
static void
range_edit_get_property (GObject *object,
unsigned int prop_id,
GValue *value,
GParamSpec *pspec)
{
RangeEdit *self = RANGE_EDIT (object);
switch (prop_id)
{
case PROP_ADJUSTMENT:
g_value_set_object (value, self->adjustment);
break;
case PROP_DEFAULT_VALUE:
g_value_set_double (value, self->default_value);
break;
case PROP_N_CHARS:
g_value_set_int (value, self->n_chars);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
adjustment_changed (GtkAdjustment *adjustment,
RangeEdit *self)
{
char *str;
str = g_strdup_printf ("%.1f", gtk_adjustment_get_value (adjustment));
gtk_editable_set_text (GTK_EDITABLE (self->entry), str);
g_free (str);
}
static void
range_edit_set_property (GObject *object,
unsigned int prop_id,
const GValue *value,
GParamSpec *pspec)
{
RangeEdit *self = RANGE_EDIT (object);
switch (prop_id)
{
case PROP_ADJUSTMENT:
g_set_object (&self->adjustment, g_value_get_object (value));
g_signal_connect (self->adjustment, "value-changed", G_CALLBACK (adjustment_changed), self);
adjustment_changed (self->adjustment, self);
break;
case PROP_DEFAULT_VALUE:
self->default_value = g_value_get_double (value);
break;
case PROP_N_CHARS:
self->n_chars = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
range_edit_constructed (GObject *object)
{
RangeEdit *self = RANGE_EDIT (object);
gtk_scale_add_mark (self->scale, self->default_value, GTK_POS_TOP, NULL);
}
static void
entry_activated (GtkEntry *entry,
RangeEdit *self)
{
double value;
char *err = NULL;
value = g_strtod (gtk_editable_get_text (GTK_EDITABLE (entry)), &err);
if (err != NULL)
gtk_adjustment_set_value (self->adjustment, value);
}
static void
range_edit_class_init (RangeEditClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = range_edit_dispose;
object_class->get_property = range_edit_get_property;
object_class->set_property = range_edit_set_property;
object_class->constructed = range_edit_constructed;
properties[PROP_ADJUSTMENT] =
g_param_spec_object ("adjustment", "", "",
GTK_TYPE_ADJUSTMENT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_DEFAULT_VALUE] =
g_param_spec_double ("default-value", "", "",
-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_N_CHARS] =
g_param_spec_int ("n-chars", "", "",
0, G_MAXINT, 10,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/rangeedit.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), RangeEdit, scale);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), RangeEdit, entry);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), entry_activated);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "rangeedit");
}
RangeEdit *
range_edit_new (void)
{
return g_object_new (RANGE_EDIT_TYPE, NULL);
}
-15
View File
@@ -1,15 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define RANGE_EDIT_TYPE (range_edit_get_type ())
#define RANGE_EDIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RANGE_EDIT_TYPE, RangeEdit))
typedef struct _RangeEdit RangeEdit;
typedef struct _RangeEditClass RangeEditClass;
GType range_edit_get_type (void);
RangeEdit * range_edit_new (void);
-24
View File
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="RangeEdit" parent="GtkWidget">
<property name="layout-manager">
<object class="GtkBoxLayout">
<property name="spacing">10</property>
</object>
</property>
<child>
<object class="GtkScale" id="scale">
<property name="orientation">horizontal</property>
<property name="hexpand">1</property>
<property name="adjustment" bind-source="RangeEdit" bind-flags="sync-create"/>
</object>
</child>
<child>
<object class="GtkEntry" id="entry">
<property name="width-chars" bind-source="RangeEdit" bind-property="n-chars" bind-flags="sync-create"/>
<property name="max-width-chars" bind-source="RangeEdit" bind-property="n-chars" bind-flags="sync-create"/>
<signal name="activate" handler="entry_activated"/>
</object>
</child>
</template>
</interface>
-163
View File
@@ -1,163 +0,0 @@
#include "samplechooser.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
enum {
PROP_SAMPLE_TEXT = 1,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _SampleChooser
{
GtkWidget parent;
int sample;
const char *sample_text;
};
struct _SampleChooserClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(SampleChooser, sample_chooser, GTK_TYPE_WIDGET);
static const char *pangrams[] = {
"The quick brown fox jumps over the lazy dog.",
"Waltz, bad nymph, for quick jigs vex.",
"Quick zephyrs blow, vexing daft Jim.",
"Crazy Fredrick bought many very exquisite opal jewels.",
"Jaded zombies acted quaintly but kept driving their oxen forward.",
};
static const char *paragraphs[] = {
"Grumpy wizards make toxic brew for the evil Queen and Jack. A quick movement of the enemy will jeopardize six gunboats. The job of waxing linoleum frequently peeves chintzy kids. My girl wove six dozen plaid jackets before she quit. Twelve ziggurats quickly jumped a finch box.",
" Разъяренный чтец эгоистично бьёт пятью жердями шустрого фехтовальщика. Наш банк вчера же выплатил Ф.Я. Эйхгольду комиссию за ценные вещи. Эх, чужак, общий съём цен шляп (юфть) – вдрызг! В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!",
"Τάχιστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός",
};
static const char *alphabets[] = {
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"0123456789",
"!@#$%^&*()?",
};
static const char *titles[] = {
"From My Cold Dead Hands",
"From Afar Upon the Back of a Tiger",
"Spontaneous Apple Creation",
"Big Bizness (Screwed & Chopped)",
"Pizza Shop Extended",
"Good News & Bad News",
};
static void
next_pangram (GtkButton *button,
SampleChooser *self)
{
self->sample++;
self->sample_text = pangrams[self->sample % G_N_ELEMENTS (pangrams)];
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
}
static void
next_paragraph (GtkButton *button,
SampleChooser *self)
{
self->sample++;
self->sample_text = paragraphs[self->sample % G_N_ELEMENTS (paragraphs)];
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
}
static void
next_alphabet (GtkButton *button,
SampleChooser *self)
{
self->sample++;
self->sample_text = alphabets[self->sample % G_N_ELEMENTS (alphabets)];
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
}
static void
next_title (GtkButton *button,
SampleChooser *self)
{
self->sample++;
self->sample_text = titles[self->sample % G_N_ELEMENTS (titles)];
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
}
static void
sample_chooser_init (SampleChooser *self)
{
self->sample_text = "Boring sample text";
gtk_widget_init_template (GTK_WIDGET (self));
}
static void
sample_chooser_dispose (GObject *object)
{
GtkWidget *child;
gtk_widget_clear_template (GTK_WIDGET (object), SAMPLE_CHOOSER_TYPE);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (object))) != NULL)
gtk_widget_unparent (child);
G_OBJECT_CLASS (sample_chooser_parent_class)->dispose (object);
}
static void
sample_chooser_get_property (GObject *object,
unsigned int prop_id,
GValue *value,
GParamSpec *pspec)
{
SampleChooser *self = SAMPLE_CHOOSER (object);
switch (prop_id)
{
case PROP_SAMPLE_TEXT:
g_value_set_string (value, self->sample_text);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sample_chooser_class_init (SampleChooserClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = sample_chooser_dispose;
object_class->get_property = sample_chooser_get_property;
properties[PROP_SAMPLE_TEXT] =
g_param_spec_string ("sample-text", "", "",
"",
G_PARAM_READABLE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/samplechooser.ui");
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), next_pangram);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), next_paragraph);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), next_alphabet);
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), next_title);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "samplechooser");
}
SampleChooser *
sample_chooser_new (void)
{
return g_object_new (SAMPLE_CHOOSER_TYPE, NULL);
}
-15
View File
@@ -1,15 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define SAMPLE_CHOOSER_TYPE (sample_chooser_get_type ())
#define SAMPLE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SAMPLE_CHOOSER_TYPE, SampleChooser))
typedef struct _SampleChooser SampleChooser;
typedef struct _SampleChooserClass SampleChooserClass;
GType sample_chooser_get_type (void);
SampleChooser * sample_chooser_new (void);
-46
View File
@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="SampleChooser" parent="GtkWidget">
<property name="layout-manager"><object class="GtkGridLayout"/></property>
<child>
<object class="GtkButton">
<property name="label">Pangram</property>
<signal name="clicked" handler="next_pangram"/>
<layout>
<property name="row">0</property>
<property name="column">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Paragraph</property>
<signal name="clicked" handler="next_paragraph"/>
<layout>
<property name="row">0</property>
<property name="column">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Alphabet</property>
<signal name="clicked" handler="next_alphabet"/>
<layout>
<property name="row">1</property>
<property name="column">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Title</property>
<signal name="clicked" handler="next_title"/>
<layout>
<property name="row">1</property>
<property name="column">1</property>
</layout>
</object>
</child>
</template>
</interface>
-162
View File
@@ -1,162 +0,0 @@
#include "sampleeditor.h"
#include <gtk/gtk.h>
enum {
PROP_SAMPLE_TEXT = 1,
PROP_EDITING,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _SampleEditor
{
GtkWidget parent;
GtkTextView *edit;
char *sample_text;
gboolean editing;
};
struct _SampleEditorClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(SampleEditor, sample_editor, GTK_TYPE_WIDGET);
static void
sample_editor_init (SampleEditor *self)
{
self->sample_text = g_strdup ("Some sample text is better than other sample text");
self->editing = FALSE;
gtk_widget_set_layout_manager (GTK_WIDGET (self),
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
gtk_widget_init_template (GTK_WIDGET (self));
}
static void
sample_editor_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), SAMPLE_EDITOR_TYPE);
G_OBJECT_CLASS (sample_editor_parent_class)->dispose (object);
}
static void
sample_editor_finalize (GObject *object)
{
SampleEditor *self = SAMPLE_EDITOR (object);
g_free (self->sample_text);
G_OBJECT_CLASS (sample_editor_parent_class)->finalize (object);
}
static void
update_editing (SampleEditor *self,
gboolean editing)
{
GtkTextBuffer *buffer;
if (self->editing == editing)
return;
self->editing = editing;
buffer = gtk_text_view_get_buffer (self->edit);
if (self->editing)
{
gtk_text_buffer_set_text (buffer, self->sample_text, -1);
gtk_widget_grab_focus (GTK_WIDGET (self->edit));
}
else
{
GtkTextIter start, end;
g_free (self->sample_text);
gtk_text_buffer_get_bounds (buffer, &start, &end);
self->sample_text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
}
}
static void
sample_editor_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SampleEditor *self = SAMPLE_EDITOR (object);
switch (prop_id)
{
case PROP_SAMPLE_TEXT:
g_free (self->sample_text);
self->sample_text = g_strdup (g_value_get_string (value));
break;
case PROP_EDITING:
update_editing (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sample_editor_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SampleEditor *self = SAMPLE_EDITOR (object);
switch (prop_id)
{
case PROP_SAMPLE_TEXT:
g_value_set_string (value, self->sample_text);
break;
case PROP_EDITING:
g_value_set_boolean (value, self->editing);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sample_editor_class_init (SampleEditorClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = sample_editor_dispose;
object_class->finalize = sample_editor_finalize;
object_class->get_property = sample_editor_get_property;
object_class->set_property = sample_editor_set_property;
properties[PROP_SAMPLE_TEXT] =
g_param_spec_string ("sample-text", "", "",
"",
G_PARAM_READWRITE);
properties[PROP_EDITING] =
g_param_spec_boolean ("editing", "", "",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/sampleeditor.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), SampleEditor, edit);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "sampleeditor");
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define SAMPLE_EDITOR_TYPE (sample_editor_get_type ())
#define SAMPLE_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SAMPLE_EDITOR_TYPE, SampleEditor))
typedef struct _SampleEditor SampleEditor;
typedef struct _SampleEditorClass SampleEditorClass;
GType sample_editor_get_type (void);
-25
View File
@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="SampleEditor" parent="GtkWidget">
<style>
<class name="view"/>
</style>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>
<object class="GtkTextView" id="edit">
<property name="wrap-mode">word-char</property>
<property name="left-margin">20</property>
<property name="right-margin">20</property>
<property name="top-margin">20</property>
<property name="bottom-margin">20</property>
</object>
</child>
</object>
</child>
</template>
</interface>
-506
View File
@@ -1,506 +0,0 @@
#include "styleview.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
#include "glyphitem.h"
#include "glyphmodel.h"
#include "glyphview.h"
enum {
PROP_FONT_MAP = 1,
PROP_FONT_DESC,
PROP_SIZE,
PROP_LETTERSPACING,
PROP_LINE_HEIGHT,
PROP_FOREGROUND,
PROP_BACKGROUND,
PROP_VARIATIONS,
PROP_FEATURES,
PROP_PALETTE,
PROP_SAMPLE_TEXT,
PROP_HAS_STYLES,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _StyleView
{
GtkWidget parent;
GtkLabel *content;
GtkScrolledWindow *swin;
Pango2FontMap *font_map;
Pango2FontDescription *font_desc;
float size;
char *variations;
char *features;
char *palette;
GQuark palette_quark;
int letterspacing;
float line_height;
GdkRGBA foreground;
GdkRGBA background;
GtkCssProvider *bg_provider;
char *sample_text;
gboolean has_styles;
};
struct _StyleViewClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(StyleView, style_view, GTK_TYPE_WIDGET);
static void
style_view_init (StyleView *self)
{
self->font_map = g_object_ref (pango2_font_map_get_default ());
self->font_desc = pango2_font_description_from_string ("sans 12");
self->size = 12.;
self->letterspacing = 0;
self->line_height = 1.;
self->variations = g_strdup ("");
self->features = g_strdup ("");
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
self->palette_quark = g_quark_from_string (self->palette);
self->foreground = (GdkRGBA){0., 0., 0., 1. };
self->background = (GdkRGBA){1., 1., 1., 1. };
self->sample_text = g_strdup ("Some sample text is better than other sample text");
self->has_styles = FALSE;
gtk_widget_set_layout_manager (GTK_WIDGET (self),
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
gtk_widget_init_template (GTK_WIDGET (self));
self->bg_provider = gtk_css_provider_new ();
gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (self->content)),
GTK_STYLE_PROVIDER (self->bg_provider), 800);
}
static void
style_view_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), STYLE_VIEW_TYPE);
G_OBJECT_CLASS (style_view_parent_class)->dispose (object);
}
static void
style_view_finalize (GObject *object)
{
StyleView *self = STYLE_VIEW (object);
g_clear_object (&self->font_map);
pango2_font_description_free (self->font_desc);
g_free (self->variations);
g_free (self->features);
g_free (self->palette);
G_OBJECT_CLASS (style_view_parent_class)->finalize (object);
}
static Pango2Font *
get_font (StyleView *self)
{
Pango2Context *context;
Pango2FontDescription *desc;
Pango2Font *font;
context = pango2_context_new_with_font_map (self->font_map);
desc = pango2_font_description_copy_static (self->font_desc);
pango2_font_description_set_variations (desc, self->variations);
pango2_font_description_set_size (desc, self->size * PANGO2_SCALE);
font = pango2_context_load_font (context, desc);
pango2_font_description_free (desc);
g_object_unref (context);
return font;
}
static void
update_has_styles (StyleView *self)
{
Pango2Font *font = get_font (self);
hb_face_t *hb_face = hb_font_get_face (pango2_font_get_hb_font (font));
gboolean has_styles;
has_styles = hb_ot_var_get_named_instance_count (hb_face) > 0;
g_object_unref (font);
if (self->has_styles == has_styles)
return;
self->has_styles = has_styles;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HAS_STYLES]);
}
static int
measure_names (Pango2Context *context,
hb_face_t *hb_face)
{
Pango2Layout *layout;
Pango2FontDescription *desc;
GString *str;
int width, height;
layout = pango2_layout_new (context);
desc = pango2_font_description_from_string ("Cantarell Regular 12");
pango2_layout_set_font_description (layout, desc);
pango2_font_description_free (desc);
str = g_string_new ("");
for (int i = 0; i < hb_ot_var_get_named_instance_count (hb_face); i++)
{
hb_ot_name_id_t name_id;
char name[20];
unsigned int name_len = 20;
name_id = hb_ot_var_named_instance_get_subfamily_name_id (hb_face, i);
hb_ot_name_get_utf8 (hb_face, name_id, HB_LANGUAGE_INVALID, &name_len, name);
g_string_append_printf (str, " %s\n", name);
}
pango2_layout_set_text (layout, str->str, -1);
pango2_lines_get_size (pango2_layout_get_lines (layout), &width, &height);
g_string_free (str, TRUE);
g_object_unref (layout);
return width;
}
static void
update_view (StyleView *self)
{
Pango2FontDescription *desc;
Pango2AttrList *attrs;
char *fg, *bg, *css;
GString *str;
int start, end, text_len;
Pango2Font *font = get_font (self);
hb_face_t *hb_face = hb_font_get_face (pango2_font_get_hb_font (font));
unsigned int n_axes;
float *coords = NULL;
hb_ot_var_axis_info_t *axes;
Pango2FontDescription *label_desc;
Pango2TabArray *tabs;
int width;
desc = pango2_font_description_copy_static (self->font_desc);
pango2_font_description_set_variations (desc, self->variations);
pango2_font_description_set_size (desc, self->size * PANGO2_SCALE);
attrs = pango2_attr_list_new ();
pango2_attr_list_insert (attrs, pango2_attr_font_desc_new (desc));
pango2_attr_list_insert (attrs, pango2_attr_letter_spacing_new (self->letterspacing));
pango2_attr_list_insert (attrs, pango2_attr_line_height_new (self->line_height));
pango2_attr_list_insert (attrs, pango2_attr_foreground_new (&(Pango2Color){65535 * self->foreground.red,
65535 * self->foreground.green,
65535 * self->foreground.blue,
65535 * self->foreground.alpha}));
pango2_attr_list_insert (attrs, pango2_attr_font_features_new (self->features));
pango2_attr_list_insert (attrs, pango2_attr_palette_new (self->palette));
str = g_string_new ("");
start = 0;
text_len = strlen (self->sample_text);
n_axes = hb_ot_var_get_axis_count (hb_face);
axes = g_newa (hb_ot_var_axis_info_t, n_axes);
hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, axes);
coords = g_newa (float, n_axes);
label_desc = pango2_font_description_from_string ("Cantarell Regular 12");
width = measure_names (gtk_widget_get_pango_context (GTK_WIDGET (self->content)), hb_face);
tabs = pango2_tab_array_new (1, PANGO2_TAB_POSITIONS_DEFAULT);
pango2_tab_array_set_tab (tabs, 0, PANGO2_TAB_LEFT, width);
gtk_label_set_tabs (self->content, tabs);
pango2_tab_array_free (tabs);
for (int i = 0; i < hb_ot_var_get_named_instance_count (hb_face); i++)
{
unsigned int n_coords = n_axes;
Pango2Attribute *attr;
GString *variations;
hb_ot_name_id_t name_id;
char name[20];
unsigned int name_len = 20;
name_id = hb_ot_var_named_instance_get_subfamily_name_id (hb_face, i);
hb_ot_name_get_utf8 (hb_face, name_id, HB_LANGUAGE_INVALID, &name_len, name);
g_string_append_printf (str, "%s\t", name);
end = str->len;
attr = pango2_attr_font_desc_new (label_desc);
pango2_attribute_set_range (attr, start, end);
pango2_attr_list_insert (attrs, attr);
start = end;
hb_ot_var_named_instance_get_design_coords (hb_face, i, &n_coords, coords);
variations = g_string_new ("");
for (int j = 0; j < n_axes; j++)
{
char buf[5] = { 0, };
if (variations->len > 0)
g_string_append_c (variations, ',');
hb_tag_to_string (axes[j].tag, buf);
g_string_append_printf (variations, "%s=%f", buf, coords[j]);
}
g_string_append (str, self->sample_text);
g_string_append (str, ""); /* Unicode line separator */
end = start + text_len + strlen ("");
pango2_font_description_set_variations (desc, variations->str);
g_string_free (variations, TRUE);
attr = pango2_attr_font_desc_new (desc);
pango2_attribute_set_range (attr, start, end);
pango2_attr_list_insert (attrs, attr);
start = end;
}
pango2_font_description_free (label_desc);
gtk_label_set_text (self->content, str->str);
gtk_label_set_attributes (self->content, attrs);
g_string_free (str, TRUE);
pango2_attr_list_unref (attrs);
pango2_font_description_free (desc);
fg = gdk_rgba_to_string (&self->foreground);
bg = gdk_rgba_to_string (&self->background);
css = g_strdup_printf (".content { caret-color: %s; background-color: %s; }", fg, bg);
gtk_css_provider_load_from_data (self->bg_provider, css, strlen (css));
g_free (css);
g_free (fg);
g_free (bg);
g_object_unref (font);
}
static void
style_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
StyleView *self = STYLE_VIEW (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_set_object (&self->font_map, g_value_get_object (value));
gtk_widget_set_font_map (GTK_WIDGET (self->content), self->font_map);
update_has_styles (self);
break;
case PROP_FONT_DESC:
pango2_font_description_free (self->font_desc);
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
update_has_styles (self);
break;
case PROP_SIZE:
self->size = g_value_get_float (value);
break;
case PROP_LETTERSPACING:
self->letterspacing = g_value_get_int (value);
break;
case PROP_LINE_HEIGHT:
self->line_height = g_value_get_float (value);
break;
case PROP_FOREGROUND:
self->foreground = *(GdkRGBA *)g_value_get_boxed (value);
break;
case PROP_BACKGROUND:
self->background = *(GdkRGBA *)g_value_get_boxed (value);
break;
case PROP_VARIATIONS:
g_free (self->variations);
self->variations = g_strdup (g_value_get_string (value));
break;
case PROP_FEATURES:
g_free (self->features);
self->features = g_strdup (g_value_get_string (value));
break;
case PROP_PALETTE:
g_free (self->palette);
self->palette = g_strdup (g_value_get_string (value));
self->palette_quark = g_quark_from_string (self->palette);
break;
case PROP_SAMPLE_TEXT:
g_free (self->sample_text);
self->sample_text = g_strdup (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
update_view (self);
}
static void
style_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
StyleView *self = STYLE_VIEW (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_value_set_object (value, self->font_map);
break;
case PROP_FONT_DESC:
g_value_set_boxed (value, self->font_desc);
break;
case PROP_SIZE:
g_value_set_float (value, self->size);
break;
case PROP_LETTERSPACING:
g_value_set_int (value, self->letterspacing);
break;
case PROP_LINE_HEIGHT:
g_value_set_float (value, self->line_height);
break;
case PROP_FOREGROUND:
g_value_set_boxed (value, &self->foreground);
break;
case PROP_BACKGROUND:
g_value_set_boxed (value, &self->background);
break;
case PROP_VARIATIONS:
g_value_set_string (value, self->variations);
break;
case PROP_FEATURES:
g_value_set_string (value, self->features);
break;
case PROP_PALETTE:
g_value_set_string (value, self->palette);
break;
case PROP_SAMPLE_TEXT:
g_value_set_string (value, self->sample_text);
break;
case PROP_HAS_STYLES:
g_value_set_boolean (value, self->has_styles);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
style_view_class_init (StyleViewClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = style_view_dispose;
object_class->finalize = style_view_finalize;
object_class->get_property = style_view_get_property;
object_class->set_property = style_view_set_property;
properties[PROP_FONT_MAP] =
g_param_spec_object ("font-map", "", "",
PANGO2_TYPE_FONT_MAP,
G_PARAM_READWRITE);
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", "", "",
PANGO2_TYPE_FONT_DESCRIPTION,
G_PARAM_READWRITE);
properties[PROP_SIZE] =
g_param_spec_float ("size", "", "",
0., 100., 12.,
G_PARAM_READWRITE);
properties[PROP_LETTERSPACING] =
g_param_spec_int ("letterspacing", "", "",
-G_MAXINT, G_MAXINT, 0,
G_PARAM_READWRITE);
properties[PROP_LINE_HEIGHT] =
g_param_spec_float ("line-height", "", "",
0., 100., 1.,
G_PARAM_READWRITE);
properties[PROP_FOREGROUND] =
g_param_spec_boxed ("foreground", "", "",
GDK_TYPE_RGBA,
G_PARAM_READWRITE);
properties[PROP_BACKGROUND] =
g_param_spec_boxed ("background", "", "",
GDK_TYPE_RGBA,
G_PARAM_READWRITE);
properties[PROP_VARIATIONS] =
g_param_spec_string ("variations", "", "",
"",
G_PARAM_READWRITE);
properties[PROP_FEATURES] =
g_param_spec_string ("features", "", "",
"",
G_PARAM_READWRITE);
properties[PROP_PALETTE] =
g_param_spec_string ("palette", "", "",
PANGO2_COLOR_PALETTE_DEFAULT,
G_PARAM_READWRITE);
properties[PROP_SAMPLE_TEXT] =
g_param_spec_string ("sample-text", "", "",
"",
G_PARAM_READWRITE);
properties[PROP_HAS_STYLES] =
g_param_spec_boolean ("has-styles", "", "",
FALSE,
G_PARAM_READABLE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/styleview.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), StyleView, swin);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), StyleView, content);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "styleview");
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define STYLE_VIEW_TYPE (style_view_get_type ())
#define STYLE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STYLE_VIEW_TYPE, StyleView))
typedef struct _StyleView StyleView;
typedef struct _StyleViewClass StyleViewClass;
GType style_view_get_type (void);
-31
View File
@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="StyleView" parent="GtkWidget">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<style>
<class name="view"/>
</style>
<child>
<object class="GtkScrolledWindow" id="swin">
<property name="hscrollbar-policy">automatic</property>
<property name="vscrollbar-policy">automatic</property>
<child>
<object class="GtkLabel" id="content">
<property name="label">Content</property>
<property name="wrap">0</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="halign">fill</property>
<property name="valign">fill</property>
<style>
<class name="content"/>
</style>
</object>
</child>
</object>
</child>
</template>
</interface>
-401
View File
@@ -1,401 +0,0 @@
#include "waterfallview.h"
#include <gtk/gtk.h>
#include <hb-ot.h>
#include "glyphitem.h"
#include "glyphmodel.h"
#include "glyphview.h"
enum {
PROP_FONT_MAP = 1,
PROP_FONT_DESC,
PROP_SIZE,
PROP_LETTERSPACING,
PROP_LINE_HEIGHT,
PROP_FOREGROUND,
PROP_BACKGROUND,
PROP_VARIATIONS,
PROP_FEATURES,
PROP_PALETTE,
PROP_SAMPLE_TEXT,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
struct _WaterfallView
{
GtkWidget parent;
GtkLabel *content;
GtkScrolledWindow *swin;
Pango2FontMap *font_map;
Pango2FontDescription *font_desc;
float size;
char *variations;
char *features;
char *palette;
GQuark palette_quark;
int letterspacing;
float line_height;
GdkRGBA foreground;
GdkRGBA background;
GtkCssProvider *bg_provider;
char *sample_text;
};
struct _WaterfallViewClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE(WaterfallView, waterfall_view, GTK_TYPE_WIDGET);
static void
waterfall_view_init (WaterfallView *self)
{
self->font_map = g_object_ref (pango2_font_map_get_default ());
self->font_desc = pango2_font_description_from_string ("sans 12");
self->size = 12.;
self->letterspacing = 0;
self->line_height = 1.;
self->variations = g_strdup ("");
self->features = g_strdup ("");
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
self->palette_quark = g_quark_from_string (self->palette);
self->foreground = (GdkRGBA){0., 0., 0., 1. };
self->background = (GdkRGBA){1., 1., 1., 1. };
self->sample_text = g_strdup ("Some sample text is better than other sample text");
gtk_widget_set_layout_manager (GTK_WIDGET (self),
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
gtk_widget_init_template (GTK_WIDGET (self));
self->bg_provider = gtk_css_provider_new ();
gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (self->content)),
GTK_STYLE_PROVIDER (self->bg_provider), 800);
}
static void
waterfall_view_dispose (GObject *object)
{
gtk_widget_clear_template (GTK_WIDGET (object), WATERFALL_VIEW_TYPE);
G_OBJECT_CLASS (waterfall_view_parent_class)->dispose (object);
}
static void
waterfall_view_finalize (GObject *object)
{
WaterfallView *self = WATERFALL_VIEW (object);
g_clear_object (&self->font_map);
pango2_font_description_free (self->font_desc);
g_free (self->variations);
g_free (self->features);
g_free (self->palette);
G_OBJECT_CLASS (waterfall_view_parent_class)->finalize (object);
}
static void
update_view (WaterfallView *self)
{
Pango2FontDescription *desc;
Pango2AttrList *attrs;
char *fg, *bg, *css;
GString *str;
int sizes[] = { 7, 8, 9, 10, 12, 14, 16, 20, 24, 30, 40, 50, 60, 70, 90, 120 };
int start, end, text_len;
Pango2TabArray *tabs;
desc = pango2_font_description_copy_static (self->font_desc);
pango2_font_description_set_size (desc, 12 * PANGO2_SCALE);
pango2_font_description_set_variations (desc, self->variations);
attrs = pango2_attr_list_new ();
pango2_attr_list_insert (attrs, pango2_attr_font_desc_new (desc));
pango2_attr_list_insert (attrs, pango2_attr_size_new (self->size * PANGO2_SCALE));
pango2_attr_list_insert (attrs, pango2_attr_line_height_new (self->line_height));
pango2_attr_list_insert (attrs, pango2_attr_letter_spacing_new (self->letterspacing));
pango2_attr_list_insert (attrs, pango2_attr_foreground_new (&(Pango2Color){65535 * self->foreground.red,
65535 * self->foreground.green,
65535 * self->foreground.blue,
65535 * self->foreground.alpha}));
pango2_attr_list_insert (attrs, pango2_attr_font_features_new (self->features));
pango2_attr_list_insert (attrs, pango2_attr_palette_new (self->palette));
pango2_font_description_free (desc);
tabs = pango2_tab_array_new (2, PANGO2_TAB_POSITIONS_SPACES);
pango2_tab_array_set_tab (tabs, 0, PANGO2_TAB_RIGHT, 5);
pango2_tab_array_set_tab (tabs, 1, PANGO2_TAB_LEFT, 8);
gtk_label_set_tabs (self->content, tabs);
pango2_tab_array_free (tabs);
str = g_string_new ("");
start = 0;
text_len = strlen (self->sample_text);
for (int i = 0; i < G_N_ELEMENTS (sizes); i++)
{
Pango2Attribute *attr;
g_string_append_printf (str, "\t%d\t", sizes[i]);
end = str->len;
attr = pango2_attr_family_new ("Cantarell");
pango2_attribute_set_range (attr, start, end);
pango2_attr_list_insert (attrs, attr);
attr = pango2_attr_weight_new (PANGO2_WEIGHT_NORMAL);
pango2_attribute_set_range (attr, start, end);
pango2_attr_list_insert (attrs, attr);
attr = pango2_attr_style_new (PANGO2_STYLE_NORMAL);
pango2_attribute_set_range (attr, start, end);
pango2_attr_list_insert (attrs, attr);
attr = pango2_attr_size_new (12 * PANGO2_SCALE);
pango2_attribute_set_range (attr, start, end);
pango2_attr_list_insert (attrs, attr);
attr = pango2_attr_font_features_new ("tnum=1");
pango2_attribute_set_range (attr, start, end);
pango2_attr_list_insert (attrs, attr);
attr = pango2_attr_letter_spacing_new (0);
pango2_attribute_set_range (attr, start, end);
pango2_attr_list_insert (attrs, attr);
start = end;
g_string_append (str, self->sample_text);
g_string_append (str, ""); /* Unicode line separator */
end = start + text_len + strlen ("");
attr = pango2_attr_size_new (sizes[i] * PANGO2_SCALE);
pango2_attribute_set_range (attr, start, end);
pango2_attr_list_insert (attrs, attr);
start = end;
}
gtk_label_set_text (self->content, str->str);
gtk_label_set_attributes (self->content, attrs);
g_string_free (str, TRUE);
pango2_attr_list_unref (attrs);
fg = gdk_rgba_to_string (&self->foreground);
bg = gdk_rgba_to_string (&self->background);
css = g_strdup_printf (".content { caret-color: %s; background-color: %s; }", fg, bg);
gtk_css_provider_load_from_data (self->bg_provider, css, strlen (css));
g_free (css);
g_free (fg);
g_free (bg);
}
static void
waterfall_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
WaterfallView *self = WATERFALL_VIEW (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_set_object (&self->font_map, g_value_get_object (value));
gtk_widget_set_font_map (GTK_WIDGET (self->content), self->font_map);
break;
case PROP_FONT_DESC:
pango2_font_description_free (self->font_desc);
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
break;
case PROP_SIZE:
self->size = g_value_get_float (value);
break;
case PROP_LETTERSPACING:
self->letterspacing = g_value_get_int (value);
break;
case PROP_LINE_HEIGHT:
self->line_height = g_value_get_float (value);
break;
case PROP_FOREGROUND:
self->foreground = *(GdkRGBA *)g_value_get_boxed (value);
break;
case PROP_BACKGROUND:
self->background = *(GdkRGBA *)g_value_get_boxed (value);
break;
case PROP_VARIATIONS:
g_free (self->variations);
self->variations = g_strdup (g_value_get_string (value));
break;
case PROP_FEATURES:
g_free (self->features);
self->features = g_strdup (g_value_get_string (value));
break;
case PROP_PALETTE:
g_free (self->palette);
self->palette = g_strdup (g_value_get_string (value));
self->palette_quark = g_quark_from_string (self->palette);
break;
case PROP_SAMPLE_TEXT:
g_free (self->sample_text);
self->sample_text = g_strdup (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
update_view (self);
}
static void
waterfall_view_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
WaterfallView *self = WATERFALL_VIEW (object);
switch (prop_id)
{
case PROP_FONT_MAP:
g_value_set_object (value, self->font_map);
break;
case PROP_FONT_DESC:
g_value_set_boxed (value, self->font_desc);
break;
case PROP_SIZE:
g_value_set_float (value, self->size);
break;
case PROP_LETTERSPACING:
g_value_set_int (value, self->letterspacing);
break;
case PROP_LINE_HEIGHT:
g_value_set_float (value, self->line_height);
break;
case PROP_FOREGROUND:
g_value_set_boxed (value, &self->foreground);
break;
case PROP_BACKGROUND:
g_value_set_boxed (value, &self->background);
break;
case PROP_VARIATIONS:
g_value_set_string (value, self->variations);
break;
case PROP_FEATURES:
g_value_set_string (value, self->features);
break;
case PROP_PALETTE:
g_value_set_string (value, self->palette);
break;
case PROP_SAMPLE_TEXT:
g_value_set_string (value, self->sample_text);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
waterfall_view_class_init (WaterfallViewClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->dispose = waterfall_view_dispose;
object_class->finalize = waterfall_view_finalize;
object_class->get_property = waterfall_view_get_property;
object_class->set_property = waterfall_view_set_property;
properties[PROP_FONT_MAP] =
g_param_spec_object ("font-map", "", "",
PANGO2_TYPE_FONT_MAP,
G_PARAM_READWRITE);
properties[PROP_FONT_DESC] =
g_param_spec_boxed ("font-desc", "", "",
PANGO2_TYPE_FONT_DESCRIPTION,
G_PARAM_READWRITE);
properties[PROP_SIZE] =
g_param_spec_float ("size", "", "",
0., 100., 12.,
G_PARAM_READWRITE);
properties[PROP_LETTERSPACING] =
g_param_spec_int ("letterspacing", "", "",
-G_MAXINT, G_MAXINT, 0,
G_PARAM_READWRITE);
properties[PROP_LINE_HEIGHT] =
g_param_spec_float ("line-height", "", "",
0., 100., 1.,
G_PARAM_READWRITE);
properties[PROP_FOREGROUND] =
g_param_spec_boxed ("foreground", "", "",
GDK_TYPE_RGBA,
G_PARAM_READWRITE);
properties[PROP_BACKGROUND] =
g_param_spec_boxed ("background", "", "",
GDK_TYPE_RGBA,
G_PARAM_READWRITE);
properties[PROP_VARIATIONS] =
g_param_spec_string ("variations", "", "",
"",
G_PARAM_READWRITE);
properties[PROP_FEATURES] =
g_param_spec_string ("features", "", "",
"",
G_PARAM_READWRITE);
properties[PROP_PALETTE] =
g_param_spec_string ("palette", "", "",
PANGO2_COLOR_PALETTE_DEFAULT,
G_PARAM_READWRITE);
properties[PROP_SAMPLE_TEXT] =
g_param_spec_string ("sample-text", "", "",
"",
G_PARAM_READWRITE);
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/fontexplorer/waterfallview.ui");
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), WaterfallView, swin);
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), WaterfallView, content);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "waterfallview");
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define WATERFALL_VIEW_TYPE (waterfall_view_get_type ())
#define WATERFALL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WATERFALL_VIEW_TYPE, WaterfallView))
typedef struct _WaterfallView WaterfallView;
typedef struct _WaterfallViewClass WaterfallViewClass;
GType waterfall_view_get_type (void);
-31
View File
@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="WaterfallView" parent="GtkWidget">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<style>
<class name="view"/>
</style>
<child>
<object class="GtkScrolledWindow" id="swin">
<property name="hscrollbar-policy">automatic</property>
<property name="vscrollbar-policy">automatic</property>
<child>
<object class="GtkLabel" id="content">
<property name="label">Content</property>
<property name="wrap">0</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="halign">fill</property>
<property name="valign">fill</property>
<style>
<class name="content"/>
</style>
</object>
</child>
</object>
</child>
</template>
</interface>
+10 -7
View File
@@ -341,13 +341,16 @@ do_clipboard (GtkWidget *do_widget)
GtkWidget *button;
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback (scope, copy_button_clicked);
gtk_builder_cscope_add_callback (scope, paste_button_clicked);
gtk_builder_cscope_add_callback (scope, source_changed_cb);
gtk_builder_cscope_add_callback (scope, text_changed_cb);
gtk_builder_cscope_add_callback (scope, open_file_cb);
gtk_builder_cscope_add_callback (scope, on_drop);
gtk_builder_cscope_add_callback (scope, drag_prepare);
gtk_builder_cscope_add_callback_symbols (GTK_BUILDER_CSCOPE (scope),
"copy_button_clicked", G_CALLBACK (copy_button_clicked),
"paste_button_clicked", G_CALLBACK (paste_button_clicked),
"source_changed_cb", G_CALLBACK (source_changed_cb),
"text_changed_cb", G_CALLBACK (text_changed_cb),
"open_file_cb", G_CALLBACK (open_file_cb),
"on_drop", G_CALLBACK (on_drop),
"drag_prepare", G_CALLBACK (drag_prepare),
NULL);
builder = gtk_builder_new ();
gtk_builder_set_scope (builder, scope);
gtk_builder_add_from_resource (builder, "/clipboard/clipboard.ui", NULL);
+4 -5
View File
@@ -260,13 +260,12 @@ mask_entry_set_background (MaskEntry *entry)
{
if (!g_regex_match_simple (entry->mask, gtk_editable_get_text (GTK_EDITABLE (entry)), 0, 0))
{
Pango2AttrList *attrs;
Pango2Color color = { 65535, 32767, 32767, 65535 };
PangoAttrList *attrs;
attrs = pango2_attr_list_new ();
pango2_attr_list_insert (attrs, pango2_attr_foreground_new (&color));
attrs = pango_attr_list_new ();
pango_attr_list_insert (attrs, pango_attr_foreground_new (65535, 32767, 32767));
gtk_entry_set_attributes (GTK_ENTRY (entry), attrs);
pango2_attr_list_unref (attrs);
pango_attr_list_unref (attrs);
return;
}
}
+2 -2
View File
@@ -84,11 +84,11 @@ do_css_basics (GtkWidget *do_widget)
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
"warning",
"underline", PANGO2_LINE_STYLE_SOLID,
"underline", PANGO_UNDERLINE_SINGLE,
NULL);
gtk_text_buffer_create_tag (text,
"error",
"underline", PANGO2_LINE_STYLE_DOTTED,
"underline", PANGO_UNDERLINE_ERROR,
NULL);
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
+2 -2
View File
@@ -122,11 +122,11 @@ do_css_multiplebgs (GtkWidget *do_widget)
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
"warning",
"underline", PANGO2_LINE_STYLE_SOLID,
"underline", PANGO_UNDERLINE_SINGLE,
NULL);
gtk_text_buffer_create_tag (text,
"error",
"underline", PANGO2_LINE_STYLE_DOTTED,
"underline", PANGO_UNDERLINE_ERROR,
NULL);
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
+2 -2
View File
@@ -93,11 +93,11 @@ do_css_pixbufs (GtkWidget *do_widget)
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
"warning",
"underline", PANGO2_LINE_STYLE_SOLID,
"underline", PANGO_UNDERLINE_SINGLE,
NULL);
gtk_text_buffer_create_tag (text,
"error",
"underline", PANGO2_LINE_STYLE_DOTTED,
"underline", PANGO_UNDERLINE_ERROR,
NULL);
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
+2 -2
View File
@@ -111,11 +111,11 @@ do_css_shadows (GtkWidget *do_widget)
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
"warning",
"underline", PANGO2_LINE_STYLE_SOLID,
"underline", PANGO_UNDERLINE_SINGLE,
NULL);
gtk_text_buffer_create_tag (text,
"error",
"underline", PANGO2_LINE_STYLE_DOTTED,
"underline", PANGO_UNDERLINE_ERROR,
NULL);
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
File diff suppressed because it is too large Load Diff
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define CURVE_TYPE_EDITOR (curve_editor_get_type ())
G_DECLARE_FINAL_TYPE (CurveEditor, curve_editor, CURVE, EDITOR, GtkWidget)
GtkWidget * curve_editor_new (void);
void curve_editor_set_edit (CurveEditor *self,
gboolean edit);
void curve_editor_set_path (CurveEditor *self,
GskPath *path);
GskPath * curve_editor_get_path (CurveEditor *self);
void curve_editor_set_stroke (CurveEditor *self,
GskStroke *stroke);
const GskStroke * curve_editor_get_stroke (CurveEditor *self);
void curve_editor_set_color (CurveEditor *self,
GdkRGBA *color);
const GdkRGBA * curve_editor_get_color (CurveEditor *self);
gboolean curve_editor_get_show_outline (CurveEditor *self);
void curve_editor_set_show_outline (CurveEditor *self,
gboolean show_outline);
G_END_DECLS
+272
View File
@@ -0,0 +1,272 @@
/* Path/Curve Editor
*
* This demo shows an elaborate curve editor that you would expect to find
* in a vector graphics editor. It is built on top of GTK's path APIs.
*/
#include <gtk/gtk.h>
#include "curve-editor.h"
static GskPath *
make_circle_path (void)
{
float w = 310;
float h = 310;
float cx = w / 2;
float cy = h / 2;
float pad = 20;
float r = (w - 2 * pad) / 2;
float k = 0.55228;
float kr = k * r;
GskPathBuilder *builder;
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder, cx, pad);
gsk_path_builder_curve_to (builder, cx + kr, pad,
w - pad, cy - kr,
w - pad, cy);
gsk_path_builder_curve_to (builder, w - pad, cy + kr,
cx + kr, h - pad,
cx, h - pad);
gsk_path_builder_curve_to (builder, cx - kr, h - pad,
pad, cy + kr,
pad, cy);
gsk_path_builder_curve_to (builder, pad, cy - kr,
cx - kr, pad,
cx, pad);
gsk_path_builder_close (builder);
return gsk_path_builder_free_to_path (builder);
}
static void
edit_changed (GtkToggleButton *button,
GParamSpec *pspec,
CurveEditor *editor)
{
curve_editor_set_edit (editor, gtk_toggle_button_get_active (button));
}
static void
reset (GtkButton *button,
CurveEditor *editor)
{
GskPath *path;
path = make_circle_path ();
curve_editor_set_path (editor, path);
gsk_path_unref (path);
}
static void
line_width_changed (GtkSpinButton *spin,
CurveEditor *editor)
{
GskStroke *stroke;
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
gsk_stroke_set_line_width (stroke, gtk_spin_button_get_value (spin));
curve_editor_set_stroke (editor, stroke);
gsk_stroke_free (stroke);
}
static void
cap_changed (GtkDropDown *combo,
GParamSpec *pspec,
CurveEditor *editor)
{
GskStroke *stroke;
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
gsk_stroke_set_line_cap (stroke, (GskLineCap)gtk_drop_down_get_selected (combo));
curve_editor_set_stroke (editor, stroke);
gsk_stroke_free (stroke);
}
static void
join_changed (GtkDropDown *combo,
GParamSpec *pspec,
CurveEditor *editor)
{
GskStroke *stroke;
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
gsk_stroke_set_line_join (stroke, (GskLineJoin)gtk_drop_down_get_selected (combo));
curve_editor_set_stroke (editor, stroke);
gsk_stroke_free (stroke);
}
static void
color_changed (GtkColorChooser *chooser,
GParamSpec *pspec,
CurveEditor *editor)
{
GdkRGBA color;
gtk_color_chooser_get_rgba (chooser, &color);
curve_editor_set_color (editor, &color);
}
static void
stroke_toggled (GtkCheckButton *button,
CurveEditor *editor)
{
curve_editor_set_show_outline (editor, gtk_check_button_get_active (button));
gtk_widget_queue_draw (GTK_WIDGET (editor));
}
static void
limit_changed (GtkSpinButton *spin,
CurveEditor *editor)
{
GskStroke *stroke;
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
gsk_stroke_set_miter_limit (stroke, gtk_spin_button_get_value (spin));
curve_editor_set_stroke (editor, stroke);
gsk_stroke_free (stroke);
}
static void
dashes_changed (GtkEntry *entry,
GParamSpec *spec,
CurveEditor *editor)
{
const char *text;
char **split;
GArray *dash;
GskStroke *stroke;
text = gtk_editable_get_text (GTK_EDITABLE (entry));
split = g_strsplit (text, " ", 0);
dash = g_array_new (FALSE, FALSE, sizeof (float));
for (int i = 0; split[i] != NULL; i++)
{
double d;
char *endp = 0;
d = g_strtod (split[i], &endp);
if (*endp == '\0')
g_array_append_vals (dash, (float[1]) { d }, 1);
}
g_strfreev (split);
stroke = gsk_stroke_copy (curve_editor_get_stroke (editor));
gsk_stroke_set_dash (stroke, (const float *)dash->data, dash->len);
curve_editor_set_stroke (editor, stroke);
gsk_stroke_free (stroke);
g_array_free (dash, TRUE);
}
GtkWidget *
do_curve (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *demo;
GtkWidget *edit_toggle;
GtkWidget *reset_button;
GtkWidget *titlebar;
GtkWidget *stroke_toggle;
GtkWidget *line_width_spin;
GtkWidget *stroke_button;
GtkWidget *popover;
GtkWidget *grid;
GtkWidget *cap_combo;
GtkWidget *join_combo;
GtkWidget *color_button;
GtkWidget *limit_spin;
GtkWidget *dash_entry;
if (!window)
{
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "Curve Editor");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
gtk_window_set_default_size (GTK_WINDOW (window), 315, 350);
edit_toggle = gtk_toggle_button_new ();
gtk_button_set_icon_name (GTK_BUTTON (edit_toggle), "document-edit-symbolic");
reset_button = gtk_button_new_from_icon_name ("edit-undo-symbolic");
stroke_button = gtk_menu_button_new ();
gtk_menu_button_set_icon_name (GTK_MENU_BUTTON (stroke_button), "open-menu-symbolic");
popover = gtk_popover_new ();
gtk_menu_button_set_popover (GTK_MENU_BUTTON (stroke_button), popover);
grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
gtk_popover_set_child (GTK_POPOVER (popover), grid);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Color:"), 0, 0, 1, 1);
color_button = gtk_color_button_new_with_rgba (&(GdkRGBA){ 0., 0., 0., 1.});
gtk_grid_attach (GTK_GRID (grid), color_button, 1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Line width:"), 0, 1, 1, 1);
line_width_spin = gtk_spin_button_new_with_range (1, 20, 1);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (line_width_spin), 1);
gtk_grid_attach (GTK_GRID (grid), line_width_spin, 1, 1, 1, 1);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Line cap:"), 0, 2, 1, 1);
cap_combo = gtk_drop_down_new_from_strings ((const char *[]){"Butt", "Round", "Square", NULL});
gtk_grid_attach (GTK_GRID (grid), cap_combo, 1, 2, 1, 1);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Line join:"), 0, 3, 1, 1);
join_combo = gtk_drop_down_new_from_strings ((const char *[]){"Miter", "Miter-clip", "Round", "Bevel", "Arcs", NULL});
gtk_grid_attach (GTK_GRID (grid), join_combo, 1, 3, 1, 1);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Miter limit:"), 0, 4, 1, 1);
limit_spin = gtk_spin_button_new_with_range (0, 10, 1);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (limit_spin), 1);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (limit_spin), 4);
gtk_grid_attach (GTK_GRID (grid), limit_spin, 1, 4, 1, 1);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Dashes:"), 0, 5, 1, 1);
dash_entry = gtk_entry_new ();
gtk_grid_attach (GTK_GRID (grid), dash_entry, 1, 5, 1, 1);
stroke_toggle = gtk_check_button_new_with_label ("Show outline");
gtk_grid_attach (GTK_GRID (grid), stroke_toggle, 1, 6, 1, 1);
titlebar = gtk_header_bar_new ();
gtk_header_bar_pack_start (GTK_HEADER_BAR (titlebar), edit_toggle);
gtk_header_bar_pack_start (GTK_HEADER_BAR (titlebar), reset_button);
gtk_header_bar_pack_start (GTK_HEADER_BAR (titlebar), stroke_button);
gtk_window_set_titlebar (GTK_WINDOW (window), titlebar);
demo = curve_editor_new ();
g_signal_connect (stroke_toggle, "toggled", G_CALLBACK (stroke_toggled), demo);
g_signal_connect (edit_toggle, "notify::active", G_CALLBACK (edit_changed), demo);
g_signal_connect (reset_button, "clicked", G_CALLBACK (reset), demo);
g_signal_connect (cap_combo, "notify::selected", G_CALLBACK (cap_changed), demo);
g_signal_connect (join_combo, "notify::selected", G_CALLBACK (join_changed), demo);
g_signal_connect (color_button, "notify::rgba", G_CALLBACK (color_changed), demo);
g_signal_connect (line_width_spin, "value-changed", G_CALLBACK (line_width_changed), demo);
g_signal_connect (limit_spin, "value-changed", G_CALLBACK (limit_changed), demo);
g_signal_connect (dash_entry, "notify::text", G_CALLBACK (dashes_changed), demo);
reset (NULL, CURVE_EDITOR (demo));
gtk_spin_button_set_value (GTK_SPIN_BUTTON (line_width_spin), 6);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (color_button), &(GdkRGBA) { 1, 0, 0, 1 });
gtk_drop_down_set_selected (GTK_DROP_DOWN (cap_combo), GSK_LINE_CAP_ROUND);
gtk_editable_set_text (GTK_EDITABLE (dash_entry), "0 8");
gtk_window_set_child (GTK_WINDOW (window), demo);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}
+14 -2
View File
@@ -128,6 +128,7 @@
<file>fishbowl.ui</file>
<file>gtkfishbowl.c</file>
<file>gtkfishbowl.h</file>
<file>tiger.node</file>
</gresource>
<gresource prefix="/frames">
<file>frames.ui</file>
@@ -250,6 +251,10 @@
<gresource prefix="/video-player">
<file>bbb.png</file>
</gresource>
<gresource prefix="/curve">
<file>curve-editor.c</file>
<file>curve-editor.h</file>
</gresource>
<gresource prefix="/sources">
<file>application_demo.c</file>
<file>assistant.c</file>
@@ -267,6 +272,7 @@
<file>css_pixbufs.c</file>
<file>css_shadows.c</file>
<file>cursors.c</file>
<file>curve.c</file>
<file>dialog.c</file>
<file>drawingarea.c</file>
<file>dropdown.c</file>
@@ -287,6 +293,7 @@
<file>gears.c</file>
<file>gestures.c</file>
<file>glarea.c</file>
<file>glyphs.c</file>
<file>gltransition.c</file>
<file>headerbar.c</file>
<file>hypertext.c</file>
@@ -325,11 +332,13 @@
<file>paintable_symbolic.c</file>
<file>panes.c</file>
<file>password_entry.c</file>
<file>path_fill.c</file>
<file>path_maze.c</file>
<file>path_text.c</file>
<file>peg_solitaire.c</file>
<file>pickers.c</file>
<file>printing.c</file>
<file>revealer.c</file>
<file>read_more.c</file>
<file>rotated_text.c</file>
<file>scale.c</file>
<file>search_entry.c</file>
@@ -376,7 +385,7 @@
<file>glarea-gles.vs.glsl</file>
</gresource>
<gresource prefix="/font_features">
<file>font_features.ui</file>
<file>font-features.ui</file>
<file>fontplane.c</file>
</gresource>
<gresource prefix="/spinbutton">
@@ -410,6 +419,9 @@
<gresource prefix="/fontrendering">
<file>fontrendering.ui</file>
</gresource>
<gresource prefix="/path_text">
<file>path_text.ui</file>
</gresource>
<gresource prefix="/org/gtk/Demo4">
<file>icons/16x16/actions/application-exit.png</file>
<file>icons/16x16/actions/document-new.png</file>
+10 -11
View File
@@ -263,7 +263,7 @@ drop_down_new_from_strings (const char *const *titles,
static char *
get_family_name (gpointer item)
{
return g_strdup (pango2_font_family_get_name (PANGO2_FONT_FAMILY (item)));
return g_strdup (pango_font_family_get_name (PANGO_FONT_FAMILY (item)));
}
static char *
@@ -326,8 +326,8 @@ bind_highlight_item (GtkSignalListItemFactory *factory,
{
MatchObject *obj;
GtkWidget *label;
Pango2AttrList *attrs;
Pango2Attribute *attr;
PangoAttrList *attrs;
PangoAttribute *attr;
const char *str;
obj = MATCH_OBJECT (gtk_list_item_get_item (item));
@@ -336,14 +336,13 @@ bind_highlight_item (GtkSignalListItemFactory *factory,
str = match_object_get_string (obj);
gtk_label_set_label (GTK_LABEL (label), str);
attrs = pango2_attr_list_new ();
attr = pango2_attr_weight_new (PANGO2_WEIGHT_BOLD);
pango2_attribute_set_range (attr,
match_object_get_match_start (obj),
match_object_get_match_end (obj));
pango2_attr_list_insert (attrs, attr);
attrs = pango_attr_list_new ();
attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
attr->start_index = match_object_get_match_start (obj);
attr->end_index = match_object_get_match_end (obj);
pango_attr_list_insert (attrs, attr);
gtk_label_set_attributes (GTK_LABEL (label), attrs);
pango2_attr_list_unref (attrs);
pango_attr_list_unref (attrs);
}
static void
@@ -435,7 +434,7 @@ do_dropdown (GtkWidget *do_widget)
button = gtk_drop_down_new (NULL, NULL);
model = G_LIST_MODEL (pango2_font_map_get_default ());
model = G_LIST_MODEL (pango_cairo_font_map_get_default ());
gtk_drop_down_set_model (GTK_DROP_DOWN (button), model);
gtk_drop_down_set_selected (GTK_DROP_DOWN (button), 0);
+6 -3
View File
@@ -90,9 +90,12 @@ do_errorstates (GtkWidget *do_widget)
toplevel = GTK_WIDGET (gtk_widget_get_root (do_widget));
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback (scope, validate_more_details);
gtk_builder_cscope_add_callback (scope, mode_switch_state_set);
gtk_builder_cscope_add_callback (scope, level_scale_value_changed);
gtk_builder_cscope_add_callback_symbols (GTK_BUILDER_CSCOPE (scope),
"validate_more_details", G_CALLBACK (validate_more_details),
"mode_switch_state_set", G_CALLBACK (mode_switch_state_set),
"level_scale_value_changed", G_CALLBACK (level_scale_value_changed),
NULL);
builder = gtk_builder_new ();
gtk_builder_set_scope (builder, scope);
gtk_builder_expose_object (builder, "toplevel", G_OBJECT (toplevel));
+17
View File
@@ -11,6 +11,9 @@
#include "gtkgears.h"
#include "gskshaderpaintable.h"
#include "nodewidget.h"
#include "graphwidget.h"
const char *const css =
".blurred-button {"
" box-shadow: 0px 0px 5px 10px rgba(0, 0, 0, 0.5);"
@@ -201,6 +204,18 @@ create_menu_button (void)
return w;
}
static GtkWidget *
create_tiger (void)
{
return node_widget_new ("/fishbowl/tiger.node");
}
static GtkWidget *
create_graph (void)
{
return graph_widget_new ();
}
static const struct {
const char *name;
GtkWidget * (*create_func) (void);
@@ -218,6 +233,8 @@ static const struct {
{ "Switch", create_switch },
{ "Menubutton", create_menu_button },
{ "Shader", create_cogs },
{ "Tiger", create_tiger },
{ "Graph", create_graph },
};
static int selected_widget_type = -1;
+190
View File
@@ -0,0 +1,190 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window">
<property name="default-width">600</property>
<property name="default-height">500</property>
<property name="title">Font Explorer</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<child>
<object class="GtkButton" id="reset">
<property name="receives-default">1</property>
<property name="tooltip-text">Reset</property>
<property name="icon-name">view-refresh-symbolic</property>
<signal name="clicked" handler="font_features_reset_features" swapped="no"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<child>
<object class="GtkViewport">
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkFontButton" id="font">
<property name="receives-default">1</property>
<property name="font">Sans 12</property>
<property name="level">family|style|size|variations|features</property>
<signal name="font-set" handler="font_features_font_changed" swapped="no"/>
</object>
</child>
<child>
<object class="GtkExpander">
<child type="label">
<object class="GtkLabel">
<property name="xalign">0</property>
<property name="label" translatable="yes">Font Features</property>
<attributes>
<attribute name="weight" value="bold"></attribute>
</attributes>
</object>
</child>
<child>
<object class="GtkBox" id="feature_list">
<property name="orientation">vertical</property>
<child>
<object class="GtkComboBox" id="script_lang">
<property name="margin-top">10</property>
<signal name="changed" handler="font_features_script_changed" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkExpander">
<child type="label">
<object class="GtkLabel" id="variations_heading">
<property name="label" translatable="yes">Font Variations</property>
<property name="xalign">0</property>
<attributes>
<attribute name="weight" value="bold"></attribute>
</attributes>
</object>
</child>
<child>
<object class="GtkGrid" id="variations_grid">
<property name="column-spacing">10</property>
<property name="row-spacing">10</property>
</object>
</child>
</object>
</child>
</object>
</child>
<style>
<class name="view"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="margin-start">20</property>
<property name="margin-end">20</property>
<property name="margin-top">20</property>
<property name="margin-bottom">20</property>
<property name="spacing">20</property>
<child>
<object class="GtkStack" id="stack">
<child>
<object class="GtkStackPage">
<property name="name">label</property>
<property name="child">
<object class="GtkLabel" id="label">
<property name="wrap">1</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="valign">start</property>
<property name="selectable">1</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">entry</property>
<property name="child">
<object class="GtkEntry" id="entry">
<property name="text">Grumpy wizards make toxic brew for the evil Queen and Jack. A quick movement of the enemy will jeopardize six gunboats. The job of waxing linoleum frequently peeves chintzy kids. My girl wove six dozen plaid jackets before she quit. Twelve ziggurats quickly jumped a finch box.
Разъяренный чтец эгоистично бьёт пятью жердями шустрого фехтовальщика. Наш банк вчера же выплатил Ф.Я. Эйхгольду комиссию за ценные вещи. Эх, чужак, общий съём цен шляп (юфть) – вдрызг! В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!
Τάχιστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός</property>
<signal name="activate" handler="font_features_stop_edit"/>
<property name="valign">start</property>
<property name="width-chars">50</property>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkLabel" id="settings">
<property name="wrap">1</property>
<property name="xalign">0</property>
<property name="valign">end</property>
<property name="width-chars">50</property>
<property name="max-width-chars">50</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<style>
<class name="monospace"/>
</style>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">10</property>
<child>
<object class="GtkLabel" id="description">
<property name="wrap">1</property>
<property name="xalign">0</property>
<property name="valign">end</property>
<property name="width-chars">50</property>
<property name="max-width-chars">50</property>
<property name="hexpand">1</property>
<style>
<class name="monospace"/>
</style>
</object>
</child>
<child>
<object class="GtkToggleButton" id="edit_toggle">
<property name="icon-name">document-edit-symbolic</property>
<property name="halign">end</property>
<property name="valign">end</property>
<signal name="toggled" handler="font_features_toggle_edit"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>
File diff suppressed because it is too large Load Diff
-65
View File
@@ -1,65 +0,0 @@
--- demos/gtk-demo/font_features.c
+++ demos/gtk-demo/font_features.c
@@ -434,7 +434,7 @@ static void
update_display (void)
{
GString *s;
- const char *text;
+ char *text;
gboolean has_feature;
GtkTreeIter iter;
GtkTreeModel *model;
@@ -452,8 +452,12 @@ update_display (void)
gboolean do_waterfall;
GString *waterfall;
char *palette;
+ GtkTextBuffer *buffer;
+ GtkTextIter start_iter, end_iter;
- text = gtk_editable_get_text (GTK_EDITABLE (demo->the_entry));
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (demo->the_entry));
+ gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
+ text = gtk_text_buffer_get_text (buffer, &start_iter, &end_iter, FALSE);
text_len = strlen (text);
do_waterfall = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (demo->waterfall_toggle));
@@ -631,6 +635,8 @@ update_display (void)
pango2_font_description_free (desc);
g_free (features);
pango2_attr_list_unref (attrs);
+
+ g_free (text);
}
static Pango2Font *
@@ -1603,8 +1609,12 @@ font_features_toggle_edit (void)
{
if (strcmp (gtk_stack_get_visible_child_name (GTK_STACK (demo->stack)), "entry") != 0)
{
+ GtkTextBuffer *buffer;
+ GtkTextIter start, end;
g_free (demo->text);
- demo->text = g_strdup (gtk_editable_get_text (GTK_EDITABLE (demo->the_entry)));
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (demo->the_entry));
+ gtk_text_buffer_get_bounds (buffer, &start, &end);
+ demo->text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_stack_set_visible_child_name (GTK_STACK (demo->stack), "entry");
gtk_widget_grab_focus (demo->the_entry);
gtk_adjustment_set_value (gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (demo->swin)), 0);
@@ -1632,7 +1642,7 @@ entry_key_press (GtkEventController *controller,
{
if (keyval == GDK_KEY_Escape)
{
- gtk_editable_set_text (GTK_EDITABLE (entry), demo->text);
+ gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (demo->the_entry)), demo->text, -1);
return GDK_EVENT_STOP;
}
@@ -1701,7 +1711,6 @@ do_font_features (GtkWidget *do_widget)
basic_value_changed (demo->line_height_adjustment, demo->line_height_entry);
controller = gtk_event_controller_key_new ();
- g_object_set_data_full (G_OBJECT (demo->the_entry), "controller", g_object_ref (controller), g_object_unref);
g_signal_connect (controller, "key-pressed", G_CALLBACK (entry_key_press), demo->the_entry);
gtk_widget_add_controller (demo->the_entry, controller);
-476
View File
@@ -1,476 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkAdjustment" id="size_adjustment">
<property name="lower">7</property>
<property name="upper">100</property>
<property name="value">14</property>
<property name="step_increment">0.5</property>
<property name="page_increment">10</property>
<signal name="value-changed" handler="basic_value_changed" object="size_entry" swapped="false"/>
</object>
<object class="GtkAdjustment" id="letterspacing_adjustment">
<property name="lower">-1024</property>
<property name="upper">8192</property>
<property name="value">0</property>
<property name="step_increment">1</property>
<property name="page_increment">512</property>
<signal name="value-changed" handler="basic_value_changed" object="letterspacing_entry" swapped="false"/>
</object>
<object class="GtkAdjustment" id="line_height_adjustment">
<property name="lower">0.75</property>
<property name="upper">2.5</property>
<property name="value">1.0</property>
<property name="step_increment">0.1</property>
<property name="page_increment">1</property>
<signal name="value-changed" handler="basic_value_changed" object="line_height_entry" swapped="false"/>
</object>
<object class="GtkWindow" id="window">
<property name="default-width">600</property>
<property name="default-height">500</property>
<property name="title">Font Explorer</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<child>
<object class="GtkButton" id="reset">
<property name="receives-default">1</property>
<property name="tooltip-text">Reset</property>
<property name="icon-name">view-refresh-symbolic</property>
<signal name="clicked" handler="font_features_reset_basic" swapped="no"/>
<signal name="clicked" handler="font_features_reset_features" swapped="no"/>
<signal name="clicked" handler="font_features_reset_variations" swapped="no"/>
<signal name="clicked" handler="font_features_reset_colors" swapped="no"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<child>
<object class="GtkViewport">
<child>
<object class="GtkBox">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkFontButton" id="font">
<property name="receives-default">1</property>
<property name="font">Sans 12</property>
<property name="level">family|style</property>
<signal name="font-set" handler="font_features_font_changed" swapped="no"/>
</object>
</child>
<child>
<object class="GtkGrid">
<property name="column-spacing">10</property>
<property name="row-spacing">10</property>
<child>
<object class="GtkLabel">
<property name="label">Size</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkScale" id="size_scale">
<property name="hexpand">1</property>
<property name="width-request">100</property>
<property name="valign">baseline</property>
<property name="adjustment">size_adjustment</property>
<layout>
<property name="column">1</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="size_entry">
<property name="width-chars">4</property>
<property name="max-width-chars">4</property>
<property name="hexpand">0</property>
<property name="valign">baseline</property>
<signal name="activate" handler="basic_entry_activated"
object="size_adjustment" swapped="false"/>
<layout>
<property name="column">2</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Letterspacing</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkScale">
<property name="hexpand">1</property>
<property name="width-request">100</property>
<property name="valign">baseline</property>
<property name="adjustment">letterspacing_adjustment</property>
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="letterspacing_entry">
<property name="width-chars">4</property>
<property name="max-width-chars">4</property>
<property name="hexpand">0</property>
<property name="valign">baseline</property>
<signal name="activate" handler="basic_entry_activated"
object="letterspacing_adjustment" swapped="false"/>
<layout>
<property name="column">2</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Line Height</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkScale">
<property name="hexpand">1</property>
<property name="width-request">100</property>
<property name="valign">baseline</property>
<property name="adjustment">line_height_adjustment</property>
<layout>
<property name="column">1</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="line_height_entry">
<property name="width-chars">4</property>
<property name="max-width-chars">4</property>
<property name="hexpand">0</property>
<property name="valign">baseline</property>
<signal name="activate" handler="basic_entry_activated"
object="line_height_adjustment" swapped="false"/>
<layout>
<property name="column">2</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Foreground</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkColorButton" id="foreground">
<property name="valign">baseline</property>
<property name="rgba">black</property>
<signal name="notify::rgba" handler="color_set_cb"/>
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Background</property>
<property name="xalign">0</property>
<property name="valign">baseline</property>
<layout>
<property name="column">0</property>
<property name="row">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkColorButton" id="background">
<property name="valign">baseline</property>
<property name="rgba">white</property>
<signal name="notify::rgba" handler="color_set_cb"/>
<layout>
<property name="column">1</property>
<property name="row">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton">
<property name="icon-name">object-flip-vertical-symbolic</property>
<property name="halign">start</property>
<property name="valign">center</property>
<style>
<class name="circular"/>
</style>
<signal name="clicked" handler="swap_colors"/>
<layout>
<property name="column">2</property>
<property name="row">3</property>
<property name="row-span">2</property>
</layout>
</object>
</child>
</object>
</child>
<child>
<object class="GtkExpander">
<child type="label">
<object class="GtkLabel">
<property name="xalign">0</property>
<property name="label" translatable="yes">OpenType Features</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<style>
<class name="title-4"/>
</style>
</object>
</child>
<child>
<object class="GtkBox" id="feature_list">
<property name="orientation">vertical</property>
<child>
<object class="GtkComboBox" id="script_lang">
<property name="tooltip-text" translatable="yes">Language System</property>
<property name="margin-top">10</property>
<signal name="changed" handler="font_features_script_changed" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkExpander">
<child type="label">
<object class="GtkLabel" id="variations_heading">
<property name="label" translatable="yes">Variation Axes</property>
<property name="xalign">0</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<style>
<class name="title-4"/>
</style>
</object>
</child>
<child>
<object class="GtkGrid" id="variations_grid">
<property name="column-spacing">10</property>
<property name="row-spacing">10</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkExpander">
<child type="label">
<object class="GtkLabel">
<property name="label" translatable="yes">Color Palettes</property>
<property name="xalign">0</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<style>
<class name="title-4"/>
</style>
</object>
</child>
<child>
<object class="GtkGrid" id="colors_grid">
<property name="column-spacing">10</property>
<property name="row-spacing">10</property>
</object>
</child>
</object>
</child>
</object>
</child>
<style>
<class name="view"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="margin-start">20</property>
<property name="margin-end">20</property>
<property name="margin-top">20</property>
<property name="margin-bottom">20</property>
<property name="spacing">20</property>
<child>
<object class="GtkScrolledWindow" id="swin">
<property name="hscrollbar-policy">automatic</property>
<property name="vscrollbar-policy">automatic</property>
<property name="propagate-natural-height">1</property>
<property name="vexpand">1</property>
<style>
<class name="font_features_background"/>
</style>
<child>
<object class="GtkStack" id="stack">
<child>
<object class="GtkStackPage">
<property name="name">label</property>
<property name="child">
<object class="GtkLabel" id="label">
<property name="wrap">1</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="valign">start</property>
<property name="selectable">1</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">entry</property>
<property name="child">
<object class="GtkTextView" id="entry">
<property name="buffer">
<object class="GtkTextBuffer">
<property name="text">Grumpy wizards make toxic brew for the evil Queen and Jack. A quick movement of the enemy will jeopardize six gunboats. The job of waxing linoleum frequently peeves chintzy kids. My girl wove six dozen plaid jackets before she quit. Twelve ziggurats quickly jumped a finch box.
Разъяренный чтец эгоистично бьёт пятью жердями шустрого фехтовальщика. Наш банк вчера же выплатил Ф.Я. Эйхгольду комиссию за ценные вещи. Эх, чужак, общий съём цен шляп (юфть) – вдрызг! В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!
Τάχιστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός</property>
</object>
</property>
<property name="valign">fill</property>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">10</property>
<child>
<object class="GtkLabel" id="settings">
<property name="wrap">1</property>
<property name="xalign">0</property>
<property name="valign">end</property>
<property name="width-chars">50</property>
<property name="max-width-chars">50</property>
<property name="hexpand">1</property>
<style>
<class name="monospace"/>
</style>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Alphabet</property>
<signal name="clicked" handler="set_text_alphabet"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Paragraph</property>
<signal name="clicked" handler="set_text_paragraph"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">10</property>
<child>
<object class="GtkLabel" id="description">
<property name="wrap">1</property>
<property name="wrap-mode">char</property>
<property name="xalign">0</property>
<property name="valign">end</property>
<property name="width-chars">50</property>
<property name="max-width-chars">50</property>
<property name="hexpand">1</property>
<style>
<class name="monospace"/>
</style>
</object>
</child>
<child>
<object class="GtkBox">
<style>
<class name="linked"/>
</style>
<property name="valign">end</property>
<child>
<object class="GtkToggleButton" id="plain_toggle">
<property name="label" translatable="yes">Plain</property>
<property name="active">1</property>
<property name="valign">baseline</property>
<signal name="toggled" handler="font_features_toggle_plain"/>
</object>
</child>
<child>
<object class="GtkToggleButton" id="waterfall_toggle">
<property name="label" translatable="yes">Waterfall</property>
<property name="valign">baseline</property>
<property name="group">plain_toggle</property>
<signal name="toggled" handler="font_features_toggle_plain"/>
<signal name="notify::active" handler="font_features_notify_waterfall"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkToggleButton" id="edit_toggle">
<property name="group">waterfall_toggle</property>
<property name="icon-name">document-edit-symbolic</property>
<property name="halign">end</property>
<property name="valign">end</property>
<signal name="clicked" handler="font_features_toggle_edit"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>
+89 -71
View File
@@ -19,7 +19,7 @@
*/
static void
insert_tags_for_attributes (GtkTextBuffer *buffer,
Pango2AttrIterator *iter,
PangoAttrIterator *iter,
GtkTextIter *start,
GtkTextIter *end)
{
@@ -27,12 +27,13 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
GSList *attrs, *l;
GtkTextTag *tag;
char name[256];
float fg_alpha, bg_alpha;
table = gtk_text_buffer_get_tag_table (buffer);
#define LANGUAGE_ATTR(attr_name) \
{ \
const char *language = pango2_language_to_string (pango2_attribute_get_language (attr)); \
const char *language = pango_language_to_string (((PangoAttrLanguage*)attr)->value); \
g_snprintf (name, 256, "language=%s", language); \
tag = gtk_text_tag_table_lookup (table, name); \
if (!tag) \
@@ -47,7 +48,7 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
#define STRING_ATTR(attr_name) \
{ \
const char *string = pango2_attribute_get_string (attr); \
const char *string = ((PangoAttrString*)attr)->value; \
g_snprintf (name, 256, #attr_name "=%s", string); \
tag = gtk_text_tag_table_lookup (table, name); \
if (!tag) \
@@ -62,7 +63,7 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
#define INT_ATTR(attr_name) \
{ \
int value = pango2_attribute_get_int (attr); \
int value = ((PangoAttrInt*)attr)->value; \
g_snprintf (name, 256, #attr_name "=%d", value); \
tag = gtk_text_tag_table_lookup (table, name); \
if (!tag) \
@@ -77,8 +78,8 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
#define FONT_ATTR(attr_name) \
{ \
Pango2FontDescription *desc = pango2_attribute_get_font_desc (attr); \
char *str = pango2_font_description_to_string (desc); \
PangoFontDescription *desc = ((PangoAttrFontDesc*)attr)->desc; \
char *str = pango_font_description_to_string (desc); \
g_snprintf (name, 256, "font-desc=%s", str); \
g_free (str); \
tag = gtk_text_tag_table_lookup (table, name); \
@@ -94,7 +95,7 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
#define FLOAT_ATTR(attr_name) \
{ \
float value = pango2_attribute_get_float (attr); \
float value = ((PangoAttrFloat*)attr)->value; \
g_snprintf (name, 256, #attr_name "=%g", value); \
tag = gtk_text_tag_table_lookup (table, name); \
if (!tag) \
@@ -107,14 +108,15 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
gtk_text_buffer_apply_tag (buffer, tag, start, end); \
}
#define RGBA_ATTR(attr_name) \
#define RGBA_ATTR(attr_name, alpha_value) \
{ \
Pango2Color *color = pango2_attribute_get_color (attr); \
PangoColor *color; \
GdkRGBA rgba; \
color = &((PangoAttrColor*)attr)->color; \
rgba.red = color->red / 65535.; \
rgba.green = color->green / 65535.; \
rgba.blue = color->blue / 65535.; \
rgba.alpha = color->alpha / 65535.; \
rgba.alpha = alpha_value; \
char *str = gdk_rgba_to_string (&rgba); \
g_snprintf (name, 256, #attr_name "=%s", str); \
g_free (str); \
@@ -142,157 +144,173 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
gtk_text_buffer_apply_tag (buffer, tag, start, end); \
}
attrs = pango2_attr_iterator_get_attrs (iter);
fg_alpha = bg_alpha = 1.;
attrs = pango_attr_iterator_get_attrs (iter);
for (l = attrs; l; l = l->next)
{
Pango2Attribute *attr = l->data;
PangoAttribute *attr = l->data;
switch (pango2_attribute_type (attr))
switch ((int)attr->klass->type)
{
case PANGO2_ATTR_LANGUAGE:
case PANGO_ATTR_FOREGROUND_ALPHA:
fg_alpha = ((PangoAttrInt*)attr)->value / 65535.;
break;
case PANGO_ATTR_BACKGROUND_ALPHA:
bg_alpha = ((PangoAttrInt*)attr)->value / 65535.;
break;
default:
break;
}
}
for (l = attrs; l; l = l->next)
{
PangoAttribute *attr = l->data;
switch (attr->klass->type)
{
case PANGO_ATTR_LANGUAGE:
LANGUAGE_ATTR (language);
break;
case PANGO2_ATTR_FAMILY:
case PANGO_ATTR_FAMILY:
STRING_ATTR (family);
break;
case PANGO2_ATTR_STYLE:
case PANGO_ATTR_STYLE:
INT_ATTR (style);
break;
case PANGO2_ATTR_WEIGHT:
case PANGO_ATTR_WEIGHT:
INT_ATTR (weight);
break;
case PANGO2_ATTR_VARIANT:
case PANGO_ATTR_VARIANT:
INT_ATTR (variant);
break;
case PANGO2_ATTR_STRETCH:
case PANGO_ATTR_STRETCH:
INT_ATTR (stretch);
break;
case PANGO2_ATTR_SIZE:
case PANGO_ATTR_SIZE:
INT_ATTR (size);
break;
case PANGO2_ATTR_FONT_DESC:
case PANGO_ATTR_FONT_DESC:
FONT_ATTR (font-desc);
break;
case PANGO2_ATTR_FOREGROUND:
RGBA_ATTR (foreground_rgba);
case PANGO_ATTR_FOREGROUND:
RGBA_ATTR (foreground_rgba, fg_alpha);
break;
case PANGO2_ATTR_BACKGROUND:
RGBA_ATTR (background_rgba);
case PANGO_ATTR_BACKGROUND:
RGBA_ATTR (background_rgba, bg_alpha);
break;
case PANGO2_ATTR_UNDERLINE:
case PANGO_ATTR_UNDERLINE:
INT_ATTR (underline);
break;
case PANGO2_ATTR_UNDERLINE_COLOR:
RGBA_ATTR (underline_rgba);
case PANGO_ATTR_UNDERLINE_COLOR:
RGBA_ATTR (underline_rgba, fg_alpha);
break;
case PANGO2_ATTR_OVERLINE:
case PANGO_ATTR_OVERLINE:
INT_ATTR (overline);
break;
case PANGO2_ATTR_OVERLINE_COLOR:
RGBA_ATTR (overline_rgba);
case PANGO_ATTR_OVERLINE_COLOR:
RGBA_ATTR (overline_rgba, fg_alpha);
break;
case PANGO2_ATTR_STRIKETHROUGH:
case PANGO_ATTR_STRIKETHROUGH:
INT_ATTR (strikethrough);
break;
case PANGO2_ATTR_STRIKETHROUGH_COLOR:
RGBA_ATTR (strikethrough_rgba);
case PANGO_ATTR_STRIKETHROUGH_COLOR:
RGBA_ATTR (strikethrough_rgba, fg_alpha);
break;
case PANGO2_ATTR_RISE:
case PANGO_ATTR_RISE:
INT_ATTR (rise);
break;
case PANGO2_ATTR_SCALE:
case PANGO_ATTR_SCALE:
FLOAT_ATTR (scale);
break;
case PANGO2_ATTR_FALLBACK:
case PANGO_ATTR_FALLBACK:
INT_ATTR (fallback);
break;
case PANGO2_ATTR_LETTER_SPACING:
case PANGO_ATTR_LETTER_SPACING:
INT_ATTR (letter_spacing);
break;
case PANGO2_ATTR_FONT_FEATURES:
case PANGO_ATTR_FONT_FEATURES:
STRING_ATTR (font_features);
break;
case PANGO2_ATTR_ALLOW_BREAKS:
case PANGO_ATTR_ALLOW_BREAKS:
INT_ATTR (allow_breaks);
break;
case PANGO2_ATTR_SHOW:
case PANGO_ATTR_SHOW:
INT_ATTR (show_spaces);
break;
case PANGO2_ATTR_INSERT_HYPHENS:
case PANGO_ATTR_INSERT_HYPHENS:
INT_ATTR (insert_hyphens);
break;
case PANGO2_ATTR_LINE_HEIGHT:
case PANGO_ATTR_LINE_HEIGHT:
FLOAT_ATTR (line_height);
break;
case PANGO2_ATTR_ABSOLUTE_LINE_HEIGHT:
case PANGO_ATTR_ABSOLUTE_LINE_HEIGHT:
break;
case PANGO2_ATTR_LINE_SPACING:
INT_ATTR (pixels_inside_wrap);
break;
case PANGO2_ATTR_WORD:
case PANGO_ATTR_WORD:
VOID_ATTR (word);
break;
case PANGO2_ATTR_SENTENCE:
case PANGO_ATTR_SENTENCE:
VOID_ATTR (sentence);
break;
case PANGO2_ATTR_PARAGRAPH:
VOID_ATTR (paragraph);
break;
case PANGO2_ATTR_BASELINE_SHIFT:
case PANGO_ATTR_BASELINE_SHIFT:
INT_ATTR (baseline_shift);
break;
case PANGO2_ATTR_FONT_SCALE:
case PANGO_ATTR_FONT_SCALE:
INT_ATTR (font_scale);
break;
case PANGO2_ATTR_ABSOLUTE_SIZE:
case PANGO2_ATTR_GRAVITY:
case PANGO2_ATTR_GRAVITY_HINT:
case PANGO_ATTR_SHAPE:
case PANGO_ATTR_ABSOLUTE_SIZE:
case PANGO_ATTR_GRAVITY:
case PANGO_ATTR_GRAVITY_HINT:
case PANGO_ATTR_FOREGROUND_ALPHA:
case PANGO_ATTR_BACKGROUND_ALPHA:
break;
case PANGO2_ATTR_TEXT_TRANSFORM:
case PANGO_ATTR_TEXT_TRANSFORM:
INT_ATTR (text_transform);
break;
case PANGO2_ATTR_INVALID:
case PANGO_ATTR_INVALID:
default:
g_assert_not_reached ();
break;
}
}
g_slist_free_full (attrs, (GDestroyNotify)pango2_attribute_destroy);
g_slist_free_full (attrs, (GDestroyNotify)pango_attribute_destroy);
#undef LANGUAGE_ATTR
#undef STRING_ATTR
@@ -311,9 +329,9 @@ typedef struct
GtkTextBuffer *buffer;
GtkTextIter iter;
GtkTextMark *mark;
Pango2AttrList *attributes;
PangoAttrList *attributes;
char *text;
Pango2AttrIterator *attr;
PangoAttrIterator *attr;
} MarkupData;
static void
@@ -322,8 +340,8 @@ free_markup_data (MarkupData *mdata)
g_free (mdata->markup);
g_clear_pointer (&mdata->parser, g_markup_parse_context_free);
gtk_text_buffer_delete_mark (mdata->buffer, mdata->mark);
g_clear_pointer (&mdata->attr, pango2_attr_iterator_destroy);
g_clear_pointer (&mdata->attributes, pango2_attr_list_unref);
g_clear_pointer (&mdata->attr, pango_attr_iterator_destroy);
g_clear_pointer (&mdata->attributes, pango_attr_list_unref);
g_free (mdata->text);
g_object_unref (mdata->buffer);
g_free (mdata);
@@ -349,7 +367,7 @@ insert_markup_idle (gpointer data)
return G_SOURCE_REMOVE;
}
pango2_attr_iterator_range (mdata->attr, &start, &end);
pango_attr_iterator_range (mdata->attr, &start, &end);
if (end == G_MAXINT) /* last chunk */
end = start - 1; /* resulting in -1 to be passed to _insert */
@@ -362,7 +380,7 @@ insert_markup_idle (gpointer data)
gtk_text_buffer_get_iter_at_mark (mdata->buffer, &mdata->iter, mdata->mark);
}
while (pango2_attr_iterator_next (mdata->attr));
while (pango_attr_iterator_next (mdata->attr));
free_markup_data (mdata);
return G_SOURCE_REMOVE;
@@ -398,7 +416,7 @@ parse_markup_idle (gpointer data)
mdata->pos += 4096;
} while (mdata->pos < mdata->len);
if (!pango2_markup_parser_finish (mdata->parser,
if (!pango_markup_parser_finish (mdata->parser,
&mdata->attributes,
&mdata->text,
NULL,
@@ -417,7 +435,7 @@ parse_markup_idle (gpointer data)
return G_SOURCE_REMOVE;
}
mdata->attr = pango2_attr_list_get_iterator (mdata->attributes);
mdata->attr = pango_attr_list_get_iterator (mdata->attributes);
insert_markup_idle (data);
return G_SOURCE_REMOVE;
@@ -443,7 +461,7 @@ insert_markup (GtkTextBuffer *buffer,
data->markup = markup;
data->len = len;
data->parser = pango2_markup_parser_new (0);
data->parser = pango_markup_parser_new (0);
data->pos = 0;
/* create mark with right gravity */
+42 -44
View File
@@ -25,7 +25,7 @@ static GtkWidget *show_extents = NULL;
static GtkWidget *show_pixels = NULL;
static GtkWidget *show_outlines = NULL;
static Pango2Context *context;
static PangoContext *context;
static int scale = 7;
static double pixel_alpha = 1.0;
@@ -35,9 +35,9 @@ static void
update_image (void)
{
const char *text;
Pango2FontDescription *desc;
Pango2Layout *layout;
Pango2Rectangle ink, logical;
PangoFontDescription *desc;
PangoLayout *layout;
PangoRectangle ink, logical;
int baseline;
cairo_surface_t *surface;
cairo_t *cr;
@@ -56,7 +56,7 @@ update_image (void)
text = gtk_editable_get_text (GTK_EDITABLE (entry));
desc = gtk_font_chooser_get_font_desc (GTK_FONT_CHOOSER (font_button));
fopt = cairo_font_options_copy (pango2_cairo_context_get_font_options (context));
fopt = cairo_font_options_copy (pango_cairo_context_get_font_options (context));
hint = gtk_combo_box_get_active_id (GTK_COMBO_BOX (hinting));
hintstyle = CAIRO_HINT_STYLE_DEFAULT;
@@ -85,20 +85,20 @@ update_image (void)
antialias = CAIRO_ANTIALIAS_NONE;
cairo_font_options_set_antialias (fopt, antialias);
pango2_context_set_round_glyph_positions (context, hintmetrics == CAIRO_HINT_METRICS_ON);
pango2_cairo_context_set_font_options (context, fopt);
pango_context_set_round_glyph_positions (context, hintmetrics == CAIRO_HINT_METRICS_ON);
pango_cairo_context_set_font_options (context, fopt);
cairo_font_options_destroy (fopt);
pango2_context_changed (context);
pango_context_changed (context);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (text_radio)))
{
layout = pango2_layout_new (context);
pango2_layout_set_font_description (layout, desc);
pango2_layout_set_text (layout, text, -1);
pango2_lines_get_extents (pango2_layout_get_lines (layout), &ink, &logical);
baseline = pango2_lines_get_baseline (pango2_layout_get_lines (layout));
layout = pango_layout_new (context);
pango_layout_set_font_description (layout, desc);
pango_layout_set_text (layout, text, -1);
pango_layout_get_extents (layout, &ink, &logical);
baseline = pango_layout_get_baseline (layout);
pango2_extents_to_pixels (&ink, NULL);
pango_extents_to_pixels (&ink, NULL);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ink.width + 20, ink.height + 20);
cr = cairo_create (surface);
@@ -108,9 +108,9 @@ update_image (void)
cairo_set_source_rgba (cr, 0, 0, 0, pixel_alpha);
cairo_move_to (cr, 10, 10);
pango2_cairo_show_layout (cr, layout);
pango_cairo_show_layout (cr, layout);
pango2_cairo_layout_path (cr, layout);
pango_cairo_layout_path (cr, layout);
path = cairo_copy_path (cr);
cairo_destroy (cr);
@@ -154,15 +154,15 @@ update_image (void)
cairo_set_source_rgb (cr, 0, 0, 1);
cairo_rectangle (cr,
scale * (10 + pango2_units_to_double (logical.x)) - 0.5,
scale * (10 + pango2_units_to_double (logical.y)) - 0.5,
scale * pango2_units_to_double (logical.width) + 1,
scale * pango2_units_to_double (logical.height) + 1);
scale * (10 + pango_units_to_double (logical.x)) - 0.5,
scale * (10 + pango_units_to_double (logical.y)) - 0.5,
scale * pango_units_to_double (logical.width) + 1,
scale * pango_units_to_double (logical.height) + 1);
cairo_stroke (cr);
cairo_move_to (cr, scale * (10 + pango2_units_to_double (logical.x)) - 0.5,
scale * (10 + pango2_units_to_double (baseline)) - 0.5);
cairo_line_to (cr, scale * (10 + pango2_units_to_double (logical.x + logical.width)) + 1,
scale * (10 + pango2_units_to_double (baseline)) - 0.5);
cairo_move_to (cr, scale * (10 + pango_units_to_double (logical.x)) - 0.5,
scale * (10 + pango_units_to_double (baseline)) - 0.5);
cairo_line_to (cr, scale * (10 + pango_units_to_double (logical.x + logical.width)) + 1,
scale * (10 + pango_units_to_double (baseline)) - 0.5);
cairo_stroke (cr);
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_rectangle (cr,
@@ -206,10 +206,9 @@ update_image (void)
}
else
{
Pango2LineIter *iter;
Pango2Run *run;
Pango2GlyphString *glyphs;
Pango2GlyphInfo *g;
PangoLayoutIter *iter;
PangoLayoutRun *run;
PangoGlyphInfo *g;
int i, j;
GString *str;
gunichar ch;
@@ -227,44 +226,43 @@ update_image (void)
g_string_append_unichar (str, 0x200c);
}
layout = pango2_layout_new (context);
pango2_layout_set_font_description (layout, desc);
pango2_layout_set_text (layout, str->str, -1);
layout = pango_layout_new (context);
pango_layout_set_font_description (layout, desc);
pango_layout_set_text (layout, str->str, -1);
g_string_free (str, TRUE);
pango2_lines_get_extents (pango2_layout_get_lines (layout), &ink, &logical);
pango2_extents_to_pixels (&logical, NULL);
pango_layout_get_extents (layout, &ink, &logical);
pango_extents_to_pixels (&logical, NULL);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, logical.width * 3 / 2, 4*logical.height);
cr = cairo_create (surface);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
iter = pango2_layout_get_iter (layout);
run = pango2_line_iter_get_run (iter);
glyphs = pango2_run_get_glyphs (run);
iter = pango_layout_get_iter (layout);
run = pango_layout_iter_get_run (iter);
cairo_set_source_rgb (cr, 0, 0, 0);
for (i = 0; i < 4; i++)
{
g = &(glyphs->glyphs[2*i]);
g->geometry.width = PANGO2_UNITS_ROUND (g->geometry.width * 3 / 2);
g = &(run->glyphs->glyphs[2*i]);
g->geometry.width = PANGO_UNITS_ROUND (g->geometry.width * 3 / 2);
}
for (j = 0; j < 4; j++)
{
for (i = 0; i < 4; i++)
{
g = &(glyphs->glyphs[2*i]);
g->geometry.x_offset = i * (PANGO2_SCALE / 4);
g->geometry.y_offset = j * (PANGO2_SCALE / 4);
g = &(run->glyphs->glyphs[2*i]);
g->geometry.x_offset = i * (PANGO_SCALE / 4);
g->geometry.y_offset = j * (PANGO_SCALE / 4);
}
cairo_move_to (cr, 0, j * logical.height);
pango2_cairo_show_layout (cr, layout);
pango_cairo_show_layout (cr, layout);
}
cairo_destroy (cr);
pango2_line_iter_free (iter);
pango_layout_iter_free (iter);
g_object_unref (layout);
pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, cairo_image_surface_get_width (surface), cairo_image_surface_get_height (surface));
@@ -277,7 +275,7 @@ update_image (void)
g_object_unref (pixbuf2);
pango2_font_description_free (desc);
pango_font_description_free (desc);
}
static gboolean fading = FALSE;
File diff suppressed because it is too large Load Diff
+164
View File
@@ -0,0 +1,164 @@
#include "graphwidget.h"
struct _GraphWidget
{
GtkWidget parent_instance;
GskPath *path;
GskStroke *stroke;
GdkRGBA color;
GskPath *stroke_path;
guint tick_cb;
guint64 start_time;
double period;
double amplitude;
};
struct _GraphWidgetClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (GraphWidget, graph_widget, GTK_TYPE_WIDGET)
static void
update_path (GraphWidget *self,
float amplitude)
{
graphene_point_t p[20];
GskPathBuilder *builder;
g_clear_pointer (&self->path, gsk_path_unref);
g_clear_pointer (&self->stroke_path, gsk_path_unref);
for (int i = 0; i < 20; i++)
{
p[i].x = 10 * i;
p[i].y = 50;
if (i % 4 == 1 || i % 4 == 2)
{
if (i % 8 < 4)
p[i].y += amplitude;
else
p[i].y -= amplitude;
}
}
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder, p[0].x, p[0].y);
for (int i = 0; i < 20; i += 4)
gsk_path_builder_curve_to (builder,
p[i+1].x, p[i+1].y,
p[i+2].x, p[i+2].y,
p[i+3].x, p[i+3].y);
self->path = gsk_path_builder_free_to_path (builder);
self->stroke_path = gsk_path_stroke (self->path, self->stroke);
}
static gboolean
tick_cb (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data)
{
GraphWidget *self = GRAPH_WIDGET (widget);
guint64 now;
double angle;
now = gdk_frame_clock_get_frame_time (frame_clock);
if (self->start_time == 0)
self->start_time = now;
angle = 360 * (now - self->start_time) / (double)(self->period * G_TIME_SPAN_MINUTE);
update_path (self, sin (angle) * self->amplitude);
gtk_widget_queue_draw (widget);
return G_SOURCE_CONTINUE;
}
static void
graph_widget_init (GraphWidget *self)
{
self->color.red = g_random_double_range (0, 1);
self->color.green = g_random_double_range (0, 1);
self->color.blue = g_random_double_range (0, 1);
self->color.alpha = 1;
self->period = g_random_double_range (0.5, 1);
self->amplitude = g_random_double_range (10, 25);
self->stroke = gsk_stroke_new (2);
update_path (self, 0);
self->start_time = 0;
self->tick_cb = gtk_widget_add_tick_callback (GTK_WIDGET (self), tick_cb, NULL, NULL);
}
static void
graph_widget_dispose (GObject *object)
{
GraphWidget *self = GRAPH_WIDGET (object);
gsk_path_unref (self->path);
gsk_stroke_free (self->stroke);
G_OBJECT_CLASS (graph_widget_parent_class)->dispose (object);
}
static void
graph_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GraphWidget *self = GRAPH_WIDGET (widget);
int width, height;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
gtk_snapshot_push_fill (snapshot, self->stroke_path, GSK_FILL_RULE_WINDING);
gtk_snapshot_append_color (snapshot,
&self->color,
&GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_pop (snapshot);
}
static void
graph_widget_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
if (orientation == GTK_ORIENTATION_HORIZONTAL)
*minimum = *natural = 200;
else
*minimum = *natural = 100;
}
static void
graph_widget_class_init (GraphWidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = graph_widget_dispose;
widget_class->snapshot = graph_widget_snapshot;
widget_class->measure = graph_widget_measure;
}
GtkWidget *
graph_widget_new (void)
{
return g_object_new (GRAPH_TYPE_WIDGET, NULL);
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <gtk/gtk.h>
#define GRAPH_TYPE_WIDGET (graph_widget_get_type ())
G_DECLARE_FINAL_TYPE (GraphWidget, graph_widget, GRAPH, WIDGET, GtkWidget)
GtkWidget * graph_widget_new (void);
+1 -2
View File
@@ -23,7 +23,7 @@ do_headerbar (GtkWidget *do_widget)
{
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Welcome to the Hotel California");
gtk_window_set_title (GTK_WINDOW (window), "Welcome to Facebook - Log in, sign up or learn more");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
@@ -31,7 +31,6 @@ do_headerbar (GtkWidget *do_widget)
header = gtk_header_bar_new ();
button = gtk_button_new_from_icon_name ("mail-send-receive-symbolic");
gtk_widget_set_tooltip_text (button, "Check out");
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+4 -4
View File
@@ -29,7 +29,7 @@ insert_link (GtkTextBuffer *buffer,
tag = gtk_text_buffer_create_tag (buffer, NULL,
"foreground", "blue",
"underline", PANGO2_LINE_STYLE_SOLID,
"underline", PANGO_UNDERLINE_SINGLE,
NULL);
g_object_set_data (G_OBJECT (tag), "page", GINT_TO_POINTER (page));
gtk_text_buffer_insert_with_tags (buffer, iter, text, -1, tag, NULL);
@@ -72,8 +72,8 @@ show_page (GtkTextView *text_view,
buffer = gtk_text_view_get_buffer (text_view);
bold = gtk_text_buffer_create_tag (buffer, NULL,
"weight", PANGO2_WEIGHT_BOLD,
"scale", PANGO2_SCALE_X_LARGE,
"weight", PANGO_WEIGHT_BOLD,
"scale", PANGO_SCALE_X_LARGE,
NULL);
mono = gtk_text_buffer_create_tag (buffer, NULL,
"family", "monospace",
@@ -100,7 +100,7 @@ show_page (GtkTextView *text_view,
theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (text_view)));
icon = gtk_icon_theme_lookup_icon (theme,
"view-conceal-symbolic",
"eye-not-looking-symbolic",
NULL,
16,
1,
+2 -2
View File
@@ -123,11 +123,11 @@ populate_emoji_text (void)
for (int i = 0; i < 500; i++)
{
if (i % 2)
g_string_append (s, "<span underline=\"solid\" underline_color=\"red\">x</span>");
g_string_append (s, "<span underline=\"single\" underline_color=\"red\">x</span>");
for (int j = 0; j < 30; j++)
{
g_string_append (s, "💓");
g_string_append (s, "<span underline=\"solid\" underline_color=\"red\">x</span>");
g_string_append (s, "<span underline=\"single\" underline_color=\"red\">x</span>");
}
g_string_append (s, "\n");
}
+9 -9
View File
@@ -44,7 +44,7 @@ get_win32_all_locales_scripts (LPWSTR locale_w, DWORD flags, LPARAM param)
gint i;
const LCTYPE iso639_lctypes[] = { LOCALE_SISO639LANGNAME, LOCALE_SISO639LANGNAME2 };
GHashTable *ht_scripts_langs = (GHashTable *) param;
Pango2Language *lang;
PangoLanguage *lang;
gint langname_size, locale_abbrev_size;
langname_size = GetLocaleInfoEx (locale_w, LOCALE_SLOCALIZEDDISPLAYNAME, langname_w, 0);
@@ -60,7 +60,7 @@ get_win32_all_locales_scripts (LPWSTR locale_w, DWORD flags, LPARAM param)
langname = g_utf16_to_utf8 (langname_w, -1, NULL, NULL, NULL);
locale = g_utf16_to_utf8 (locale_w, -1, NULL, NULL, NULL);
p = strchr (locale, '-');
lang = pango2_language_from_string (locale);
lang = pango_language_from_string (locale);
if (g_hash_table_lookup (ht_scripts_langs, lang) == NULL)
g_hash_table_insert (ht_scripts_langs, lang, langname);
@@ -77,7 +77,7 @@ get_win32_all_locales_scripts (LPWSTR locale_w, DWORD flags, LPARAM param)
GetLocaleInfoEx (locale_w, iso639_lctypes[i], locale_abbrev_w, locale_abbrev_size);
locale_abbrev = g_utf16_to_utf8 (locale_abbrev_w, -1, NULL, NULL, NULL);
lang = pango2_language_from_string (locale_abbrev);
lang = pango_language_from_string (locale_abbrev);
if (g_hash_table_lookup (ht_scripts_langs, lang) == NULL)
g_hash_table_insert (ht_scripts_langs, lang, langname);
@@ -218,22 +218,22 @@ languages_parse_start_tag (GMarkupParseContext *ctx,
if (ccode != NULL)
g_hash_table_insert (language_map,
pango2_language_from_string (ccode),
pango_language_from_string (ccode),
g_strdup (display_name));
if (ccode_longB != NULL)
g_hash_table_insert (language_map,
pango2_language_from_string (ccode_longB),
pango_language_from_string (ccode_longB),
g_strdup (display_name));
if (ccode_longT != NULL)
g_hash_table_insert (language_map,
pango2_language_from_string (ccode_longT),
pango_language_from_string (ccode_longT),
g_strdup (display_name));
if (ccode_id != NULL)
g_hash_table_insert (language_map,
pango2_language_from_string (ccode_id),
pango_language_from_string (ccode_id),
g_strdup (display_name));
g_free (display_name);
@@ -295,7 +295,7 @@ languages_init (void)
}
const char *
get_language_name (Pango2Language *language)
get_language_name (PangoLanguage *language)
{
languages_init ();
@@ -311,5 +311,5 @@ get_language_name_for_tag (guint32 tag)
lang = hb_ot_tag_to_language (tag);
s = hb_language_to_string (lang);
return get_language_name (pango2_language_from_string (s));
return get_language_name (pango_language_from_string (s));
}
+2 -2
View File
@@ -1,11 +1,11 @@
#ifndef LANGUAGE_NAMES_H
#define LANGUAGE_NAMES_H
#include <pango2/pango.h>
#include <pango/pango.h>
G_BEGIN_DECLS
const char * get_language_name (Pango2Language *language);
const char * get_language_name (PangoLanguage *language);
const char * get_language_name_for_tag (guint32 tag);
G_END_DECLS
+6 -4
View File
@@ -66,13 +66,15 @@ do_links (GtkWidget *do_widget)
"as hyperlinks, which can be clicked "
"or activated via <a href=\"keynav\">keynav</a> "
"and they work fine with other markup, like when "
"linking to <a href=\"http://www.flathub.org/\"><b>"
"<span letter_spacing=\"1024\" underline=\"none\" color=\"pink\" background=\"darkslategray\">Flathub</span>"
"</b></a>.");
"searching on <a href=\"http://www.google.com/\">"
"<span color=\"#0266C8\">G</span><span color=\"#F90101\">o</span>"
"<span color=\"#F2B50F\">o</span><span color=\"#0266C8\">g</span>"
"<span color=\"#00933B\">l</span><span color=\"#F90101\">e</span>"
"</a>.");
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
gtk_label_set_max_width_chars (GTK_LABEL (label), 40);
gtk_label_set_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_wrap_mode (GTK_LABEL (label), PANGO2_WRAP_WORD);
gtk_label_set_wrap_mode (GTK_LABEL (label), PANGO_WRAP_WORD);
g_signal_connect (label, "activate-link", G_CALLBACK (activate_link), NULL);
gtk_widget_set_margin_start (label, 20);
gtk_widget_set_margin_end (label, 20);
+2 -1
View File
@@ -42,7 +42,8 @@ do_listbox_controls (GtkWidget *do_widget)
GtkBuilder *builder;
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback (scope, row_activated);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope),
"row_activated", G_CALLBACK (row_activated));
builder = gtk_builder_new ();
gtk_builder_set_scope (builder, scope);
+8 -8
View File
@@ -758,15 +758,15 @@ setup_number_item (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *label;
Pango2AttrList *attrs;
PangoAttrList *attrs;
label = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (label), 1);
attrs = pango2_attr_list_new ();
pango2_attr_list_insert (attrs, pango2_attr_font_features_new ("tnum"));
attrs = pango_attr_list_new ();
pango_attr_list_insert (attrs, pango_attr_font_features_new ("tnum"));
gtk_label_set_attributes (GTK_LABEL (label), attrs);
pango2_attr_list_unref (attrs);
pango_attr_list_unref (attrs);
gtk_list_item_set_child (item, label);
}
@@ -862,7 +862,7 @@ do_listview_colors (GtkWidget *do_widget)
GtkExpression *expression;
GtkWidget *button;
GtkWidget *label;
Pango2AttrList *attrs;
PangoAttrList *attrs;
char *string;
guint len;
GtkWidget *selection_view;
@@ -990,10 +990,10 @@ do_listview_colors (GtkWidget *do_widget)
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), button);
label = gtk_label_new ("0 /");
attrs = pango2_attr_list_new ();
pango2_attr_list_insert (attrs, pango2_attr_font_features_new ("tnum"));
attrs = pango_attr_list_new ();
pango_attr_list_insert (attrs, pango_attr_font_features_new ("tnum"));
gtk_label_set_attributes (GTK_LABEL (label), attrs);
pango2_attr_list_unref (attrs);
pango_attr_list_unref (attrs);
string = g_strdup_printf ("%'u", 4096);
len = g_utf8_strlen (string, -1);
g_free (string);
+4 -4
View File
@@ -356,10 +356,10 @@ do_listview_settings (GtkWidget *do_widget)
g_type_ensure (SETTINGS_TYPE_KEY);
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback (scope, search_enabled);
gtk_builder_cscope_add_callback (scope, search_changed);
gtk_builder_cscope_add_callback (scope, stop_search);
gtk_builder_cscope_add_callback (scope, item_value_changed);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "search_enabled", (GCallback)search_enabled);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "search_changed", (GCallback)search_changed);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "stop_search", (GCallback)stop_search);
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope), "item_value_changed", (GCallback)item_value_changed);
builder = gtk_builder_new ();
gtk_builder_set_scope (builder, scope);
+1 -1
View File
@@ -123,7 +123,7 @@ setup_ellipsizing_label (GtkSignalListItemFactory *factory,
GtkWidget *label;
label = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO2_ELLIPSIZE_END);
gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
gtk_label_set_width_chars (GTK_LABEL (label), 20);
gtk_list_item_set_child (GTK_LIST_ITEM (listitem), label);
}
+4 -3
View File
@@ -1,5 +1,5 @@
/* Lists/Words
* #Keywords: GtkListView, GtkFilterListModel, GtkInscription
* #Keywords: GtkListView, GtkFilterListModel
*
* This demo shows filtering a long list - of words.
*
@@ -17,9 +17,10 @@ const char *factory_text =
"<interface>\n"
" <template class='GtkListItem'>\n"
" <property name='child'>\n"
" <object class='GtkInscription'>\n"
" <object class='GtkLabel'>\n"
" <property name='ellipsize'>end</property>\n"
" <property name='xalign'>0</property>\n"
" <binding name='text'>\n"
" <binding name='label'>\n"
" <lookup name='string' type='GtkStringObject'>\n"
" <lookup name='item'>GtkListItem</lookup>\n"
" </lookup>\n"
+3 -3
View File
@@ -7,9 +7,9 @@
<lookup name="item">GtkListItem</lookup>
</binding>
<property name="child">
<object class="GtkInscription">
<property name="hexpand">1</property>
<binding name="text">
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<lookup name="title" type="GtkDemo">
<lookup name="item">expander</lookup>
</lookup>
+2 -2
View File
@@ -190,8 +190,8 @@ activate_about (GSimpleAction *action,
glib_major_version,
glib_minor_version,
glib_micro_version);
g_string_append_printf (s, "\tPango2\t%s\n",
pango2_version_string ());
g_string_append_printf (s, "\tPango\t%s\n",
pango_version_string ());
g_string_append_printf (s, "\tGTK \t%d.%d.%d\n",
gtk_get_major_version (),
gtk_get_minor_version (),
+3 -3
View File
@@ -7,9 +7,9 @@ Text weights: <span weight="thin">thin</span> <span weight="light">light</span>
Text <span color="gray">c<span color="green">o</span>l<span color="tomato">o</span>rs</span> and <span background="pink">backgrounds</span>
Colorful <span underline_position="under" underline-color="blue"><span underline="double" underline-color="red">under</span>lines</span> and <span background="pink"><span underline="wavy">mo</span><span underline="wavy" underline-color="green">re</span></span>
Colorful <span underline="low" underline-color="blue"><span underline="double" underline-color="red">under</span>lines</span> and <span background="pink"><span underline="error">mo</span><span underline="error" underline-color="green">re</span></span>
Colorful <span strikethrough="solid" strikethrough-color="magenta">strikethroughs</span> and <span overline="solid" overline_color="green">overlines</span>
Colorful <span strikethrough="true" strikethrough-color="magenta">strikethroughs</span> and <span overline="single" overline_color="green">overlines</span>
Superscripts and subscripts: 𝜀<span rise="-6000" size="x-small" font_desc="italic">0</span> = 𝜔<span rise="8000" size="smaller">𝜔<span rise="14000" size="smaller">𝜔<span rise="20000">.<span rise="23000">.<span rise="26000">.</span></span></span></span></span>
@@ -19,7 +19,7 @@ OpenType font features: <span font_desc="sans regular" font_features="dlig=0">fe
Shortcuts: <tt>Monospace</tt> <b>Bold</b> <i>Italic</i> <big>Big</big> <small>Small</small> <u>Underlined</u> <s>Strikethrough</s> Super<sup>script</sup> Sub<sub>script</sub>
A hy­phen­ation al­go­rithm is a <span allow_breaks="false" style="italic">set of rules</span>, espe­ci­ally one co­di­fied for im­ple­men­tation in a com­pu­ter pro­gram, that de­ci­des at which points a word can be bro­ken over two lines with a hy­phen. For ex­am­ple, a hy­phen­ation al­go­rithm might de­cide that im­peach­ment can be broken as impeach‧ment or im‧peachment but not impe‧achment.
hy­phen­ation al­go­rithm is a <span allow_breaks="false" style="italic">set of rules</span>, espe­ci­ally one co­di­fied for im­ple­men­tation in a com­pu­ter pro­gram, that de­ci­des at which points a word can be bro­ken over two lines with a hy­phen. For ex­am­ple, a hy­phen­ation al­go­rithm might de­cide that im­peach­ment can be broken as impeach‧ment or im‧peachment but not impe‧achment.
<span insert_hyphens="false">one/two three/four five/six seven/eight nine/ten</span>
+9 -2
View File
@@ -17,6 +17,7 @@ demos = files([
'css_pixbufs.c',
'css_shadows.c',
'cursors.c',
'curve.c',
'dialog.c',
'drawingarea.c',
'dnd.c',
@@ -34,6 +35,7 @@ demos = files([
'gestures.c',
'glarea.c',
'gltransition.c',
'glyphs.c',
'headerbar.c',
'hypertext.c',
'iconscroll.c',
@@ -70,12 +72,14 @@ demos = files([
'paintable_symbolic.c',
'panes.c',
'password_entry.c',
'path_fill.c',
'path_maze.c',
'path_text.c',
'peg_solitaire.c',
'pickers.c',
'printing.c',
'read_more.c',
'revealer.c',
#'rotated_text.c', FIXME
'rotated_text.c',
'scale.c',
'search_entry.c',
'search_entry2.c',
@@ -131,6 +135,9 @@ extra_demo_sources = files([
'unicode-names.c',
'suggestionentry.c',
'language-names.c',
'curve-editor.c',
'nodewidget.c',
'graphwidget.c',
])
if os_unix
+76
View File
@@ -0,0 +1,76 @@
#include "nodewidget.h"
struct _NodeWidget
{
GtkWidget parent_instance;
GskRenderNode *node;
};
struct _NodeWidgetClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (NodeWidget, node_widget, GTK_TYPE_WIDGET)
static void
node_widget_init (NodeWidget *self)
{
}
static void
node_widget_dispose (GObject *object)
{
NodeWidget *self = NODE_WIDGET (object);
gsk_render_node_unref (self->node);
G_OBJECT_CLASS (node_widget_parent_class)->dispose (object);
}
static void
node_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
NodeWidget *self = NODE_WIDGET (widget);
gtk_snapshot_append_node (snapshot, self->node);
}
static void
node_widget_class_init (NodeWidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = node_widget_dispose;
widget_class->snapshot = node_widget_snapshot;
}
GtkWidget *
node_widget_new (const char *resource)
{
NodeWidget *self;
GBytes *bytes;
GskRenderNode *node;
graphene_rect_t bounds;
float scale;
GskTransform *transform;
self = g_object_new (NODE_TYPE_WIDGET, NULL);
bytes = g_resources_lookup_data (resource, 0, NULL);
node = gsk_render_node_deserialize (bytes, NULL, NULL);
g_bytes_unref (bytes);
gsk_render_node_get_bounds (node, &bounds);
scale = MIN (100.0/bounds.size.width, 100.0/bounds.size.height);
transform = gsk_transform_scale (NULL, scale, scale);
self->node = gsk_transform_node_new (node, transform);
gsk_transform_unref (transform);
gsk_render_node_unref (node);
return GTK_WIDGET (self);
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <gtk/gtk.h>
#define NODE_TYPE_WIDGET (node_widget_get_type ())
G_DECLARE_FINAL_TYPE (NodeWidget, node_widget, NODE, WIDGET, GtkWidget)
GtkWidget * node_widget_new (const char *file);
+348
View File
@@ -0,0 +1,348 @@
/* Path/Text Fill
*
* This demo shows how to use PangoCairo to draw text with more than
* just a single color.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "paintable.h"
#include "gsk/gskpathdashprivate.h"
#define GTK_TYPE_PATH_PAINTABLE (gtk_path_paintable_get_type ())
G_DECLARE_FINAL_TYPE (GtkPathPaintable, gtk_path_paintable, GTK, PATH_PAINTABLE, GObject)
struct _GtkPathPaintable
{
GObject parent_instance;
int width;
int height;
GskPath *path;
GdkPaintable *background;
};
struct _GtkPathPaintableClass
{
GObjectClass parent_class;
};
static int
gtk_path_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
if (self->background)
return MAX (gdk_paintable_get_intrinsic_width (self->background), self->width);
else
return self->width;
}
static int
gtk_path_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
if (self->background)
return MAX (gdk_paintable_get_intrinsic_height (self->background), self->height);
else
return self->height;
}
static void
gtk_path_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
#if 0
gtk_snapshot_push_fill (snapshot, self->path, GSK_FILL_RULE_WINDING);
#else
GskStroke *stroke = gsk_stroke_new (2.0);
gtk_snapshot_push_stroke (snapshot, self->path, stroke);
gsk_stroke_free (stroke);
#endif
if (self->background)
{
gdk_paintable_snapshot (self->background, snapshot, width, height);
}
else
{
gtk_snapshot_append_linear_gradient (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (0, 0),
&GRAPHENE_POINT_INIT (width, height),
(GskColorStop[8]) {
{ 0.0, { 1.0, 0.0, 0.0, 1.0 } },
{ 0.2, { 1.0, 0.0, 0.0, 1.0 } },
{ 0.3, { 1.0, 1.0, 0.0, 1.0 } },
{ 0.4, { 0.0, 1.0, 0.0, 1.0 } },
{ 0.6, { 0.0, 1.0, 1.0, 1.0 } },
{ 0.7, { 0.0, 0.0, 1.0, 1.0 } },
{ 0.8, { 1.0, 0.0, 1.0, 1.0 } },
{ 1.0, { 1.0, 0.0, 1.0, 1.0 } }
},
8);
}
gtk_snapshot_pop (snapshot);
}
static GdkPaintableFlags
gtk_path_paintable_get_flags (GdkPaintable *paintable)
{
GtkPathPaintable *self = GTK_PATH_PAINTABLE (paintable);
if (self->background)
return gdk_paintable_get_flags (self->background);
else
return GDK_PAINTABLE_STATIC_CONTENTS | GDK_PAINTABLE_STATIC_SIZE;
}
static void
gtk_path_paintable_paintable_init (GdkPaintableInterface *iface)
{
iface->get_intrinsic_width = gtk_path_paintable_get_intrinsic_width;
iface->get_intrinsic_height = gtk_path_paintable_get_intrinsic_height;
iface->snapshot = gtk_path_paintable_snapshot;
iface->get_flags = gtk_path_paintable_get_flags;
}
/* When defining the GType, we need to implement the GdkPaintable interface */
G_DEFINE_TYPE_WITH_CODE (GtkPathPaintable, gtk_path_paintable, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_path_paintable_paintable_init))
/* Here's the boilerplate for the GObject declaration.
* We don't need to do anything special here, because we keep no
* data of our own.
*/
static void
gtk_path_paintable_class_init (GtkPathPaintableClass *klass)
{
}
static void
gtk_path_paintable_init (GtkPathPaintable *self)
{
}
/* And finally, we add a simple constructor.
* It is declared in the header so that the other examples
* can use it.
*/
GdkPaintable *
gtk_path_paintable_new (GskPath *path,
GdkPaintable *background,
int width,
int height)
{
GtkPathPaintable *self;
self = g_object_new (GTK_TYPE_PATH_PAINTABLE, NULL);
self->path = path;
self->background = background;
if (self->background)
{
g_signal_connect_swapped (self->background, "invalidate-contents", G_CALLBACK (gdk_paintable_invalidate_contents), self);
g_signal_connect_swapped (self->background, "invalidate-size", G_CALLBACK (gdk_paintable_invalidate_size), self);
}
self->width = width;
self->height = height;
return GDK_PAINTABLE (self);
}
void
gtk_path_paintable_set_path (GtkPathPaintable *self,
GskPath *path)
{
g_clear_pointer (&self->path, gsk_path_unref);
self->path = gsk_path_ref (path);
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
}
static GskPath *
create_hexagon (GtkWidget *widget)
{
GskPathBuilder *builder;
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder, 120, 0);
gsk_path_builder_line_to (builder, 360, 0);
gsk_path_builder_line_to (builder, 480, 208);
gsk_path_builder_line_to (builder, 360, 416);
gsk_path_builder_line_to (builder, 120, 416);
gsk_path_builder_line_to (builder, 0, 208);
gsk_path_builder_close (builder);
return gsk_path_builder_free_to_path (builder);
}
static GskPath *
create_path_from_text (GtkWidget *widget)
{
PangoLayout *layout;
PangoFontDescription *desc;
GskPathBuilder *builder;
layout = gtk_widget_create_pango_layout (widget, "Pango power!\nPango power!\nPango power!");
desc = pango_font_description_from_string ("sans bold 36");
pango_layout_set_font_description (layout, desc);
pango_font_description_free (desc);
builder = gsk_path_builder_new ();
gsk_path_builder_add_layout (builder, layout);
return gsk_path_builder_free_to_path (builder);
}
static gboolean
build_path (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
gpointer user_data)
{
GskPathBuilder *builder = user_data;
switch (op)
{
case GSK_PATH_MOVE:
gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
break;
case GSK_PATH_CLOSE:
gsk_path_builder_close (builder);
break;
case GSK_PATH_LINE:
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
break;
case GSK_PATH_CURVE:
gsk_path_builder_curve_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
break;
case GSK_PATH_CONIC:
gsk_path_builder_conic_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y, weight);
break;
default:
g_assert_not_reached ();
break;
}
return TRUE;
}
static gboolean
update_path (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer measure)
{
float progress = gdk_frame_clock_get_frame_time (frame_clock) % (60 * G_USEC_PER_SEC) / (float) (30 * G_USEC_PER_SEC);
GskPathBuilder *builder;
GskPath *path;
graphene_point_t pos;
graphene_vec2_t tangent;
GskStroke *stroke;
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder,
measure,
#if 1
0.0, gsk_path_measure_get_length (measure));
#else
progress > 1 ? (progress - 1) * gsk_path_measure_get_length (measure) : 0.0,
(progress < 1 ? progress : 1.0) * gsk_path_measure_get_length (measure));
#endif
path = gsk_path_builder_free_to_path (builder);
stroke = gsk_stroke_new (1);
gsk_stroke_set_dash (stroke, (float[2]) { 10, 5 }, 2);
gsk_stroke_set_dash_offset (stroke, - (gdk_frame_clock_get_frame_time (frame_clock) % G_USEC_PER_SEC) * 15. / G_USEC_PER_SEC);
builder = gsk_path_builder_new ();
gsk_path_dash (path, stroke, 0.2, build_path, builder);
gsk_path_unref (path);
gsk_path_measure_get_point (measure,
(progress > 1 ? (progress - 1) : progress) * gsk_path_measure_get_length (measure),
&pos,
&tangent);
gsk_path_builder_move_to (builder, pos.x + 5 * graphene_vec2_get_x (&tangent), pos.y + 5 * graphene_vec2_get_y (&tangent));
gsk_path_builder_line_to (builder, pos.x + 3 * graphene_vec2_get_y (&tangent), pos.y + 3 * graphene_vec2_get_x (&tangent));
gsk_path_builder_line_to (builder, pos.x - 3 * graphene_vec2_get_y (&tangent), pos.y - 3 * graphene_vec2_get_x (&tangent));
gsk_path_builder_close (builder);
path = gsk_path_builder_free_to_path (builder);
gtk_path_paintable_set_path (GTK_PATH_PAINTABLE (gtk_picture_get_paintable (GTK_PICTURE (widget))),
path);
gsk_path_unref (path);
return G_SOURCE_CONTINUE;
}
GtkWidget *
do_path_fill (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *picture;
GdkPaintable *paintable;
GtkMediaStream *stream;
GskPath *path;
graphene_rect_t bounds;
GskPathMeasure *measure;
window = gtk_window_new ();
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
gtk_window_set_title (GTK_WINDOW (window), "Path Fill");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
#if 0
stream = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
#else
stream = gtk_nuclear_media_stream_new ();
#endif
gtk_media_stream_play (stream);
gtk_media_stream_set_loop (stream, TRUE);
path = create_hexagon (window);
path = create_path_from_text (window);
gsk_path_get_bounds (path, &bounds);
paintable = gtk_path_paintable_new (path,
GDK_PAINTABLE (stream),
bounds.origin.x + bounds.size.width,
bounds.origin.y + bounds.size.height);
picture = gtk_picture_new_for_paintable (paintable);
measure = gsk_path_measure_new (path);
gtk_widget_add_tick_callback (picture, update_path, measure, (GDestroyNotify) gsk_path_measure_unref);
gtk_picture_set_keep_aspect_ratio (GTK_PICTURE (picture), FALSE);
gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
g_object_unref (paintable);
gtk_window_set_child (GTK_WINDOW (window), picture);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

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