Compare commits

..

18 Commits

Author SHA1 Message Date
Matthias Clasen
a2bb1e6f13 Make the testsuite pass
We were crashing while finalizing the solver.
2019-06-26 05:15:40 +00:00
Matthias Clasen
93b707f0e2 Add an interactive constraints demo 2019-06-26 04:40:20 +00:00
Matthias Clasen
959bc0e816 Add gtk_constraint_layout_remove_constraint
Otherwise, you can't do many interesting things.
2019-06-26 04:25:45 +00:00
Matthias Clasen
5f3e661c37 Make the constraints demo more interesting
Add a max size to the buttons, to force the
space to open up.
2019-06-26 04:25:45 +00:00
Matthias Clasen
ea8bf0fc1e constraints: Make internal consistency required
The relations between left, right, width
and top, bottom, height are required for
internal consistency. It doesn't make sense
to ever drop these.

Changing the strength of these relations makes
my systems behave much more stable.
2019-06-26 04:25:45 +00:00
Matthias Clasen
9a438a8bfc Add GtkConstraintGuide
This is meant to be a flexible space.
2019-06-26 04:25:44 +00:00
Matthias Clasen
e5a8c4e4ab constraints demo: Use GtkConstraintTarget 2019-06-26 04:25:44 +00:00
Matthias Clasen
8cae495994 Redefine constraints with GtkConstraintTarget
This is in preparation for allowing non-widgets
to act as constraint targets.
2019-06-26 04:25:44 +00:00
Matthias Clasen
9ad690fb7d widget: Implement GtkConstraintTarget 2019-06-26 04:25:44 +00:00
Matthias Clasen
44670cf58b Add GtkConstraintTarget
This is an marker interface that we will
use to accept other things that widgets
in constraints.
2019-06-26 04:25:44 +00:00
Emmanuele Bassi
6835ce4a95 Do not leak LayoutChild instances
Since the LayoutManager owns the LayoutChild it creates, it's also
responsible for mopping them up.
2019-06-17 09:28:33 +01:00
Emmanuele Bassi
5ed66d069d Add GtkConstraintLayout demo 2019-06-17 09:28:33 +01:00
Emmanuele Bassi
5472cc5fe9 Add GtkConstraintLayout
A layout manager using GtkConstraintSolver to measure and allocate
children.
2019-06-17 09:28:33 +01:00
Emmanuele Bassi
556a51d862 Propagate rooting and unrooting widgets to layout managers
Layout managers may need to get access to data attached to the root of a
scene graph.
2019-06-17 09:28:33 +01:00
Emmanuele Bassi
6e8feebb3b window: Create a GtkConstraintSolver
Implement the GtkRoot getter for GtkConstraintSolver.
2019-06-17 09:28:33 +01:00
Emmanuele Bassi
78e86b4df1 Assign a GtkConstraintSolver to each GtkRoot
Constraints need to work across different parents, so it's better to
have a single constraint solver per top level.
2019-06-17 09:28:32 +01:00
Emmanuele Bassi
13d7f59c40 Move the Root interface to a private header
We don't expect out of tree implementations of GtkRoot, and having the
interface structure private to the GTK code allows us to add virtual
functions involving private types.
2019-06-17 09:28:32 +01:00
Emmanuele Bassi
aec8da3363 Add constraint solver
GtkConstraintSolver is an implementation of the Cassowary constraint
solving algorithm:

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

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

  x = y × coefficient + constant

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

These equations can be used to describe constraints applied to a layout
of UI elements, which allows layout managers using the Cassowary method
to quickly, and efficiently, lay out widgets in complex relations
between themselves and their parent container.
2019-06-17 09:28:32 +01:00
927 changed files with 79881 additions and 220448 deletions

View File

@@ -1,7 +1,7 @@
stages:
- build
- flatpak
# - deploy
- deploy
.cache-paths: &cache-paths
paths:
@@ -12,8 +12,8 @@ stages:
- subprojects/libepoxy/
- subprojects/pango/
fedora-x86_64: &fedora-x86_64-defaults
image: registry.gitlab.gnome.org/gnome/gtk/master:v7
fedora-x86_64:
image: registry.gitlab.gnome.org/gnome/gtk/master:v6
stage: build
script:
- bash -x ./.gitlab-ci/test-docker.sh
@@ -33,11 +33,6 @@ fedora-x86_64: &fedora-x86_64-defaults
key: "$CI_JOB_NAME"
<<: *cache-paths
fedora-x86_64-staticlibs:
variables:
EXTRA_MESON_FLAGS: "-Ddefault_library=both"
<<: *fedora-x86_64-defaults
.mingw-defaults: &mingw-defaults
stage: build
tags:
@@ -45,7 +40,6 @@ fedora-x86_64-staticlibs:
script:
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
- C:\msys64\usr\bin\bash -lc "bash -x ./.gitlab-ci/test-msys2.sh"
allow_failure: true
cache:
key: "%CI_JOB_NAME%"
<<: *cache-paths
@@ -107,19 +101,20 @@ flatpak-master:icon-browser:
APPID: org.gtk.IconBrowser4
<<: *flatpak-master
#pages:
# image: registry.gitlab.gnome.org/gnome/gtk/master:v6
# stage: deploy
# script:
# - meson -Dgtk_doc=true _build .
# - ninja -C _build
# - ninja -C _build gdk4-doc gsk4-doc gtk4-doc
# - mkdir -p public/
# - mv _build/docs/reference/gtk/html/ public/gtk/
# - mv _build/docs/reference/gdk/html/ public/gdk/
# - mv _build/docs/reference/gsk/html/ public/gsk/
# artifacts:
# paths:
# - public
# only:
# - master
pages:
image: registry.gitlab.gnome.org/gnome/gtk/master:v6
stage: deploy
script:
- meson -Ddocumentation=true _build .
- ninja -C _build
- ninja -C _build gdk4-doc gsk4-doc gtk4-doc
- mkdir -p public/
- mv _build/docs/reference/gtk/html/ public/gtk/
- mv _build/docs/reference/gdk/html/ public/gdk/
- mv _build/docs/reference/gsk/html/ public/gsk/
artifacts:
paths:
- public
only:
- master

View File

@@ -1,6 +1,7 @@
FROM fedora:31
FROM fedora:30
RUN dnf -y install \
hicolor-icon-theme \
adwaita-icon-theme \
atk-devel \
at-spi2-atk-devel \
@@ -13,7 +14,6 @@ RUN dnf -y install \
dbus-daemon \
dejavu-sans-mono-fonts \
desktop-file-utils \
diffutils \
elfutils-libelf-devel \
fribidi-devel \
gcc \
@@ -32,7 +32,6 @@ RUN dnf -y install \
gstreamer1-plugins-bad-free-devel \
gstreamer1-plugins-base-devel \
gtk-doc \
hicolor-icon-theme \
iso-codes \
itstool \
json-glib-devel \

View File

@@ -149,11 +149,11 @@ ul.images li {
<article>
<section>
<div class="summary">
<h3><a name="summary">Summary</a></h3>
<h3>Summary</h3>
<ul>
<li><strong>Total units:</strong> {{ report.total_units }}</li>
<li><strong>Passed:</strong> <a href="#passed">{{ report.total_successes }}</a></li>
<li><strong>Failed:</strong> <a href="#failures">{{ report.total_failures }}</a></li>
<li><strong>Passed:</strong> {{ report.total_successes }}</li>
<li><strong>Failed:</strong> {{ report.total_failures }}</li>
</ul>
</div>
</section>
@@ -161,7 +161,7 @@ ul.images li {
{% for suite_result in report.results_list %}
<section>
<div class="result">
<h3><a name="results">Suite: {{ suite_result.suite_name }}</a></h3>
<h3>Suite: {{ suite_result.suite_name }}</h3>
<ul>
<li><strong>Units:</strong> {{ suite_result.n_units }}</li>
<li><strong>Passed:</strong> {{ suite_result.n_successes }}</li>
@@ -169,7 +169,7 @@ ul.images li {
</ul>
<div class="successes">
<h4><a name="passed">Passed</a></h4>
<h4>Passed</h4>
<ul class="passed">
{% for success in suite_result.successes if success.result == 'OK' %}
<li>{{ success.name }} - result: <span class="result pass">{{ success.result }}</li>
@@ -178,7 +178,7 @@ ul.images li {
{% endfor %}
</ul>
<h4><a name="skipped">Skipped</a></h4>
<h4>Skipped</h4>
<ul>
{% for success in suite_result.successes if success.result == 'SKIP' %}
<li>{{ success.name }} - result: <span class="result skip">{{ success.result }}</li>
@@ -187,10 +187,10 @@ ul.images li {
{% endfor %}
</ul>
<h4><a name="expected-fail">Expected failures</a></h4>
<h4>Expected failures</h4>
<ul>
{% for success in suite_result.successes if success.result == 'EXPECTEDFAIL' %}
<li><a name="{{ success.name }}">{{ success.name }}</a> - result: <span class="result xfail">{{ success.result }}</span><br/>
<li>{{ success.name }} - result: <span class="result xfail">{{ success.result }}</span><br/>
{% if success.stdout %}
Output: <pre>{{ success.stdout }}</pre>
{% endif %}
@@ -209,10 +209,10 @@ ul.images li {
</div>
<div class="failures">
<h4><a name="failed">Failed</a></h4>
<h4>Failed</h4>
<ul class="failed">
{% for failure in suite_result.failures if failure.result == 'FAIL' %}
<li><a name="{{ failure.name }}">{{ failure.name }}</a> - result: <span class="result fail">{{ failure.result }}</span><br/>
<li>{{ failure.name }} - result: <span class="result fail">{{ failure.result }}</span><br/>
{% if failure.stdout %}
Output: <pre>{{ failure.stdout }}</pre>
{% endif %}
@@ -229,10 +229,10 @@ ul.images li {
{% endfor %}
</ul>
<h4><a name="timed-out">Timed out</a></h4>
<h4>Timed out</h4>
<ul class="failed">
{% for failure in suite_result.failures if failure.result == 'TIMEOUT' %}
<li><a name="{{ failure.name }}">{{ failure.name }}</a> - result: <span class="result fail">{{ failure.result }}</span><br/>
<li>{{ failure.name }} - result: <span class="result fail">{{ failure.result }}</span><br/>
{% if failure.stdout %}
Output: <pre>{{ failure.stdout }}</pre>
{% endif %}

View File

@@ -2,7 +2,7 @@
set -e
TAG="registry.gitlab.gnome.org/gnome/gtk/master:v7"
TAG="registry.gitlab.gnome.org/gnome/gtk/master:v6"
sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \
--file "Dockerfile" .

View File

@@ -17,7 +17,6 @@ meson \
-Dbroadway-backend=true \
-Dvulkan=yes \
--werror \
${EXTRA_MESON_FLAGS:-} \
_build $srcdir
unset CCACHE_DISABLE

View File

@@ -56,6 +56,12 @@
/* Define if GStreamer support is available */
#mesondefine HAVE_GSTREAMER
/* Define to 1 if you have the `httpGetAuthString' function. */
#mesondefine HAVE_HTTPGETAUTHSTRING
/* Define if cups http_t authstring field is accessible */
#mesondefine HAVE_HTTP_AUTHSTRING
/* Define to 1 if you have the <inttypes.h> header file. */
#mesondefine HAVE_INTTYPES_H
@@ -185,6 +191,9 @@
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#mesondefine LT_OBJDIR
/* Define if <X11/extensions/XIproto.h> needed for xReply */
#mesondefine NEED_XIPROTO_H_FOR_XREPLY
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
#mesondefine NO_MINUS_C_MINUS_O

View File

@@ -1,115 +0,0 @@
/*
* Copyright © 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen
*/
#include "config.h"
#include "constraint-editor-application.h"
#include "constraint-editor-window.h"
struct _ConstraintEditorApplication
{
GtkApplication parent_instance;
};
G_DEFINE_TYPE(ConstraintEditorApplication, constraint_editor_application, GTK_TYPE_APPLICATION);
static void
constraint_editor_application_init (ConstraintEditorApplication *app)
{
}
static void
quit_activated (GSimpleAction *action,
GVariant *parameter,
gpointer data)
{
g_application_quit (G_APPLICATION (data));
}
static GActionEntry app_entries[] =
{
{ "quit", quit_activated, NULL, NULL, NULL }
};
static void
constraint_editor_application_startup (GApplication *app)
{
const char *quit_accels[2] = { "<Ctrl>Q", NULL };
const char *open_accels[2] = { "<Ctrl>O", NULL };
GtkCssProvider *provider;
G_APPLICATION_CLASS (constraint_editor_application_parent_class)->startup (app);
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);
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "win.open", open_accels);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/org/gtk/gtk4/constraint-editor/constraint-editor.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
static void
constraint_editor_application_activate (GApplication *app)
{
ConstraintEditorWindow *win;
win = constraint_editor_window_new (CONSTRAINT_EDITOR_APPLICATION (app));
gtk_window_present (GTK_WINDOW (win));
}
static void
constraint_editor_application_open (GApplication *app,
GFile **files,
gint n_files,
const gchar *hint)
{
ConstraintEditorWindow *win;
gint i;
for (i = 0; i < n_files; i++)
{
win = constraint_editor_window_new (CONSTRAINT_EDITOR_APPLICATION (app));
constraint_editor_window_load (win, files[i]);
gtk_window_present (GTK_WINDOW (win));
}
}
static void
constraint_editor_application_class_init (ConstraintEditorApplicationClass *class)
{
GApplicationClass *application_class = G_APPLICATION_CLASS (class);
application_class->startup = constraint_editor_application_startup;
application_class->activate = constraint_editor_application_activate;
application_class->open = constraint_editor_application_open;
}
ConstraintEditorApplication *
constraint_editor_application_new (void)
{
return g_object_new (CONSTRAINT_EDITOR_APPLICATION_TYPE,
"application-id", "org.gtk.gtk4.ConstraintEditor",
"flags", G_APPLICATION_HANDLES_OPEN,
NULL);
}

View File

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

View File

@@ -1,639 +0,0 @@
/*
* Copyright © 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen
*/
#include "config.h"
#include "constraint-editor-window.h"
#include "constraint-view.h"
#include "constraint-editor.h"
#include "guide-editor.h"
struct _ConstraintEditorWindow
{
GtkApplicationWindow parent_instance;
GtkWidget *paned;
GtkWidget *view;
GtkWidget *list;
};
G_DEFINE_TYPE(ConstraintEditorWindow, constraint_editor_window, GTK_TYPE_APPLICATION_WINDOW);
static GtkConstraintTarget *
find_target (GListModel *model,
GtkConstraintTarget *orig)
{
const char *name;
const char *model_name;
gpointer item;
int i;
if (orig == NULL)
return NULL;
if (GTK_IS_LABEL (orig))
name = gtk_label_get_label (GTK_LABEL (orig));
else if (GTK_IS_CONSTRAINT_GUIDE (orig))
name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (orig));
else
{
g_warning ("Don't know how to handle %s targets", G_OBJECT_TYPE_NAME (orig));
return NULL;
}
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
item = g_list_model_get_item (model, i);
g_object_unref (item);
if (GTK_IS_WIDGET (item))
model_name = gtk_widget_get_name (GTK_WIDGET (item));
else
model_name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item));
if (strcmp (name, model_name) == 0)
return GTK_CONSTRAINT_TARGET (item);
}
g_warning ("Failed to find target '%s'", name);
return NULL;
}
gboolean
constraint_editor_window_load (ConstraintEditorWindow *self,
GFile *file)
{
char *path;
GtkBuilder *builder;
GError *error = NULL;
GtkWidget *view;
GtkLayoutManager *layout;
GtkWidget *child;
const char *name;
gpointer item;
int i;
GListModel *list;
path = g_file_get_path (file);
builder = gtk_builder_new ();
if (!gtk_builder_add_from_file (builder, path, &error))
{
g_print ("Could not load %s: %s", path, error->message);
g_error_free (error);
g_free (path);
g_object_unref (builder);
return FALSE;
}
view = GTK_WIDGET (gtk_builder_get_object (builder, "view"));
if (!GTK_IS_BOX (view))
{
g_print ("Could not load %s: No GtkBox named 'view'", path);
g_free (path);
g_object_unref (builder);
return FALSE;
}
layout = gtk_widget_get_layout_manager (view);
if (!GTK_IS_CONSTRAINT_LAYOUT (layout))
{
g_print ("Could not load %s: Widget 'view' does not use GtkConstraintLayout", path);
g_free (path);
g_object_unref (builder);
return FALSE;
}
for (child = gtk_widget_get_first_child (view);
child;
child = gtk_widget_get_next_sibling (child))
{
if (!GTK_IS_LABEL (child))
{
g_print ("Skipping non-GtkLabel child\n");
continue;
}
name = gtk_label_get_label (GTK_LABEL (child));
constraint_view_add_child (CONSTRAINT_VIEW (self->view), name);
}
list = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (layout));
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
GtkConstraintGuide *guide, *clone;
int w, h;
item = g_list_model_get_item (list, i);
guide = GTK_CONSTRAINT_GUIDE (item);
/* need to clone here, to attach to the right targets */
clone = gtk_constraint_guide_new ();
gtk_constraint_guide_set_name (clone, gtk_constraint_guide_get_name (guide));
gtk_constraint_guide_set_strength (clone, gtk_constraint_guide_get_strength (guide));
gtk_constraint_guide_get_min_size (guide, &w, &h);
gtk_constraint_guide_set_min_size (clone, w, h);
gtk_constraint_guide_get_nat_size (guide, &w, &h);
gtk_constraint_guide_set_nat_size (clone, w, h);
gtk_constraint_guide_get_max_size (guide, &w, &h);
gtk_constraint_guide_set_max_size (clone, w, h);
constraint_view_add_guide (CONSTRAINT_VIEW (self->view), clone);
g_object_unref (guide);
g_object_unref (clone);
}
g_object_unref (list);
list = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (layout));
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
GtkConstraint *constraint;
GtkConstraint *clone;
GtkConstraintTarget *target;
GtkConstraintTarget *source;
item = g_list_model_get_item (list, i);
constraint = GTK_CONSTRAINT (item);
target = gtk_constraint_get_target (constraint);
source = gtk_constraint_get_source (constraint);
clone = gtk_constraint_new (find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), target),
gtk_constraint_get_target_attribute (constraint),
gtk_constraint_get_relation (constraint),
find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), source),
gtk_constraint_get_target_attribute (constraint),
gtk_constraint_get_multiplier (constraint),
gtk_constraint_get_constant (constraint),
gtk_constraint_get_strength (constraint));
constraint_view_add_constraint (CONSTRAINT_VIEW (self->view), clone);
g_object_unref (constraint);
g_object_unref (clone);
}
g_object_unref (list);
g_free (path);
g_object_unref (builder);
return TRUE;
}
static void
open_response_cb (GtkNativeDialog *dialog,
gint response,
ConstraintEditorWindow *self)
{
gtk_native_dialog_hide (dialog);
if (response == GTK_RESPONSE_ACCEPT)
{
GFile *file;
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
constraint_editor_window_load (self, file);
g_object_unref (file);
}
gtk_native_dialog_destroy (dialog);
}
static void
open_cb (GtkWidget *button,
ConstraintEditorWindow *self)
{
GtkFileChooserNative *dialog;
dialog = gtk_file_chooser_native_new ("Open file",
GTK_WINDOW (self),
GTK_FILE_CHOOSER_ACTION_OPEN,
"_Load",
"_Cancel");
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), ".");
g_signal_connect (dialog, "response", G_CALLBACK (open_response_cb), self);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
}
static void
serialize_child (GString *str,
int indent,
GtkWidget *child)
{
const char *name;
name = gtk_widget_get_name (child);
g_string_append_printf (str, "%*s<child>\n", indent, "");
g_string_append_printf (str, "%*s <object class=\"GtkLabel\" id=\"%s\">\n", indent, "", name);
g_string_append_printf (str, "%*s <property name=\"label\">%s</property>\n", indent, "", name);
g_string_append_printf (str, "%*s </object>\n", indent, "");
g_string_append_printf (str, "%*s</child>\n", indent, "");
}
static char *
serialize_model (GListModel *list)
{
GString *str = g_string_new ("");
int i;
g_string_append (str, "<interface>\n");
g_string_append (str, " <object class=\"GtkBox\" id=\"view\">\n");
g_string_append (str, " <property name=\"layout-manager\">\n");
g_string_append (str, " <object class=\"GtkConstraintLayout\">\n");
g_string_append (str, " <constraints>\n");
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
gpointer item = g_list_model_get_item (list, i);
g_object_unref (item);
if (GTK_IS_CONSTRAINT (item))
constraint_editor_serialize_constraint (str, 10, GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
guide_editor_serialize_guide (str, 10, GTK_CONSTRAINT_GUIDE (item));
}
g_string_append (str, " </constraints>\n");
g_string_append (str, " </object>\n");
g_string_append (str, " </property>\n");
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
gpointer item = g_list_model_get_item (list, i);
g_object_unref (item);
if (GTK_IS_WIDGET (item))
serialize_child (str, 4, GTK_WIDGET (item));
}
g_string_append (str, " </object>\n");
g_string_append (str, "</interface>\n");
return g_string_free (str, FALSE);
}
static void
save_response_cb (GtkNativeDialog *dialog,
gint response,
ConstraintEditorWindow *self)
{
gtk_native_dialog_hide (dialog);
if (response == GTK_RESPONSE_ACCEPT)
{
GListModel *model;
char *text, *filename;
GError *error = NULL;
model = constraint_view_get_model (CONSTRAINT_VIEW (self->view));
text = serialize_model (model);
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
if (!g_file_set_contents (filename, text, -1, &error))
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))),
GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"Saving failed");
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", error->message);
g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
g_error_free (error);
}
g_free (filename);
}
gtk_native_dialog_destroy (dialog);
}
static void
save_cb (GtkWidget *button,
ConstraintEditorWindow *self)
{
GtkFileChooserNative *dialog;
dialog = gtk_file_chooser_native_new ("Save constraints",
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (button))),
GTK_FILE_CHOOSER_ACTION_SAVE,
"_Save",
"_Cancel");
gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), ".");
g_signal_connect (dialog, "response", G_CALLBACK (save_response_cb), self);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
}
static void
constraint_editor_window_finalize (GObject *object)
{
//ConstraintEditorWindow *self = (ConstraintEditorWindow *)object;
G_OBJECT_CLASS (constraint_editor_window_parent_class)->finalize (object);
}
static int child_counter;
static int guide_counter;
static void
add_child (ConstraintEditorWindow *win)
{
char *name;
child_counter++;
name = g_strdup_printf ("Child %d", child_counter);
constraint_view_add_child (CONSTRAINT_VIEW (win->view), name);
g_free (name);
}
static void
add_guide (ConstraintEditorWindow *win)
{
char *name;
GtkConstraintGuide *guide;
guide_counter++;
name = g_strdup_printf ("Guide %d", guide_counter);
guide = gtk_constraint_guide_new ();
gtk_constraint_guide_set_name (guide, name);
g_free (name);
constraint_view_add_guide (CONSTRAINT_VIEW (win->view), guide);
}
static void
constraint_editor_done (ConstraintEditor *editor,
GtkConstraint *constraint,
ConstraintEditorWindow *win)
{
GtkConstraint *old_constraint;
g_object_get (editor, "constraint", &old_constraint, NULL);
if (old_constraint)
constraint_view_remove_constraint (CONSTRAINT_VIEW (win->view), old_constraint);
constraint_view_add_constraint (CONSTRAINT_VIEW (win->view), constraint);
g_clear_object (&old_constraint);
gtk_widget_destroy (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW));
}
static void
edit_constraint (ConstraintEditorWindow *win,
GtkConstraint *constraint)
{
GtkWidget *window;
ConstraintEditor *editor;
GListModel *model;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win));
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
if (constraint)
gtk_window_set_title (GTK_WINDOW (window), "Edit Constraint");
else
gtk_window_set_title (GTK_WINDOW (window), "Create Constraint");
model = constraint_view_get_model (CONSTRAINT_VIEW (win->view));
editor = constraint_editor_new (model, constraint);
gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (editor));
g_signal_connect (editor, "done", G_CALLBACK (constraint_editor_done), win);
gtk_widget_show (window);
}
static void
add_constraint (ConstraintEditorWindow *win)
{
edit_constraint (win, NULL);
}
static void
guide_editor_done (GuideEditor *editor,
GtkConstraintGuide *guide,
ConstraintEditorWindow *win)
{
gtk_widget_destroy (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW));
}
static void
edit_guide (ConstraintEditorWindow *win,
GtkConstraintGuide *guide)
{
GtkWidget *window;
GuideEditor *editor;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win));
gtk_window_set_title (GTK_WINDOW (window), "Edit Guide");
editor = guide_editor_new (guide);
gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (editor));
g_signal_connect (editor, "done", G_CALLBACK (guide_editor_done), win);
gtk_widget_show (window);
}
static void
row_activated (GtkListBox *list,
GtkListBoxRow *row,
ConstraintEditorWindow *win)
{
GObject *item;
item = G_OBJECT (g_object_get_data (G_OBJECT (row), "item"));
if (GTK_IS_CONSTRAINT (item))
edit_constraint (win, GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
edit_guide (win, GTK_CONSTRAINT_GUIDE (item));
}
static void
constraint_editor_window_class_init (ConstraintEditorWindowClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
g_type_ensure (CONSTRAINT_VIEW_TYPE);
object_class->finalize = constraint_editor_window_finalize;
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/constraint-editor/constraint-editor-window.ui");
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, paned);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, view);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, list);
gtk_widget_class_bind_template_callback (widget_class, open_cb);
gtk_widget_class_bind_template_callback (widget_class, save_cb);
gtk_widget_class_bind_template_callback (widget_class, add_child);
gtk_widget_class_bind_template_callback (widget_class, add_guide);
gtk_widget_class_bind_template_callback (widget_class, add_constraint);
gtk_widget_class_bind_template_callback (widget_class, row_activated);
}
static void
row_edit (GtkButton *button,
ConstraintEditorWindow *win)
{
GtkWidget *row;
GObject *item;
row = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_LIST_BOX_ROW);
item = (GObject *)g_object_get_data (G_OBJECT (row), "item");
if (GTK_IS_CONSTRAINT (item))
edit_constraint (win, GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
edit_guide (win, GTK_CONSTRAINT_GUIDE (item));
}
static void
mark_constraints_invalid (ConstraintEditorWindow *win,
gpointer removed)
{
GtkWidget *child;
GObject *item;
for (child = gtk_widget_get_first_child (win->list);
child;
child = gtk_widget_get_next_sibling (child))
{
item = (GObject *)g_object_get_data (G_OBJECT (child), "item");
if (GTK_IS_CONSTRAINT (item))
{
GtkConstraint *constraint = GTK_CONSTRAINT (item);
if (gtk_constraint_get_target (constraint) == (GtkConstraintTarget *)removed ||
gtk_constraint_get_source (constraint) == (GtkConstraintTarget *)removed)
{
GtkWidget *button;
button = (GtkWidget *)g_object_get_data (G_OBJECT (child), "edit");
gtk_button_set_icon_name (GTK_BUTTON (button), "dialog-warning-symbolic");
gtk_widget_set_tooltip_text (button, "Constraint is invalid");
}
}
}
}
static void
row_delete (GtkButton *button,
ConstraintEditorWindow *win)
{
GtkWidget *row;
GObject *item;
row = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_LIST_BOX_ROW);
item = (GObject *)g_object_get_data (G_OBJECT (row), "item");
if (GTK_IS_CONSTRAINT (item))
constraint_view_remove_constraint (CONSTRAINT_VIEW (win->view),
GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
{
mark_constraints_invalid (win, item);
constraint_view_remove_guide (CONSTRAINT_VIEW (win->view),
GTK_CONSTRAINT_GUIDE (item));
}
else if (GTK_IS_WIDGET (item))
{
mark_constraints_invalid (win, item);
constraint_view_remove_child (CONSTRAINT_VIEW (win->view),
GTK_WIDGET (item));
}
}
static GtkWidget *
create_widget_func (gpointer item,
gpointer user_data)
{
ConstraintEditorWindow *win = user_data;
const char *name;
char *freeme = NULL;
GtkWidget *row, *box, *label, *button;
if (GTK_IS_WIDGET (item))
name = gtk_widget_get_name (GTK_WIDGET (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item));
else if (GTK_IS_CONSTRAINT (item))
name = freeme = constraint_editor_constraint_to_string (GTK_CONSTRAINT (item));
else
name = "";
row = gtk_list_box_row_new ();
g_object_set_data_full (G_OBJECT (row), "item", g_object_ref (item), g_object_unref);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
label = gtk_label_new (name);
if (GTK_IS_WIDGET (item) || GTK_IS_CONSTRAINT_GUIDE (item))
g_object_bind_property (item, "name",
label, "label",
G_BINDING_DEFAULT);
g_object_set (label, "margin", 10, NULL);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_widget_set_hexpand (label, TRUE);
gtk_container_add (GTK_CONTAINER (row), box);
gtk_container_add (GTK_CONTAINER (box), label);
if (GTK_IS_CONSTRAINT (item) || GTK_IS_CONSTRAINT_GUIDE (item))
{
button = gtk_button_new_from_icon_name ("document-edit-symbolic");
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_edit), win);
g_object_set_data (G_OBJECT (row), "edit", button);
gtk_container_add (GTK_CONTAINER (box), button);
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
gtk_container_add (GTK_CONTAINER (box), button);
}
else if (GTK_IS_WIDGET (item))
{
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
gtk_container_add (GTK_CONTAINER (box), button);
}
g_free (freeme);
return row;
}
static void
constraint_editor_window_init (ConstraintEditorWindow *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
gtk_list_box_bind_model (GTK_LIST_BOX (self->list),
constraint_view_get_model (CONSTRAINT_VIEW (self->view)),
create_widget_func,
self,
NULL);
}
ConstraintEditorWindow *
constraint_editor_window_new (ConstraintEditorApplication *application)
{
return g_object_new (CONSTRAINT_EDITOR_WINDOW_TYPE,
"application", application,
NULL);
}

View File

@@ -1,34 +0,0 @@
/*
* Copyright © 2019 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen
*/
#pragma once
#include <gtk/gtk.h>
#include "constraint-editor-application.h"
#define CONSTRAINT_EDITOR_WINDOW_TYPE (constraint_editor_window_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintEditorWindow, constraint_editor_window, CONSTRAINT, EDITOR_WINDOW, GtkApplicationWindow)
ConstraintEditorWindow * constraint_editor_window_new (ConstraintEditorApplication *application);
gboolean constraint_editor_window_load (ConstraintEditorWindow *self,
GFile *file);

View File

@@ -1,82 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="ConstraintEditorWindow" parent="GtkApplicationWindow">
<style>
<class name="devel"/>
</style>
<property name="title" translatable="yes">GTK Constraint Editor</property>
<property name="default-width">1024</property>
<property name="default-height">768</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="title" translatable="yes">GTK Constraint Editor</property>
<property name="show-title-buttons">1</property>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-open-symbolic</property>
<property name="tooltip-text">Open ui file</property>
<signal name="clicked" handler="open_cb"/>
</object>
</child>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-save-symbolic</property>
<property name="tooltip-text">Save to ui file</property>
<signal name="clicked" handler="save_cb"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkPaned" id="paned">
<property name="orientation">horizontal</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<child>
<object class="GtkButton">
<property name="label">Add Child</property>
<signal name="clicked" handler="add_child" swapped="yes"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Add Guide</property>
<signal name="clicked" handler="add_guide" swapped="yes"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Add Constraint</property>
<signal name="clicked" handler="add_constraint" swapped="yes"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<property name="vexpand">1</property>
<child>
<object class="GtkListBox" id="list">
<property name="show-separators">1</property>
<property name="selection-mode">none</property>
<signal name="row-activated" handler="row_activated"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="ConstraintView" id="view">
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -1,656 +0,0 @@
/*
* Copyright © 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen
*/
#include "config.h"
#include "constraint-editor.h"
struct _ConstraintEditor
{
GtkWidget parent_instance;
GtkWidget *grid;
GtkWidget *target;
GtkWidget *target_attr;
GtkWidget *relation;
GtkWidget *source;
GtkWidget *source_attr;
GtkWidget *multiplier;
GtkWidget *constant;
GtkWidget *strength;
GtkWidget *preview;
GtkWidget *button;
GtkConstraint *constraint;
GListModel *model;
gboolean constructed;
};
enum {
PROP_MODEL = 1,
PROP_CONSTRAINT,
LAST_PROP
};
static GParamSpec *pspecs[LAST_PROP];
enum {
DONE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE(ConstraintEditor, constraint_editor, GTK_TYPE_WIDGET);
static const char *
get_target_name (GtkConstraintTarget *target)
{
if (target == NULL)
return "super";
else if (GTK_IS_WIDGET (target))
return gtk_widget_get_name (GTK_WIDGET (target));
else if (GTK_IS_CONSTRAINT_GUIDE (target))
return gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (target));
else
return "";
}
static void
constraint_target_combo (GListModel *model,
GtkWidget *combo,
gboolean is_source)
{
int i;
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "super", "Super");
if (model)
{
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
GObject *item = g_list_model_get_object (model, i);
const char *name;
if (GTK_IS_CONSTRAINT (item))
continue;
name = get_target_name (GTK_CONSTRAINT_TARGET (item));
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), name, name);
g_object_unref (item);
}
}
}
static void
constraint_attribute_combo (GtkWidget *combo,
gboolean is_source)
{
if (is_source)
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "none", "None");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "left", "Left");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "right", "Right");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "top", "Top");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "bottom", "Bottom");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "start", "Start");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "end", "End");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "width", "Width");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "height", "Height");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "center-x", "Center X");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "center-y", "Center Y");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "baseline", "Baseline");
}
static void
constraint_relation_combo (GtkWidget *combo)
{
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "le", "");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "eq", "=");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "ge", "");
}
static void
constraint_strength_combo (GtkWidget *combo)
{
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "weak", "Weak");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "medium", "Medium");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "strong", "Strong");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "required", "Required");
}
static gpointer
get_target (GListModel *model,
const char *id)
{
int i;
if (strcmp ("super", id) == 0)
return NULL;
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
GObject *item = g_list_model_get_object (model, i);
g_object_unref (item);
if (GTK_IS_CONSTRAINT (item))
continue;
else if (GTK_IS_WIDGET (item))
{
if (strcmp (id, gtk_widget_get_name (GTK_WIDGET (item))) == 0)
return item;
}
else if (GTK_IS_CONSTRAINT_GUIDE (item))
{
if (strcmp (id, gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item))) == 0)
return item;
}
}
return NULL;
}
static GtkConstraintAttribute
get_target_attr (const char *id)
{
GtkConstraintAttribute attr;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_ATTRIBUTE);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
attr = value->value;
g_type_class_unref (class);
return attr;
}
static const char *
get_attr_nick (GtkConstraintAttribute attr)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_ATTRIBUTE);
GEnumValue *value = g_enum_get_value (class, attr);
const char *nick = value->value_nick;
g_type_class_unref (class);
return nick;
}
static GtkConstraintRelation
get_relation (const char *id)
{
GtkConstraintRelation relation;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_RELATION);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
relation = value->value;
g_type_class_unref (class);
return relation;
}
static const char *
get_relation_nick (GtkConstraintRelation relation)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_RELATION);
GEnumValue *value = g_enum_get_value (class, relation);
const char *nick = value->value_nick;
g_type_class_unref (class);
return nick;
}
static GtkConstraintStrength
get_strength (const char *id)
{
GtkConstraintStrength strength;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
strength = value->value;
g_type_class_unref (class);
return strength;
}
static const char *
get_strength_nick (GtkConstraintStrength strength)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value (class, strength);
const char *nick = value->value_nick;
g_type_class_unref (class);
return nick;
}
void
constraint_editor_serialize_constraint (GString *str,
int indent,
GtkConstraint *constraint)
{
const char *target;
const char *target_attr;
const char *relation;
const char *source;
const char *source_attr;
double multiplier;
double constant;
const char *strength;
target = get_target_name (gtk_constraint_get_target (constraint));
target_attr = get_attr_nick (gtk_constraint_get_target_attribute (constraint));
relation = get_relation_nick (gtk_constraint_get_relation (constraint));
source = get_target_name (gtk_constraint_get_source (constraint));
source_attr = get_attr_nick (gtk_constraint_get_source_attribute (constraint));
multiplier = gtk_constraint_get_multiplier (constraint);
constant = gtk_constraint_get_constant (constraint);
strength = get_strength_nick (gtk_constraint_get_strength (constraint));
g_string_append_printf (str, "%*s<constraint target=\"%s\" target-attribute=\"%s\"\n", indent, "", target, target_attr);
g_string_append_printf (str, "%*s relation=\"%s\"\n", indent, "", relation);
if (strcmp (source_attr, "none") != 0)
{
g_string_append_printf (str, "%*s source=\"%s\" source-attribute=\"%s\"\n", indent, "", source, source_attr);
g_string_append_printf (str, "%*s multiplier=\"%g\"\n", indent, "", multiplier);
}
g_string_append_printf (str, "%*s constant=\"%g\"\n", indent, "", constant);
g_string_append_printf (str, "%*s strength=\"%s\" />\n", indent, "", strength);
}
static void
create_constraint (GtkButton *button,
ConstraintEditor *editor)
{
const char *id;
gpointer target;
GtkConstraintAttribute target_attr;
gpointer source;
GtkConstraintAttribute source_attr;
GtkConstraintRelation relation;
double multiplier;
double constant;
int strength;
GtkConstraint *constraint;
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target));
target = get_target (editor->model, id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target_attr));
target_attr = get_target_attr (id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
source = get_target (editor->model, id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
source_attr = get_target_attr (id);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->relation));
relation = get_relation (id);
multiplier = g_ascii_strtod (gtk_editable_get_text (GTK_EDITABLE (editor->multiplier)), NULL);
constant = g_ascii_strtod (gtk_editable_get_text (GTK_EDITABLE (editor->constant)), NULL);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
strength = get_strength (id);
constraint = gtk_constraint_new (target, target_attr,
relation,
source, source_attr,
multiplier,
constant,
strength);
g_signal_emit (editor, signals[DONE], 0, constraint);
g_object_unref (constraint);
}
static void
source_attr_changed (ConstraintEditor *editor)
{
const char *id;
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
if (strcmp (id, "none") == 0)
{
gtk_combo_box_set_active (GTK_COMBO_BOX (editor->source), -1);
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "");
gtk_widget_set_sensitive (editor->source, FALSE);
gtk_widget_set_sensitive (editor->multiplier, FALSE);
}
else
{
gtk_widget_set_sensitive (editor->source, TRUE);
gtk_widget_set_sensitive (editor->multiplier, TRUE);
}
}
char *
constraint_editor_constraint_to_string (GtkConstraint *constraint)
{
GString *str;
const char *name;
const char *attr;
const char *relation;
double c, m;
str = g_string_new ("");
name = get_target_name (gtk_constraint_get_target (constraint));
attr = get_attr_nick (gtk_constraint_get_target_attribute (constraint));
relation = get_relation_nick (gtk_constraint_get_relation (constraint));
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s %s ", name, attr, relation);
c = gtk_constraint_get_constant (constraint);
attr = get_attr_nick (gtk_constraint_get_source_attribute (constraint));
if (strcmp (attr, "none") != 0)
{
name = get_target_name (gtk_constraint_get_source (constraint));
m = gtk_constraint_get_multiplier (constraint);
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s", name, attr);
if (m != 1.0)
g_string_append_printf (str, " × %g", m);
if (c > 0.0)
g_string_append_printf (str, " + %g", c);
else if (c < 0.0)
g_string_append_printf (str, " - %g", -c);
}
else
g_string_append_printf (str, "%g", c);
return g_string_free (str, FALSE);
}
static void
update_preview (ConstraintEditor *editor)
{
GString *str;
const char *name;
const char *attr;
char *relation;
const char *multiplier;
const char *constant;
double c, m;
if (!editor->constructed)
return;
str = g_string_new ("");
name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target));
attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target_attr));
relation = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (editor->relation));
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s %s ", name, attr, relation);
g_free (relation);
constant = gtk_editable_get_text (GTK_EDITABLE (editor->constant));
c = g_ascii_strtod (constant, NULL);
attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
if (strcmp (attr, "none") != 0)
{
name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
multiplier = gtk_editable_get_text (GTK_EDITABLE (editor->multiplier));
m = g_ascii_strtod (multiplier, NULL);
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s", name, attr);
if (m != 1.0)
g_string_append_printf (str, " × %g", m);
if (c > 0.0)
g_string_append_printf (str, " + %g", c);
else if (c < 0.0)
g_string_append_printf (str, " - %g", -c);
}
else
g_string_append_printf (str, "%g", c);
gtk_label_set_label (GTK_LABEL (editor->preview), str->str);
g_string_free (str, TRUE);
}
static void
update_button (ConstraintEditor *editor)
{
if (gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target)) != NULL &&
gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source)) != NULL)
gtk_widget_set_sensitive (editor->button, TRUE);
else
gtk_widget_set_sensitive (editor->button, FALSE);
}
static void
constraint_editor_init (ConstraintEditor *editor)
{
gtk_widget_init_template (GTK_WIDGET (editor));
}
static void
constraint_editor_constructed (GObject *object)
{
ConstraintEditor *editor = CONSTRAINT_EDITOR (object);
constraint_target_combo (editor->model, editor->target, FALSE);
constraint_attribute_combo (editor->target_attr, FALSE);
constraint_relation_combo (editor->relation);
constraint_target_combo (editor->model, editor->source, TRUE);
constraint_attribute_combo (editor->source_attr, TRUE);
constraint_strength_combo (editor->strength);
if (editor->constraint)
{
GtkConstraintTarget *target;
GtkConstraintAttribute attr;
GtkConstraintRelation relation;
GtkConstraintStrength strength;
const char *nick;
char *val;
double multiplier;
double constant;
target = gtk_constraint_get_target (editor->constraint);
nick = get_target_name (target);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target), nick);
attr = gtk_constraint_get_target_attribute (editor->constraint);
nick = get_attr_nick (attr);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), nick);
target = gtk_constraint_get_source (editor->constraint);
nick = get_target_name (target);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source), nick);
attr = gtk_constraint_get_source_attribute (editor->constraint);
nick = get_attr_nick (attr);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), nick);
relation = gtk_constraint_get_relation (editor->constraint);
nick = get_relation_nick (relation);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), nick);
multiplier = gtk_constraint_get_multiplier (editor->constraint);
val = g_strdup_printf ("%g", multiplier);
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), val);
g_free (val);
constant = gtk_constraint_get_constant (editor->constraint);
val = g_strdup_printf ("%g", constant);
gtk_editable_set_text (GTK_EDITABLE (editor->constant), val);
g_free (val);
strength = gtk_constraint_get_strength (editor->constraint);
nick = get_strength_nick (strength);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), nick);
gtk_button_set_label (GTK_BUTTON (editor->button), "Apply");
}
else
{
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), "left");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), "left");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), "eq");
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "required");
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "1.0");
gtk_editable_set_text (GTK_EDITABLE (editor->constant), "0.0");
gtk_button_set_label (GTK_BUTTON (editor->button), "Create");
}
editor->constructed = TRUE;
update_preview (editor);
update_button (editor);
}
static void
constraint_editor_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
ConstraintEditor *self = CONSTRAINT_EDITOR (object);
switch (property_id)
{
case PROP_MODEL:
self->model = g_value_dup_object (value);
break;
case PROP_CONSTRAINT:
self->constraint = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
constraint_editor_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
ConstraintEditor *self = CONSTRAINT_EDITOR (object);
switch (property_id)
{
case PROP_MODEL:
g_value_set_object (value, self->model);
break;
case PROP_CONSTRAINT:
g_value_set_object (value, self->constraint);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
constraint_editor_dispose (GObject *object)
{
ConstraintEditor *self = (ConstraintEditor *)object;
g_clear_pointer (&self->grid, gtk_widget_unparent);
g_clear_object (&self->model);
g_clear_object (&self->constraint);
G_OBJECT_CLASS (constraint_editor_parent_class)->dispose (object);
}
static void
constraint_editor_class_init (ConstraintEditorClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->constructed = constraint_editor_constructed;
object_class->dispose = constraint_editor_dispose;
object_class->set_property = constraint_editor_set_property;
object_class->get_property = constraint_editor_get_property;
pspecs[PROP_CONSTRAINT] =
g_param_spec_object ("constraint", "constraint", "constraint",
GTK_TYPE_CONSTRAINT,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
pspecs[PROP_MODEL] =
g_param_spec_object ("model", "model", "model",
G_TYPE_LIST_MODEL,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, LAST_PROP, pspecs);
signals[DONE] =
g_signal_new ("done",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 1, GTK_TYPE_CONSTRAINT);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/constraint-editor/constraint-editor.ui");
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, grid);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target_attr);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, relation);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, source);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, source_attr);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, multiplier);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, constant);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, strength);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, preview);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, button);
gtk_widget_class_bind_template_callback (widget_class, update_preview);
gtk_widget_class_bind_template_callback (widget_class, update_button);
gtk_widget_class_bind_template_callback (widget_class, create_constraint);
gtk_widget_class_bind_template_callback (widget_class, source_attr_changed);
}
ConstraintEditor *
constraint_editor_new (GListModel *model,
GtkConstraint *constraint)
{
return g_object_new (CONSTRAINT_EDITOR_TYPE,
"model", model,
"constraint", constraint,
NULL);
}

View File

@@ -1,12 +0,0 @@
constraintview {
background: black;
color: white;
}
constraintview .child {
background: red;
}
constraintview .guide {
background: blue;
}

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gtk/gtk4/constraint-editor">
<file preprocess="xml-stripblanks">constraint-editor-window.ui</file>
<file preprocess="xml-stripblanks">constraint-editor.ui</file>
<file preprocess="xml-stripblanks">guide-editor.ui</file>
<file>constraint-editor.css</file>
</gresource>
</gresources>

View File

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

View File

@@ -1,163 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="ConstraintEditor" parent="GtkWidget">
<child>
<object class="GtkGrid" id="grid">
<property name="margin">20</property>
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<child>
<object class="GtkLabel">
<property name="label">Target</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="target">
<signal name="changed" handler="update_preview" swapped="yes"/>
<signal name="changed" handler="update_button" swapped="yes"/>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="target_attr">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Relation</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="relation">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Source</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="source">
<signal name="changed" handler="update_preview" swapped="yes"/>
<signal name="changed" handler="update_button" swapped="yes"/>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="source_attr">
<signal name="changed" handler="update_preview" swapped="yes"/>
<signal name="changed" handler="source_attr_changed" swapped="yes"/>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Multiplier</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="multiplier">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Constant</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">5</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="constant">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">5</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Strength</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">6</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="strength">
<layout>
<property name="left-attach">1</property>
<property name="top-attach">6</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="preview">
<property name="xalign">0</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">7</property>
<property name="column-span">2</property>
</layout>
<attributes>
<attribute name="scale" value="1.44"/>
</attributes>
</object>
</child>
<child>
<object class="GtkButton" id="button">
<property name="label">Create</property>
<signal name="clicked" handler="create_constraint"/>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">8</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -1,93 +0,0 @@
/*
* Copyright © 2019 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen
*/
#include "constraint-view-child.h"
struct _ConstraintViewChild
{
GObject parent_instance;
char *name;
};
enum {
PROP_NAME = 1,
LAST_PROP
};
static GParamSpec props[LAST_PROP];
G_DEFINE_TYPE (ConstraintViewChild, constraint_view_child, G_TYPE_OBJECT)
static void
constraint_view_child_init (ConstraintViewChild *child)
{
}
static void
constraint_view_child_finalize (GObject *object)
{
ConstraintViewChild *child = CONSTRAINT_VIEW_CHILD (object);
g_free (child->name);
G_OBJECT_CLASS (constraint_view_child_parent_class)->finalize (object);
}
static void
constraint_view_child_set_property (GObject *object,
static void
constraint_view_child_class_init (ConstraintViewChildClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = constraint_view_child_finalize;
object_class->get_property = constraint_view_child_get_property;
object_class->set_property = constraint_view_child_set_property;
props[PROP_NAME] =
g_param_spec_string ("name", "name", "name",
NULL,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, LAST_PROP, props);
}
#define CONSTRAINT_VIEW_CHILD_TYPE (constraint_view_get_type ())
G_DECLARE_TYPE (ConstraintViewChild, constraint_view_child, CONSTRAINT, VIEW_CHILD, GObject)
#define CONSTRAINT_VIEW_WIDGET_TYPE (constraint_view_widget_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewWidget, constraint_view_widget, CONSTRAINT, VIEW_WIDGET, ConstraintViewChild)
ConstraintViewWidget * constraint_view_widget_new (void);
#define CONSTRAINT_VIEW_GUIDE_TYPE (constraint_view_guide_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewGuide, constraint_view_guide, CONSTRAINT, VIEW_GUIDE, ConstraintViewChild)
ConstraintViewGuide * constraint_view_guide_new (void);
#define CONSTRAINT_VIEW_CONSTRAINT_TYPE (constraint_view_constraint_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewConstraint, constraint_view_constraint, CONSTRAINT, VIEW_CONSTRAINT, ConstraintViewChild)
ConstraintViewGuide * constraint_view_constraint_new (void);

View File

@@ -1,44 +0,0 @@
/*
* Copyright © 2019 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen
*/
#pragma once
#include <gtk/gtk.h>
#define CONSTRAINT_VIEW_CHILD_TYPE (constraint_view_get_type ())
G_DECLARE_TYPE (ConstraintViewChild, constraint_view_child, CONSTRAINT, VIEW_CHILD, GObject)
#define CONSTRAINT_VIEW_WIDGET_TYPE (constraint_view_widget_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewWidget, constraint_view_widget, CONSTRAINT, VIEW_WIDGET, ConstraintViewChild)
ConstraintViewWidget * constraint_view_widget_new (void);
#define CONSTRAINT_VIEW_GUIDE_TYPE (constraint_view_guide_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewGuide, constraint_view_guide, CONSTRAINT, VIEW_GUIDE, ConstraintViewChild)
ConstraintViewGuide * constraint_view_guide_new (void);
#define CONSTRAINT_VIEW_CONSTRAINT_TYPE (constraint_view_constraint_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewConstraint, constraint_view_constraint, CONSTRAINT, VIEW_CONSTRAINT, ConstraintViewChild)
ConstraintViewGuide * constraint_view_constraint_new (void);

View File

@@ -1,348 +0,0 @@
/* Copyright (C) 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtk/gtk.h>
#include "constraint-view.h"
struct _ConstraintView
{
GtkWidget parent;
GListModel *model;
GtkWidget *drag_widget;
};
G_DEFINE_TYPE (ConstraintView, constraint_view, GTK_TYPE_WIDGET);
static void
constraint_view_dispose (GObject *object)
{
ConstraintView *view = CONSTRAINT_VIEW (object);
GtkWidget *child;
while ((child = gtk_widget_get_first_child (GTK_WIDGET (view))) != NULL)
gtk_widget_unparent (child);
g_clear_object (&view->model);
G_OBJECT_CLASS (constraint_view_parent_class)->dispose (object);
}
static void
constraint_view_class_init (ConstraintViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = constraint_view_dispose;
gtk_widget_class_set_css_name (widget_class, "constraintview");
}
static void
update_weak_position (ConstraintView *self,
GtkWidget *child,
double x,
double y)
{
GtkLayoutManager *manager;
GtkConstraint *constraint;
manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
constraint = (GtkConstraint *)g_object_get_data (G_OBJECT (child), "x-constraint");
if (constraint)
{
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "x-constraint", NULL);
}
if (x != -100)
{
constraint = gtk_constraint_new_constant (child,
GTK_CONSTRAINT_ATTRIBUTE_CENTER_X,
GTK_CONSTRAINT_RELATION_EQ,
x,
GTK_CONSTRAINT_STRENGTH_WEAK);
g_object_set_data (G_OBJECT (constraint), "internal", "yes");
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "x-constraint", constraint);
}
constraint = (GtkConstraint *)g_object_get_data (G_OBJECT (child), "y-constraint");
if (constraint)
{
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "y-constraint", NULL);
}
if (y != -100)
{
constraint = gtk_constraint_new_constant (child,
GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y,
GTK_CONSTRAINT_RELATION_EQ,
y,
GTK_CONSTRAINT_STRENGTH_WEAK);
g_object_set_data (G_OBJECT (constraint), "internal", "yes");
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "y-constraint", constraint);
}
}
static void
drag_begin (GtkGestureDrag *drag,
double start_x,
double start_y,
ConstraintView *self)
{
GtkWidget *widget;
widget = gtk_widget_pick (GTK_WIDGET (self), start_x, start_y, GTK_PICK_DEFAULT);
if (GTK_IS_LABEL (widget))
{
widget = gtk_widget_get_ancestor (widget, GTK_TYPE_FRAME);
if (widget &&
gtk_widget_get_parent (widget) == (GtkWidget *)self)
{
self->drag_widget = widget;
}
}
}
static void
drag_update (GtkGestureDrag *drag,
double offset_x,
double offset_y,
ConstraintView *self)
{
double x, y;
if (!self->drag_widget)
return;
gtk_gesture_drag_get_start_point (drag, &x, &y);
update_weak_position (self, self->drag_widget, x + offset_x, y + offset_y);
}
static void
drag_end (GtkGestureDrag *drag,
double offset_x,
double offset_y,
ConstraintView *self)
{
self->drag_widget = NULL;
}
static gboolean
omit_internal (gpointer item, gpointer user_data)
{
if (g_object_get_data (G_OBJECT (item), "internal"))
return FALSE;
return TRUE;
}
static void
constraint_view_init (ConstraintView *self)
{
GtkLayoutManager *manager;
GtkEventController *controller;
GListStore *list;
GListModel *all_children;
GListModel *all_constraints;
GListModel *guides;
GListModel *children;
GListModel *constraints;
GtkFilter *filter;
manager = gtk_constraint_layout_new ();
gtk_widget_set_layout_manager (GTK_WIDGET (self), manager);
all_children = gtk_widget_observe_children (GTK_WIDGET (self));
all_constraints = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (manager));
guides = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (manager));
filter = gtk_custom_filter_new (omit_internal, NULL, NULL);
constraints = (GListModel *)gtk_filter_list_model_new (all_constraints, filter);
g_object_unref (filter);
filter = gtk_custom_filter_new (omit_internal, NULL, NULL);
children = (GListModel *)gtk_filter_list_model_new (all_children, filter);
g_object_unref (filter);
list = g_list_store_new (G_TYPE_LIST_MODEL);
g_list_store_append (list, children);
g_list_store_append (list, guides);
g_list_store_append (list, constraints);
self->model = G_LIST_MODEL (gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list)));
g_object_unref (children);
g_object_unref (guides);
g_object_unref (constraints);
g_object_unref (all_children);
g_object_unref (all_constraints);
g_object_unref (list);
controller = (GtkEventController *)gtk_gesture_drag_new ();
g_signal_connect (controller, "drag-begin", G_CALLBACK (drag_begin), self);
g_signal_connect (controller, "drag-update", G_CALLBACK (drag_update), self);
g_signal_connect (controller, "drag-end", G_CALLBACK (drag_end), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
}
ConstraintView *
constraint_view_new (void)
{
return g_object_new (CONSTRAINT_VIEW_TYPE, NULL);
}
void
constraint_view_add_child (ConstraintView *view,
const char *name)
{
GtkWidget *frame;
GtkWidget *label;
label = gtk_label_new (name);
frame = gtk_frame_new (NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (frame), "child");
gtk_widget_set_name (frame, name);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_set_parent (frame, GTK_WIDGET (view));
update_weak_position (view, frame, 100, 100);
}
void
constraint_view_remove_child (ConstraintView *view,
GtkWidget *child)
{
update_weak_position (view, child, -100, -100);
gtk_widget_unparent (child);
}
void
constraint_view_add_guide (ConstraintView *view,
GtkConstraintGuide *guide)
{
GtkConstraintLayout *layout;
GtkWidget *frame;
GtkWidget *label;
const char *name;
GtkConstraint *constraint;
struct {
const char *name;
GtkConstraintAttribute attr;
} names[] = {
{ "left-constraint", GTK_CONSTRAINT_ATTRIBUTE_LEFT },
{ "top-constraint", GTK_CONSTRAINT_ATTRIBUTE_TOP },
{ "width-constraint", GTK_CONSTRAINT_ATTRIBUTE_WIDTH },
{ "height-constraint", GTK_CONSTRAINT_ATTRIBUTE_HEIGHT },
};
int i;
name = gtk_constraint_guide_get_name (guide);
label = gtk_label_new (name);
g_object_bind_property (guide, "name",
label, "label",
G_BINDING_DEFAULT);
frame = gtk_frame_new (NULL);
gtk_style_context_add_class (gtk_widget_get_style_context (frame), "guide");
g_object_set_data (G_OBJECT (frame), "internal", "yes");
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_insert_after (frame, GTK_WIDGET (view), NULL);
g_object_set_data (G_OBJECT (guide), "frame", frame);
layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (view)));
gtk_constraint_layout_add_guide (layout, g_object_ref (guide));
for (i = 0; i < G_N_ELEMENTS (names); i++)
{
constraint = gtk_constraint_new (frame,
names[i].attr,
GTK_CONSTRAINT_RELATION_EQ,
guide,
names[i].attr,
1.0, 0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED);
g_object_set_data (G_OBJECT (constraint), "internal", "yes");
gtk_constraint_layout_add_constraint (layout, constraint);
g_object_set_data (G_OBJECT (guide), names[i].name, constraint);
}
update_weak_position (view, frame, 150, 150);
}
void
constraint_view_remove_guide (ConstraintView *view,
GtkConstraintGuide *guide)
{
GtkConstraintLayout *layout;
GtkWidget *frame;
GtkConstraint *constraint;
const char *names[] = {
"left-constraint",
"top-constraint",
"width-constraint",
"height-constraint"
};
int i;
layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (view)));
for (i = 0; i < G_N_ELEMENTS (names); i++)
{
constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), names[i]);
gtk_constraint_layout_remove_constraint (layout, constraint);
}
frame = (GtkWidget *)g_object_get_data (G_OBJECT (guide), "frame");
update_weak_position (view, frame, -100, -100);
gtk_widget_unparent (frame);
gtk_constraint_layout_remove_guide (layout, guide);
}
void
constraint_view_add_constraint (ConstraintView *view,
GtkConstraint *constraint)
{
GtkLayoutManager *manager;
manager = gtk_widget_get_layout_manager (GTK_WIDGET (view));
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
g_object_ref (constraint));
}
void
constraint_view_remove_constraint (ConstraintView *view,
GtkConstraint *constraint)
{
GtkLayoutManager *manager;
manager = gtk_widget_get_layout_manager (GTK_WIDGET (view));
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
}
GListModel *
constraint_view_get_model (ConstraintView *view)
{
return view->model;
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright © 2019 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen
*/
#pragma once
#include <gtk/gtk.h>
#define CONSTRAINT_VIEW_TYPE (constraint_view_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintView, constraint_view, CONSTRAINT, VIEW, GtkWidget)
ConstraintView * constraint_view_new (void);
void constraint_view_add_child (ConstraintView *view,
const char *name);
void constraint_view_remove_child (ConstraintView *view,
GtkWidget *child);
void constraint_view_add_guide (ConstraintView *view,
GtkConstraintGuide *guide);
void constraint_view_remove_guide (ConstraintView *view,
GtkConstraintGuide *guide);
void constraint_view_guide_changed (ConstraintView *view,
GtkConstraintGuide *guide);
void constraint_view_add_constraint (ConstraintView *view,
GtkConstraint *constraint);
void constraint_view_remove_constraint (ConstraintView *view,
GtkConstraint *constraint);
GListModel * constraint_view_get_model (ConstraintView *view);

View File

@@ -1,355 +0,0 @@
/*
* Copyright © 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen
*/
#include "config.h"
#include "guide-editor.h"
struct _GuideEditor
{
GtkWidget parent_instance;
GtkWidget *grid;
GtkWidget *name;
GtkWidget *min_width;
GtkWidget *min_height;
GtkWidget *nat_width;
GtkWidget *nat_height;
GtkWidget *max_width;
GtkWidget *max_height;
GtkWidget *strength;
GtkWidget *button;
GtkConstraintGuide *guide;
gboolean constructed;
};
enum {
PROP_GUIDE = 1,
LAST_PROP
};
static GParamSpec *pspecs[LAST_PROP];
enum {
DONE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE(GuideEditor, guide_editor, GTK_TYPE_WIDGET);
static void
guide_strength_combo (GtkWidget *combo)
{
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "weak", "Weak");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "medium", "Medium");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "strong", "Strong");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "required", "Required");
}
static GtkConstraintStrength
get_strength (const char *id)
{
GtkConstraintStrength strength;
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value_by_nick (class, id);
strength = value->value;
g_type_class_unref (class);
return strength;
}
const char *
get_strength_nick (GtkConstraintStrength strength)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value (class, strength);
const char *nick = value->value_nick;
g_type_class_unref (class);
return nick;
}
void
guide_editor_serialize_guide (GString *str,
int indent,
GtkConstraintGuide *guide)
{
int min_width, min_height;
int nat_width, nat_height;
int max_width, max_height;
const char *name;
const char *strength;
gtk_constraint_guide_get_min_size (guide, &min_width, &min_height);
gtk_constraint_guide_get_nat_size (guide, &nat_width, &nat_height);
gtk_constraint_guide_get_max_size (guide, &max_width, &max_height);
name = gtk_constraint_guide_get_name (guide);
strength = get_strength_nick (gtk_constraint_guide_get_strength (guide));
g_string_append_printf (str, "%*s<guide min-width=\"%d\" min-height=\"%d\"\n", indent, "", min_width, min_height);
g_string_append_printf (str, "%*s nat-width=\"%d\" nat-height=\"%d\"\n", indent, "", nat_width, nat_height);
g_string_append_printf (str, "%*s max-width=\"%d\" max-height=\"%d\"\n", indent, "", max_width, max_height);
g_string_append_printf (str, "%*s name=\"%s\" strength=\"%s\" />\n", indent, "", name, strength);
}
static void
create_guide (GtkButton *button,
GuideEditor *editor)
{
const char *id;
int strength;
const char *name;
int w, h;
GtkConstraintGuide *guide;
if (editor->guide)
guide = g_object_ref (editor->guide);
else
guide = gtk_constraint_guide_new ();
name = gtk_editable_get_text (GTK_EDITABLE (editor->name));
gtk_constraint_guide_set_name (guide, name);
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_height));
gtk_constraint_guide_set_min_size (guide, w, h);
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_height));
gtk_constraint_guide_set_nat_size (guide, w, h);
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_height));
gtk_constraint_guide_set_max_size (guide, w, h);
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
strength = get_strength (id);
gtk_constraint_guide_set_strength (guide, strength);
g_signal_emit (editor, signals[DONE], 0, guide);
g_object_unref (guide);
}
static void
guide_editor_init (GuideEditor *editor)
{
gtk_widget_init_template (GTK_WIDGET (editor));
}
static int guide_counter;
static int
min_input (GtkSpinButton *spin_button,
double *new_val)
{
if (strcmp (gtk_editable_get_text (GTK_EDITABLE (spin_button)), "") == 0)
{
*new_val = 0.0;
return TRUE;
}
return FALSE;
}
static int
max_input (GtkSpinButton *spin_button,
double *new_val)
{
if (strcmp (gtk_editable_get_text (GTK_EDITABLE (spin_button)), "") == 0)
{
*new_val = G_MAXINT;
return TRUE;
}
return FALSE;
}
static void
guide_editor_constructed (GObject *object)
{
GuideEditor *editor = GUIDE_EDITOR (object);
guide_strength_combo (editor->strength);
g_signal_connect (editor->min_width, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->min_height, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->max_width, "input", G_CALLBACK (max_input), NULL);
g_signal_connect (editor->max_height, "input", G_CALLBACK (max_input), NULL);
if (editor->guide)
{
GtkConstraintStrength strength;
const char *nick;
int w, h;
nick = gtk_constraint_guide_get_name (editor->guide);
if (nick)
gtk_editable_set_text (GTK_EDITABLE (editor->name), nick);
gtk_constraint_guide_get_min_size (editor->guide, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), h);
gtk_constraint_guide_get_nat_size (editor->guide, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), h);
gtk_constraint_guide_get_max_size (editor->guide, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), h);
strength = gtk_constraint_guide_get_strength (editor->guide);
nick = get_strength_nick (strength);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), nick);
gtk_button_set_label (GTK_BUTTON (editor->button), "Apply");
}
else
{
char *name;
guide_counter++;
name = g_strdup_printf ("Guide %d", guide_counter);
gtk_editable_set_text (GTK_EDITABLE (editor->name), name);
g_free (name);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), G_MAXINT);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), G_MAXINT);
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "medium");
gtk_button_set_label (GTK_BUTTON (editor->button), "Create");
}
editor->constructed = TRUE;
}
static void
guide_editor_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GuideEditor *self = GUIDE_EDITOR (object);
switch (property_id)
{
case PROP_GUIDE:
self->guide = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
guide_editor_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GuideEditor *self = GUIDE_EDITOR (object);
switch (property_id)
{
case PROP_GUIDE:
g_value_set_object (value, self->guide);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
guide_editor_dispose (GObject *object)
{
GuideEditor *self = (GuideEditor *)object;
g_clear_pointer (&self->grid, gtk_widget_unparent);
g_clear_object (&self->guide);
G_OBJECT_CLASS (guide_editor_parent_class)->dispose (object);
}
static void
guide_editor_class_init (GuideEditorClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->constructed = guide_editor_constructed;
object_class->dispose = guide_editor_dispose;
object_class->set_property = guide_editor_set_property;
object_class->get_property = guide_editor_get_property;
pspecs[PROP_GUIDE] =
g_param_spec_object ("guide", "guide", "guide",
GTK_TYPE_CONSTRAINT_GUIDE,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, LAST_PROP, pspecs);
signals[DONE] =
g_signal_new ("done",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 1, GTK_TYPE_CONSTRAINT_GUIDE);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/constraint-editor/guide-editor.ui");
gtk_widget_class_bind_template_child (widget_class, GuideEditor, grid);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, name);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, min_width);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, min_height);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, nat_width);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, nat_height);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, max_width);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, max_height);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, strength);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, button);
gtk_widget_class_bind_template_callback (widget_class, create_guide);
}
GuideEditor *
guide_editor_new (GtkConstraintGuide *guide)
{
return g_object_new (GUIDE_EDITOR_TYPE,
"guide", guide,
NULL);
}

View File

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

View File

@@ -1,188 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkAdjustment" id="min_width_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="min_height_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="nat_width_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="nat_height_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="max_width_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="max_height_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<template class="GuideEditor" parent="GtkWidget">
<child>
<object class="GtkGrid" id="grid">
<property name="margin">20</property>
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<child>
<object class="GtkLabel">
<property name="label">Name</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="name">
<property name="max-width-chars">20</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Min Size</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="min_width">
<property name="adjustment">min_width_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="min_height">
<property name="adjustment">min_height_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Nat Size</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="nat_width">
<property name="adjustment">nat_width_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="nat_height">
<property name="adjustment">nat_height_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Max Size</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="max_width">
<property name="adjustment">max_width_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="max_height">
<property name="adjustment">max_height_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Strength</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="strength">
<layout>
<property name="left-attach">1</property>
<property name="top-attach">4</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton" id="button">
<property name="label">Create</property>
<signal name="clicked" handler="create_guide"/>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">5</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -1,28 +0,0 @@
/*
* Copyright © 2019 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Matthias Clasen <mclasen@redhat.com>
*/
#include "config.h"
#include <constraint-editor-application.h>
int
main (int argc, char *argv[])
{
return g_application_run (G_APPLICATION (constraint_editor_application_new ()), argc, argv);
}

View File

@@ -1,20 +0,0 @@
constraint_editor_sources = [
'main.c',
'constraint-editor-application.c',
'constraint-editor-window.c',
'constraint-view.c',
'constraint-editor.c',
'guide-editor.c',
]
constraint_editor_resources = gnome.compile_resources('constraint_editor_resources',
'constraint-editor.gresource.xml',
source_dir: '.')
executable('gtk4-constraint-editor',
constraint_editor_sources, constraint_editor_resources,
dependencies: libgtk_dep,
include_directories: confinc,
gui_app: true,
link_args: extra_demo_ldflags,
install: false)

View File

@@ -1,247 +0,0 @@
/*
* Copyright © 2018 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "award.h"
struct _GtkAward
{
GObject parent;
char *explanation;
char *name;
char *title;
GDateTime *granted; /* or NULL if not granted */
};
enum {
PROP_0,
PROP_EXPLANATION,
PROP_NAME,
PROP_TITLE,
PROP_GRANTED,
N_PROPS,
};
static GParamSpec *properties[N_PROPS] = { NULL, };
G_DEFINE_TYPE (GtkAward, gtk_award, G_TYPE_OBJECT)
static void
gtk_award_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkAward *self = GTK_AWARD (object);
switch (prop_id)
{
case PROP_EXPLANATION:
self->explanation = g_value_dup_string (value);
break;
case PROP_NAME:
self->name = g_value_dup_string (value);
break;
case PROP_TITLE:
self->title = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_award_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkAward *self = GTK_AWARD (object);
switch (prop_id)
{
case PROP_EXPLANATION:
g_value_set_string (value, self->explanation);
break;
case PROP_NAME:
g_value_set_string (value, self->name);
break;
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
case PROP_GRANTED:
g_value_set_boxed (value, self->granted);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_award_dispose (GObject *object)
{
GtkAward *self = GTK_AWARD (object);
g_clear_pointer (&self->name, g_free);
g_clear_pointer (&self->title, g_free);
g_clear_pointer (&self->granted, g_date_time_unref);
G_OBJECT_CLASS (gtk_award_parent_class)->dispose (object);
}
static void
gtk_award_class_init (GtkAwardClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
gobject_class->set_property = gtk_award_set_property;
gobject_class->get_property = gtk_award_get_property;
gobject_class->dispose = gtk_award_dispose;
properties[PROP_EXPLANATION] =
g_param_spec_string ("explanation",
"Explanation",
"How to get the title",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_NAME] =
g_param_spec_string ("name",
"Name",
"internal name of the award",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_TITLE] =
g_param_spec_string ("title",
"Title",
"user-visible title",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
properties[PROP_GRANTED] =
g_param_spec_boxed ("granted",
"Granted",
"Timestamp the award was granted or NULL if not granted yet",
G_TYPE_DATE_TIME,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gtk_award_init (GtkAward *self)
{
}
GListModel *
gtk_award_get_list (void)
{
static GListModel *list = NULL;
if (list == NULL)
{
GtkBuilder *builder;
g_type_ensure (GTK_TYPE_AWARD);
builder = gtk_builder_new_from_resource ("/awards.ui");
list = G_LIST_MODEL (gtk_builder_get_object (builder, "list"));
g_object_ref (list);
g_object_unref (builder);
}
return g_object_ref (list);
}
const char *
gtk_award_get_name (GtkAward *award)
{
return award->name;
}
const char *
gtk_award_get_title (GtkAward *award)
{
return award->title;
}
GDateTime *
gtk_award_get_granted (GtkAward *award)
{
return award->granted;
}
GtkAward *
award_find (const char *name)
{
GListModel *list;
GtkAward *self;
guint i;
list = gtk_award_get_list ();
g_object_unref (list);
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
self = g_list_model_get_item (list, i);
g_object_unref (self);
if (g_ascii_strcasecmp (name, self->name) == 0)
return self;
}
return NULL;
}
void
award (const char *name)
{
GtkAward *self;
GNotification *notification;
self = award_find (name);
if (self == NULL)
{
g_warning ("Did not find award \"%s\"", name);
return;
}
if (self->granted)
return;
self->granted = g_date_time_new_now_utc ();
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_GRANTED]);
notification = g_notification_new ("You won an award!");
g_notification_set_body (notification, self->title);
g_application_send_notification (g_application_get_default (), NULL, notification);
g_object_unref (notification);
}

View File

@@ -1,18 +0,0 @@
#ifndef __AWARD_H__
#define __AWARD_H__
#include <gtk/gtk.h>
#define GTK_TYPE_AWARD (gtk_award_get_type ())
G_DECLARE_FINAL_TYPE (GtkAward, gtk_award, GTK, AWARD, GObject)
GListModel * gtk_award_get_list (void);
const char * gtk_award_get_name (GtkAward *award);
const char * gtk_award_get_title (GtkAward *award);
GDateTime * gtk_award_get_granted (GtkAward *award);
void award (const char *name);
#endif /* __AWARD_H__ */

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk40">
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="label" bind-source="GtkListItem" bind-property="position"></property>
<property name="margin">6</property>
</object>
</property>
</template>
</interface>

View File

@@ -1,89 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GListStore" id="list">
<property name="item-type">GtkAward</property>
<child>
<object class="GtkAward">
<property name="name">demo-inspector</property>
<!-- Transformers -->
<property name="title" translatable="yes">You got a high-rise double-pump carburetor.</property>
<property name="explanation" translatable="yes">Launch the inspector</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">demo-start</property>
<!-- The Matrix -->
<property name="title" translatable="yes">After this, there is no turning back.</property>
<property name="explanation" translatable="yes">Start gtk-demo</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">listbox-reshare</property>
<!-- Mean Girls -->
<property name="title" translatable="yes">Trying to make fetch happen</property>
<property name="explanation" translatable="yes">Reshare a tweet</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">listbox-100th-row</property>
<!-- Aladdin -->
<property name="title" translatable="yes">The ever impressive, long contained, often imitated, but never duplicated Genie of the lamp.</property>
<property name="explanation" translatable="yes">Select a 100th row in a list</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">password-best</property>
<!-- Spaceballs -->
<property name="title" translatable="yes">I've got the same combination on my luggage!</property>
<property name="explanation" translatable="yes">Use "12345" as the password</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">password-correct</property>
<!-- Stanley Parable -->
<property name="title" translatable="yes">Night Shark 1-1-5</property>
<property name="explanation" translatable="yes">Correctly enter a password</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">puzzle-give-up</property>
<!-- Pretty Woman -->
<property name="title" translatable="yes">Big Mistake. Big. Huge!</property>
<property name="explanation" translatable="yes">Close the puzzle without finishing it</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">puzzle-solve</property>
<!-- The Incredibles -->
<property name="title" translatable="yes">That was totally wicked!</property>
<property name="explanation" translatable="yes">Solve a puzzle</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">puzzle-solve-animated</property>
<!-- The Phantom Menace -->
<property name="title" translatable="yes">A surprise to be sure but a welcome one.</property>
<property name="explanation" translatable="yes">Solve an animated puzzle</property>
</object>
</child>
<child>
<object class="GtkAward">
<property name="name">puzzle-solve-large</property>
<!-- Portal -->
<property name="title" translatable="yes">Science isn't about WHY. It's about WHY NOT?!</property>
<property name="explanation" translatable="yes">Solve a puzzle with at least 20 pieces</property>
</object>
</child>
</object>
</interface>

View File

@@ -1,49 +0,0 @@
/* Awards
*
* This demo demonstrates how to use lists to show the awards you have collected
* while exploring this demo.
*
*/
#include <gtk/gtk.h>
/* Include the header for accessing the awards */
#include "award.h"
static GtkWidget *window = NULL;
GtkWidget *
do_awardview (GtkWidget *do_widget)
{
if (!window)
{
GtkWidget *sw, *listview;
GListModel *list;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Awards");
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), sw);
listview = gtk_list_view_new_with_factory (
gtk_builder_list_item_factory_new_from_resource (NULL, "/awardview/awardlistitem.ui"));
list = gtk_award_get_list ();
gtk_list_view_set_model (GTK_LIST_VIEW (listview), list);
g_object_unref (list);
gtk_list_view_set_show_separators (GTK_LIST_VIEW (listview), TRUE);
gtk_container_add (GTK_CONTAINER (sw), listview);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -59,6 +59,7 @@ do_builder (GtkWidget *do_widget)
builder = gtk_builder_new_from_resource ("/builder/demo.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -110,7 +110,7 @@ get_image_paintable (GtkImage *image)
icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, 48, GTK_ICON_LOOKUP_GENERIC_FALLBACK);
if (icon_info == NULL)
return NULL;
return gtk_icon_info_load_icon (icon_info, NULL);
return GDK_PAINTABLE (gtk_icon_info_load_texture (icon_info));
default:
g_warning ("Image storage type %d not handled",
gtk_image_get_storage_type (image));

View File

@@ -44,21 +44,20 @@ simple_grid_class_init (SimpleGridClass *klass)
/* Layout:
*
* +-------------------------------------+
* | +-----------++-------++-----------+ |
* | | Child 1 || Space || Child 2 | |
* | +-----------++-------++-----------+ |
* | +---------------------------------+ |
* | | Child 3 | |
* | +---------------------------------+ |
* +-------------------------------------+
* +-----------------------------+
* | +-----------+ +-----------+ |
* | | Child 1 | | Child 2 | |
* | +-----------+ +-----------+ |
* | +-------------------------+ |
* | | Child 3 | |
* | +-------------------------+ |
* +-----------------------------+
*
* Constraints:
*
* super.start = child1.start - 8
* child1.width = child2.width
* child1.end = space.start
* space.end = child2.start
* child1.end = child2.start - 12
* child2.end = super.end - 8
* super.start = child3.start - 8
* child3.end = super.end - 8
@@ -70,12 +69,6 @@ simple_grid_class_init (SimpleGridClass *klass)
* child3.height = child2.height
* child3.bottom = super.bottom - 8
*
* To add some flexibility, we make the space
* stretchable:
*
* space.width >= 10
* space.width = 100
* space.width <= 200
*/
static void
build_constraints (SimpleGrid *self,
@@ -83,12 +76,12 @@ build_constraints (SimpleGrid *self,
{
GtkConstraintGuide *guide;
guide = gtk_constraint_guide_new ();
gtk_constraint_guide_set_name (guide, "space");
gtk_constraint_guide_set_min_size (guide, 10, 10);
gtk_constraint_guide_set_nat_size (guide, 100, 10);
gtk_constraint_guide_set_max_size (guide, 200, 20);
gtk_constraint_guide_set_strength (guide, GTK_CONSTRAINT_STRENGTH_STRONG);
guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE,
"min-width", 10,
"min-height", 10,
"nat-width", 100,
"nat-height", 10,
NULL);
gtk_constraint_layout_add_guide (manager, guide);
gtk_constraint_layout_add_constraint (manager,
@@ -101,40 +94,40 @@ build_constraints (SimpleGrid *self,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
self->button1,
GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button1,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
GTK_CONSTRAINT_RELATION_EQ,
self->button2,
GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button1,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
guide,
GTK_CONSTRAINT_TARGET (guide),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (guide,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (guide),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
self->button2,
GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button2,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
NULL,
@@ -146,13 +139,13 @@ build_constraints (SimpleGrid *self,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
self->button3,
GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button3,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
NULL,
@@ -164,7 +157,7 @@ build_constraints (SimpleGrid *self,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
self->button1,
GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
1.0,
-8.0,
@@ -173,49 +166,49 @@ build_constraints (SimpleGrid *self,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
self->button2,
GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button1,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
GTK_CONSTRAINT_RELATION_EQ,
self->button3,
GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
1.0,
-12.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button2,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
GTK_CONSTRAINT_RELATION_EQ,
self->button3,
GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
1.0,
-12.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button3,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
GTK_CONSTRAINT_RELATION_EQ,
self->button1,
GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button3,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
GTK_CONSTRAINT_RELATION_EQ,
self->button2,
GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (self->button3,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
GTK_CONSTRAINT_RELATION_EQ,
NULL,

View File

@@ -1,165 +0,0 @@
/* Constraints/VFL
*
* GtkConstraintLayout allows defining constraints using a
* compact syntax called Visual Format Language, or VFL.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE (VflGrid, vfl_grid, VFL, GRID, GtkWidget)
struct _VflGrid
{
GtkWidget parent_instance;
GtkWidget *button1, *button2;
GtkWidget *button3;
};
G_DEFINE_TYPE (VflGrid, vfl_grid, GTK_TYPE_WIDGET)
static void
vfl_grid_destroy (GtkWidget *widget)
{
VflGrid *self = VFL_GRID (widget);
g_clear_pointer (&self->button1, gtk_widget_destroy);
g_clear_pointer (&self->button2, gtk_widget_destroy);
g_clear_pointer (&self->button3, gtk_widget_destroy);
GTK_WIDGET_CLASS (vfl_grid_parent_class)->destroy (widget);
}
static void
vfl_grid_class_init (VflGridClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
widget_class->destroy = vfl_grid_destroy;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
}
/* Layout:
*
* +-----------------------------+
* | +-----------+ +-----------+ |
* | | Child 1 | | Child 2 | |
* | +-----------+ +-----------+ |
* | +-------------------------+ |
* | | Child 3 | |
* | +-------------------------+ |
* +-----------------------------+
*
* Constraints:
*
* super.start = child1.start - 8
* child1.width = child2.width
* child1.end = child2.start - 12
* child2.end = super.end - 8
* super.start = child3.start - 8
* child3.end = super.end - 8
* super.top = child1.top - 8
* super.top = child2.top - 8
* child1.bottom = child3.top - 12
* child2.bottom = child3.top - 12
* child3.height = child1.height
* child3.height = child2.height
* child3.bottom = super.bottom - 8
*
* Visual format:
*
* H:|-8-[view1(==view2)-12-[view2]-8-|
* H:|-8-[view3]-8-|
* V:|-8-[view1]-12-[view3(==view1)]-8-|
* V:|-8-[view2]-12-[view3(==view2)]-8-|
*/
static void
build_constraints (VflGrid *self,
GtkConstraintLayout *manager)
{
const char * const vfl[] = {
"H:|-[button1(==button2)]-12-[button2]-|",
"H:|-[button3]-|",
"V:|-[button1]-12-[button3(==button1)]-|",
"V:|-[button2]-12-[button3(==button2)]-|",
};
GError *error = NULL;
gtk_constraint_layout_add_constraints_from_description (manager, vfl, G_N_ELEMENTS (vfl),
8, 8,
&error,
"button1", self->button1,
"button2", self->button2,
"button3", self->button3,
NULL);
if (error != NULL)
{
g_printerr ("VFL parsing error:\n%s", error->message);
g_error_free (error);
}
}
static void
vfl_grid_init (VflGrid *self)
{
GtkWidget *widget = GTK_WIDGET (self);
self->button1 = gtk_button_new_with_label ("Child 1");
gtk_widget_set_parent (self->button1, widget);
gtk_widget_set_name (self->button1, "button1");
self->button2 = gtk_button_new_with_label ("Child 2");
gtk_widget_set_parent (self->button2, widget);
gtk_widget_set_name (self->button2, "button2");
self->button3 = gtk_button_new_with_label ("Child 3");
gtk_widget_set_parent (self->button3, widget);
gtk_widget_set_name (self->button3, "button3");
GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
build_constraints (self, GTK_CONSTRAINT_LAYOUT (manager));
}
GtkWidget *
do_constraints3 (GtkWidget *do_widget)
{
static GtkWidget *window;
if (!window)
{
GtkWidget *header, *box, *grid, *button;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
header = gtk_header_bar_new ();
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Constraints");
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_add (GTK_CONTAINER (window), box);
grid = g_object_new (vfl_grid_get_type (), NULL);
gtk_widget_set_hexpand (grid, TRUE);
gtk_widget_set_vexpand (grid, TRUE);
gtk_container_add (GTK_CONTAINER (box), grid);
button = gtk_button_new_with_label ("Close");
gtk_container_add (GTK_CONTAINER (box), button);
gtk_widget_set_hexpand (grid, TRUE);
g_signal_connect_swapped (button, "clicked",
G_CALLBACK (gtk_widget_destroy), window);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -24,6 +24,7 @@ do_cursors (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/cursors/cursors.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -1,11 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/">
<file>awards.ui</file>
</gresource>
<gresource prefix="/ui">
<file preprocess="xml-stripblanks">main.ui</file>
<file preprocess="xml-stripblanks">main-listitem.ui</file>
<file preprocess="xml-stripblanks">appmenu.ui</file>
</gresource>
<gresource prefix="/application_demo">
@@ -13,9 +9,6 @@
<file>application.ui</file>
<file>menus.ui</file>
</gresource>
<gresource prefix="/awardview">
<file>awardlistitem.ui</file>
</gresource>
<gresource prefix="/builder">
<file>demo.ui</file>
</gresource>
@@ -111,26 +104,10 @@
<file>gtkfishbowl.c</file>
<file>gtkfishbowl.h</file>
</gresource>
<gresource prefix="/iconscroll">
<file>iconscroll.ui</file>
</gresource>
<gresource prefix="/iconview">
<file>gnome-fs-directory.png</file>
<file>gnome-fs-regular.png</file>
</gresource>
<gresource prefix="/listview_filebrowser">
<file>listview_filebrowser.ui</file>
</gresource>
<gresource prefix="/listview_minesweeper">
<file>listview_minesweeper.ui</file>
<file>listview_minesweeper_cell.ui</file>
</gresource>
<gresource prefix="/listview_settings">
<file>listview_settings.ui</file>
</gresource>
<gresource prefix="/listview_weather">
<file compressed="true">listview_weather.txt</file>
</gresource>
<gresource prefix="/shortcuts">
<file>shortcuts.ui</file>
<file>shortcuts-builder.ui</file>
@@ -167,7 +144,6 @@
</gresource>
<gresource prefix="/sources">
<file>application_demo.c</file>
<file>awardview.c</file>
<file>assistant.c</file>
<file>builder.c</file>
<file>changedisplay.c</file>
@@ -176,7 +152,6 @@
<file>combobox.c</file>
<file>constraints.c</file>
<file>constraints2.c</file>
<file>constraints3.c</file>
<file>css_accordion.c</file>
<file>css_basics.c</file>
<file>css_blendmodes.c</file>
@@ -188,8 +163,8 @@
<file>drawingarea.c</file>
<file>dnd.c</file>
<file>editable_cells.c</file>
<file>entry_buffer.c</file>
<file>entry_completion.c</file>
<file>entry_undo.c</file>
<file>expander.c</file>
<file>filtermodel.c</file>
<file>fishbowl.c</file>
@@ -198,24 +173,16 @@
<file>foreigndrawing.c</file>
<file>font_features.c</file>
<file>fontplane.c</file>
<file>fontrendering.c</file>
<file>gestures.c</file>
<file>glarea.c</file>
<file>headerbar.c</file>
<file>hypertext.c</file>
<file>iconscroll.c</file>
<file>iconview.c</file>
<file>iconview_edit.c</file>
<file>images.c</file>
<file>infobar.c</file>
<file>links.c</file>
<file>listbox.c</file>
<file>listview_applauncher.c</file>
<file>listview_clocks.c</file>
<file>listview_filebrowser.c</file>
<file>listview_minesweeper.c</file>
<file>listview_settings.c</file>
<file>listview_weather.c</file>
<file>list_store.c</file>
<file>markup.c</file>
<file>menus.c</file>
@@ -247,7 +214,6 @@
<file>spinner.c</file>
<file>tabs.c</file>
<file>tagged_entry.c</file>
<file>textundo.c</file>
<file>textview.c</file>
<file>textscroll.c</file>
<file>theming_style_classes.c</file>
@@ -314,9 +280,6 @@
<gresource prefix="/fixed">
<file>fixed.css</file>
</gresource>
<gresource prefix="/fontrendering">
<file>fontrendering.ui</file>
</gresource>
<gresource prefix="/org/gtk/Demo4">
<file>icons/16x16/actions/application-exit.png</file>
<file>icons/16x16/actions/document-new.png</file>

View File

@@ -129,13 +129,13 @@ demo_tagged_entry_size_allocate (GtkWidget *widget,
baseline);
}
static gboolean
static void
demo_tagged_entry_grab_focus (GtkWidget *widget)
{
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (widget);
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
return gtk_widget_grab_focus (priv->entry);
gtk_widget_grab_focus (priv->entry);
}
static void

View File

@@ -1,29 +1,28 @@
/* Entry/Entry Undo
/* Entry/Entry Buffer
*
* GtkEntry can provide basic Undo/Redo support using standard keyboard
* accelerators such as Primary+z to undo and Primary+Shift+z to redo.
* Additionally, Primary+y can be used to redo.
*
* Use gtk_entry_set_enable_undo() to enable undo/redo support.
* GtkEntryBuffer provides the text content in a GtkEntry.
* Applications can provide their own buffer implementation,
* e.g. to provide secure handling for passwords in memory.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
GtkWidget *
do_entry_undo (GtkWidget *do_widget)
do_entry_buffer (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *vbox;
GtkWidget *label;
GtkWidget *entry;
GtkEntryBuffer *buffer;
if (!window)
{
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Entry Undo");
gtk_window_set_title (GTK_WINDOW (window), "Entry Buffer");
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
@@ -34,13 +33,22 @@ do_entry_undo (GtkWidget *do_widget)
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label),
"Use Primary+z or Primary+Shift+z to undo or redo changes");
"Entries share a buffer. Typing in one is reflected in the other.");
gtk_container_add (GTK_CONTAINER (vbox), label);
/* Create our entry */
entry = gtk_entry_new ();
gtk_editable_set_enable_undo (GTK_EDITABLE (entry), TRUE);
/* Create a buffer */
buffer = gtk_entry_buffer_new (NULL, 0);
/* Create our first entry */
entry = gtk_entry_new_with_buffer (buffer);
gtk_container_add (GTK_CONTAINER (vbox), entry);
/* Create the second entry */
entry = gtk_entry_new_with_buffer (buffer);
gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
gtk_container_add (GTK_CONTAINER (vbox), entry);
g_object_unref (buffer);
}
if (!gtk_widget_get_visible (window))

View File

@@ -52,7 +52,7 @@ do_expander (GtkWidget *do_widget)
area = gtk_message_dialog_get_message_area (GTK_MESSAGE_DIALOG (window));
label = gtk_widget_get_last_child (area);
gtk_label_set_wrap (GTK_LABEL (label), FALSE);
gtk_label_set_line_wrap (GTK_LABEL (label), FALSE);
gtk_widget_set_vexpand (label, FALSE);
expander = gtk_expander_new ("Details:");

View File

@@ -122,6 +122,7 @@ do_filtermodel (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/filtermodel/filtermodel.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -124,7 +124,7 @@ create_label (void)
{
GtkWidget *w = gtk_label_new ("pLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.");
gtk_label_set_wrap (GTK_LABEL (w), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
gtk_label_set_max_width_chars (GTK_LABEL (w), 100);
return w;
@@ -226,8 +226,8 @@ set_widget_type (GtkFishbowl *fishbowl,
}
void
fishbowl_next_button_clicked_cb (GtkButton *source,
gpointer user_data)
next_button_clicked_cb (GtkButton *source,
gpointer user_data)
{
GtkFishbowl *fishbowl = user_data;
int new_index;
@@ -241,8 +241,8 @@ fishbowl_next_button_clicked_cb (GtkButton *source,
}
void
fishbowl_prev_button_clicked_cb (GtkButton *source,
gpointer user_data)
prev_button_clicked_cb (GtkButton *source,
gpointer user_data)
{
GtkFishbowl *fishbowl = user_data;
int new_index;
@@ -256,8 +256,8 @@ fishbowl_prev_button_clicked_cb (GtkButton *source,
}
void
fishbowl_changes_toggled_cb (GtkToggleButton *button,
gpointer user_data)
changes_toggled_cb (GtkToggleButton *button,
gpointer user_data)
{
if (gtk_toggle_button_get_active (button))
gtk_button_set_icon_name (GTK_BUTTON (button), "changes-prevent");
@@ -265,14 +265,6 @@ fishbowl_changes_toggled_cb (GtkToggleButton *button,
gtk_button_set_icon_name (GTK_BUTTON (button), "changes-allow");
}
char *
format_header_cb (GObject *object,
guint count,
double fps)
{
return g_strdup_printf ("%u Icons, %.2f fps", count, fps);
}
GtkWidget *
do_fishbowl (GtkWidget *do_widget)
{
@@ -296,6 +288,12 @@ do_fishbowl (GtkWidget *do_widget)
g_type_ensure (GTK_TYPE_FISHBOWL);
builder = gtk_builder_new_from_resource ("/fishbowl/fishbowl.ui");
gtk_builder_add_callback_symbols (builder,
"next_button_clicked_cb", G_CALLBACK (next_button_clicked_cb),
"prev_button_clicked_cb", G_CALLBACK (prev_button_clicked_cb),
"changes_toggled_cb", G_CALLBACK (changes_toggled_cb),
NULL);
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
@@ -308,7 +306,6 @@ do_fishbowl (GtkWidget *do_widget)
G_CALLBACK (gtk_widget_destroyed), &window);
gtk_widget_realize (window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))

View File

@@ -15,32 +15,42 @@
<child>
<object class="GtkButton">
<property name="icon-name">pan-start-symbolic</property>
<signal name="clicked" handler="fishbowl_prev_button_clicked_cb" object="bowl" swapped="no"/>
<signal name="clicked" handler="prev_button_clicked_cb" object="bowl" swapped="no"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="icon-name">pan-end-symbolic</property>
<signal name="clicked" handler="fishbowl_next_button_clicked_cb" object="bowl" swapped="no"/>
<signal name="clicked" handler="next_button_clicked_cb" object="bowl" swapped="no"/>
</object>
</child>
</object>
</child>
<child type="end">
<object class="GtkLabel">
<binding name="label">
<closure type="gchararray" function="format_header_cb">
<lookup name="count">bowl</lookup>
<lookup name="framerate">bowl</lookup>
</closure>
</binding>
<property name="label">fps</property>
</object>
</child>
<child type="end">
<object class="GtkLabel">
<property name="label" bind-source="bowl" bind-property="framerate-string"/>
</object>
</child>
<child type="end">
<object class="GtkLabel">
<property name="label">Icons, </property>
</object>
</child>
<child type="end">
<object class="GtkLabel">
<property name="label" bind-source="bowl" bind-property="count"/>
</object>
</child>
<child type="end">
<object class="GtkToggleButton" id="changes_allow">
<property name="icon-name">changes-allow</property>
<property name="relief">none</property>
<signal name="notify::active" handler="fishbowl_changes_toggled_cb"/>
<signal name="notify::active" handler="changes_toggled_cb"/>
</object>
</child>
</object>

View File

@@ -13,7 +13,7 @@
<property name="can-focus">1</property>
<property name="receives-default">1</property>
<property name="tooltip-text">Reset</property>
<signal name="clicked" handler="font_features_reset_features" swapped="no"/>
<signal name="clicked" handler="reset" swapped="no"/>
<child>
<object class="GtkImage">
<property name="icon-name">view-refresh-symbolic</property>
@@ -42,7 +42,7 @@
<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"/>
<signal name="font-set" handler="font_changed" swapped="no"/>
</object>
</child>
<child>
@@ -63,7 +63,7 @@
<object class="GtkComboBox" id="script_lang">
<property name="can-focus">1</property>
<property name="margin-top">10</property>
<signal name="changed" handler="font_features_script_changed" swapped="no"/>
<signal name="changed" handler="script_changed" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
@@ -137,7 +137,7 @@
Разъяренный чтец эгоистично бьёт пятью жердями шустрого фехтовальщика. Наш банк вчера же выплатил Ф.Я. Эйхгольду комиссию за ценные вещи. Эх, чужак, общий съём цен шляп (юфть) вдрызг! В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!
Τάχιστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός</property>
<signal name="activate" handler="font_features_stop_edit"/>
<signal name="activate" handler="stop_edit"/>
<property name="valign">start</property>
<property name="width-chars">50</property>
</object>
@@ -181,7 +181,7 @@
<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"/>
<signal name="toggled" handler="toggle_edit"/>
</object>
</child>
</object>

View File

@@ -15,6 +15,10 @@
#include <pango/pangofc-font.h>
#include <hb.h>
#include <hb-ot.h>
#include <hb-ft.h>
#include <freetype/ftmm.h>
#include <freetype/ftsnames.h>
#include <freetype/ttnameid.h>
#include <glib/gi18n.h>
#include "open-type-layout.h"
@@ -480,6 +484,7 @@ update_script_combo (void)
GtkListStore *store;
hb_font_t *hb_font;
gint i, j, k;
FT_Face ft_face;
PangoFont *pango_font;
GHashTable *tags;
GHashTableIter iter;
@@ -500,7 +505,8 @@ update_script_combo (void)
store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
pango_font = get_pango_font ();
hb_font = pango_font_get_hb_font (pango_font);
ft_face = pango_fc_font_lock_face (PANGO_FC_FONT (pango_font)),
hb_font = hb_ft_font_create (ft_face, NULL);
tags = g_hash_table_new_full (tag_pair_hash, tag_pair_equal, g_free, NULL);
@@ -539,8 +545,11 @@ update_script_combo (void)
}
}
}
hb_face_destroy (hb_face);
}
pango_fc_font_unlock_face (PANGO_FC_FONT (pango_font));
g_object_unref (pango_font);
g_hash_table_iter_init (&iter, tags);
@@ -598,6 +607,7 @@ update_features (void)
GtkTreeIter iter;
guint script_index, lang_index;
PangoFont *pango_font;
FT_Face ft_face;
hb_font_t *hb_font;
GList *l;
@@ -622,7 +632,8 @@ update_features (void)
-1);
pango_font = get_pango_font ();
hb_font = pango_font_get_hb_font (pango_font);
ft_face = pango_fc_font_lock_face (PANGO_FC_FONT (pango_font)),
hb_font = hb_ft_font_create (ft_face, NULL);
if (hb_font)
{
@@ -704,8 +715,11 @@ update_features (void)
g_free (feat);
}
hb_face_destroy (hb_face);
}
pango_fc_font_unlock_face (PANGO_FC_FONT (pango_font));
g_object_unref (pango_font);
}
@@ -786,29 +800,24 @@ axes_equal (gconstpointer v1, gconstpointer v2)
}
static void
add_axis (hb_face_t *hb_face,
hb_ot_var_axis_info_t *ax,
float value,
int i)
add_axis (FT_Var_Axis *ax, FT_Fixed value, int i)
{
GtkWidget *axis_label;
GtkWidget *axis_entry;
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);
axis_label = gtk_label_new (ax->name);
gtk_widget_set_halign (axis_label, GTK_ALIGN_START);
gtk_widget_set_valign (axis_label, GTK_ALIGN_BASELINE);
gtk_grid_attach (GTK_GRID (variations_grid), axis_label, 0, i, 1, 1);
adjustment = gtk_adjustment_new (value, ax->min_value, ax->max_value,
adjustment = gtk_adjustment_new ((double)FixedToFloat(value),
(double)FixedToFloat(ax->minimum),
(double)FixedToFloat(ax->maximum),
1.0, 10.0, 0.0);
axis_scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adjustment);
gtk_scale_add_mark (GTK_SCALE (axis_scale), ax->default_value, GTK_POS_TOP, NULL);
gtk_scale_add_mark (GTK_SCALE (axis_scale), (double)FixedToFloat(ax->def), GTK_POS_TOP, NULL);
gtk_widget_set_valign (axis_scale, GTK_ALIGN_BASELINE);
gtk_widget_set_hexpand (axis_scale, TRUE);
gtk_widget_set_size_request (axis_scale, 100, -1);
@@ -833,7 +842,9 @@ add_axis (hb_face_t *hb_face,
typedef struct {
char *name;
unsigned int index;
int n_axes;
guint32 *axes;
float *coords;
} Instance;
static guint
@@ -859,32 +870,559 @@ free_instance (gpointer data)
Instance *instance = data;
g_free (instance->name);
g_free (instance->axes);
g_free (instance->coords);
g_free (instance);
}
static GHashTable *instances;
typedef struct {
const FT_UShort platform_id;
const FT_UShort encoding_id;
const char fromcode[12];
} FtEncoding;
#define TT_ENCODING_DONT_CARE 0xffff
static const FtEncoding ftEncoding[] = {
{ TT_PLATFORM_APPLE_UNICODE, TT_ENCODING_DONT_CARE, "UTF-16BE" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, "MACINTOSH" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_ID_JAPANESE, "SJIS" },
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, "UTF-16BE" },
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, "UTF-16BE" },
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_SJIS, "SJIS-WIN" },
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_GB2312, "GB2312" },
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_BIG_5, "BIG-5" },
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_WANSUNG, "Wansung" },
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_JOHAB, "Johab" },
{ TT_PLATFORM_MICROSOFT, TT_MS_ID_UCS_4, "UTF-16BE" },
{ TT_PLATFORM_ISO, TT_ISO_ID_7BIT_ASCII, "ASCII" },
{ TT_PLATFORM_ISO, TT_ISO_ID_10646, "UTF-16BE" },
{ TT_PLATFORM_ISO, TT_ISO_ID_8859_1, "ISO-8859-1" },
};
typedef struct {
const FT_UShort platform_id;
const FT_UShort language_id;
const char lang[8];
} FtLanguage;
#define TT_LANGUAGE_DONT_CARE 0xffff
static const FtLanguage ftLanguage[] = {
{ TT_PLATFORM_APPLE_UNICODE, TT_LANGUAGE_DONT_CARE, "" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ENGLISH, "en" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FRENCH, "fr" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GERMAN, "de" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ITALIAN, "it" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DUTCH, "nl" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWEDISH, "sv" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SPANISH, "es" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DANISH, "da" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PORTUGUESE, "pt" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NORWEGIAN, "no" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HEBREW, "he" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAPANESE, "ja" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARABIC, "ar" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FINNISH, "fi" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK, "el" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ICELANDIC, "is" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALTESE, "mt" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKISH, "tr" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CROATIAN, "hr" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_TRADITIONAL, "zh-tw" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_URDU, "ur" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HINDI, "hi" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_THAI, "th" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KOREAN, "ko" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LITHUANIAN, "lt" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_POLISH, "pl" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_HUNGARIAN, "hu" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESTONIAN, "et" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LETTISH, "lv" },
/* { TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SAAMISK, ??? */
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FAEROESE, "fo" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FARSI, "fa" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUSSIAN, "ru" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHINESE_SIMPLIFIED, "zh-cn" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_FLEMISH, "nl" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH, "ga" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ALBANIAN, "sq" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ROMANIAN, "ro" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CZECH, "cs" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVAK, "sk" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SLOVENIAN, "sl" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_YIDDISH, "yi" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SERBIAN, "sr" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MACEDONIAN, "mk" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BULGARIAN, "bg" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UKRAINIAN, "uk" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BYELORUSSIAN, "be" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UZBEK, "uz" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KAZAKH, "kk" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI, "az" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_CYRILLIC_SCRIPT, "az" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ARABIC_SCRIPT, "ar" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ARMENIAN, "hy" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GEORGIAN, "ka" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MOLDAVIAN, "mo" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KIRGHIZ, "ky" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAJIKI, "tg" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TURKMEN, "tk" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN, "mo" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_MONGOLIAN_SCRIPT,"mo" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MONGOLIAN_CYRILLIC_SCRIPT, "mo" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PASHTO, "ps" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KURDISH, "ku" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KASHMIRI, "ks" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINDHI, "sd" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIBETAN, "bo" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_NEPALI, "ne" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SANSKRIT, "sa" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MARATHI, "mr" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BENGALI, "bn" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ASSAMESE, "as" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUJARATI, "gu" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_PUNJABI, "pa" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ORIYA, "or" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAYALAM, "ml" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KANNADA, "kn" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAMIL, "ta" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TELUGU, "te" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SINHALESE, "si" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BURMESE, "my" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_KHMER, "km" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LAO, "lo" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_VIETNAMESE, "vi" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INDONESIAN, "id" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TAGALOG, "tl" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ROMAN_SCRIPT, "ms" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAY_ARABIC_SCRIPT, "ms" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AMHARIC, "am" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TIGRINYA, "ti" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALLA, "om" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SOMALI, "so" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SWAHILI, "sw" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUANDA, "rw" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_RUNDI, "rn" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CHEWA, "ny" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MALAGASY, "mg" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_ESPERANTO, "eo" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_WELSH, "cy" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BASQUE, "eu" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_CATALAN, "ca" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_LATIN, "la" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_QUECHUA, "qu" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GUARANI, "gn" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AYMARA, "ay" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TATAR, "tt" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_UIGHUR, "ug" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_DZONGKHA, "dz" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_JAVANESE, "jw" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SUNDANESE, "su" },
#if 0 /* these seem to be errors that have been dropped */
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC },
#endif
/* The following codes are new as of 2000-03-10 */
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GALICIAN, "gl" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AFRIKAANS, "af" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_BRETON, "br" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_INUKTITUT, "iu" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_SCOTTISH_GAELIC, "gd" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_MANX_GAELIC, "gv" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_IRISH_GAELIC, "ga" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_TONGAN, "to" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREEK_POLYTONIC, "el" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_GREELANDIC, "ik" },
{ TT_PLATFORM_MACINTOSH, TT_MAC_LANGID_AZERBAIJANI_ROMAN_SCRIPT,"az" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SAUDI_ARABIA, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_IRAQ, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_EGYPT, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LIBYA, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_ALGERIA, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_MOROCCO, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_TUNISIA, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_OMAN, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_YEMEN, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_SYRIA, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_JORDAN, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_LEBANON, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_KUWAIT, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_UAE, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_BAHRAIN, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_QATAR, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BULGARIAN_BULGARIA, "bg" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CATALAN_SPAIN, "ca" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_TAIWAN, "zh-tw" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_PRC, "zh-cn" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_HONG_KONG, "zh-hk" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_SINGAPORE, "zh-sg" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_MACAU, "zh-mo" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CZECH_CZECH_REPUBLIC, "cs" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DANISH_DENMARK, "da" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_GERMANY, "de" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_SWITZERLAND, "de" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_AUSTRIA, "de" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LUXEMBOURG, "de" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GERMAN_LIECHTENSTEI, "de" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE, "el" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_STATES, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_UNITED_KINGDOM, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_AUSTRALIA, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CANADA, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_NEW_ZEALAND, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_IRELAND, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SOUTH_AFRICA, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_JAMAICA, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_CARIBBEAN, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_BELIZE, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_TRINIDAD, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_ZIMBABWE, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_PHILIPPINES, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_TRADITIONAL_SORT,"es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_MEXICO, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_SPAIN_INTERNATIONAL_SORT,"es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_GUATEMALA, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COSTA_RICA, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PANAMA, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_DOMINICAN_REPUBLIC,"es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_VENEZUELA, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_COLOMBIA, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PERU, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ARGENTINA, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_ECUADOR, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_CHILE, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_URUGUAY, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PARAGUAY, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_BOLIVIA, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_EL_SALVADOR, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_HONDURAS, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_NICARAGUA, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_PUERTO_RICO, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FINNISH_FINLAND, "fi" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_FRANCE, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_BELGIUM, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CANADA, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SWITZERLAND, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_LUXEMBOURG, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MONACO, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HEBREW_ISRAEL, "he" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HUNGARIAN_HUNGARY, "hu" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ICELANDIC_ICELAND, "is" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_ITALY, "it" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ITALIAN_SWITZERLAND, "it" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_JAPANESE_JAPAN, "ja" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_EXTENDED_WANSUNG_KOREA,"ko" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KOREAN_JOHAB_KOREA, "ko" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_NETHERLANDS, "nl" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DUTCH_BELGIUM, "nl" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_BOKMAL, "no" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NORWEGIAN_NORWAY_NYNORSK, "nn" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_POLISH_POLAND, "pl" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_BRAZIL, "pt" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PORTUGUESE_PORTUGAL, "pt" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RHAETO_ROMANIC_SWITZERLAND,"rm" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ROMANIAN_ROMANIA, "ro" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MOLDAVIAN_MOLDAVIA, "mo" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_RUSSIA, "ru" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_RUSSIAN_MOLDAVIA, "ru" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CROATIAN_CROATIA, "hr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_LATIN, "sr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SERBIAN_SERBIA_CYRILLIC, "sr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVAK_SLOVAKIA, "sk" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ALBANIAN_ALBANIA, "sq" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_SWEDEN, "sv" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWEDISH_FINLAND, "sv" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_THAI_THAILAND, "th" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKISH_TURKEY, "tr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_PAKISTAN, "ur" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INDONESIAN_INDONESIA, "id" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UKRAINIAN_UKRAINE, "uk" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BELARUSIAN_BELARUS, "be" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SLOVENE_SLOVENIA, "sl" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ESTONIAN_ESTONIA, "et" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATVIAN_LATVIA, "lv" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LITHUANIAN_LITHUANIA, "lt" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CLASSIC_LITHUANIAN_LITHUANIA,"lt" },
#ifdef TT_MS_LANGID_MAORI_NEW_ZELAND
/* this seems to be an error that have been dropped */
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MAORI_NEW_ZEALAND, "mi" },
#endif
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FARSI_IRAN, "fa" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VIETNAMESE_VIET_NAM, "vi" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARMENIAN_ARMENIA, "hy" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_LATIN, "az" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AZERI_AZERBAIJAN_CYRILLIC, "az" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BASQUE_SPAIN, "eu" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SORBIAN_GERMANY, "wen" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MACEDONIAN_MACEDONIA, "mk" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SUTU_SOUTH_AFRICA, "st" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSONGA_SOUTH_AFRICA, "ts" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TSWANA_SOUTH_AFRICA, "tn" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_VENDA_SOUTH_AFRICA, "ven" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_XHOSA_SOUTH_AFRICA, "xh" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ZULU_SOUTH_AFRICA, "zu" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AFRIKAANS_SOUTH_AFRICA, "af" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GEORGIAN_GEORGIA, "ka" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FAEROESE_FAEROE_ISLANDS, "fo" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HINDI_INDIA, "hi" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALTESE_MALTA, "mt" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SAAMI_LAPONIA, "se" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SCOTTISH_GAELIC_UNITED_KINGDOM,"gd" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IRISH_GAELIC_IRELAND, "ga" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_MALAYSIA, "ms" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAY_BRUNEI_DARUSSALAM, "ms" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KAZAK_KAZAKSTAN, "kk" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SWAHILI_KENYA, "sw" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_LATIN, "uz" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_UZBEK_UZBEKISTAN_CYRILLIC, "uz" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TATAR_TATARSTAN, "tt" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_INDIA, "bn" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_INDIA, "pa" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUJARATI_INDIA, "gu" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ORIYA_INDIA, "or" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMIL_INDIA, "ta" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TELUGU_INDIA, "te" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANNADA_INDIA, "kn" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MALAYALAM_INDIA, "ml" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ASSAMESE_INDIA, "as" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MARATHI_INDIA, "mr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SANSKRIT_INDIA, "sa" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KONKANI_INDIA, "kok" },
/* new as of 2001-01-01 */
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ARABIC_GENERAL, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHINESE_GENERAL, "zh" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_GENERAL, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_WEST_INDIES, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_REUNION, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CONGO, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_SENEGAL, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_CAMEROON, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_COTE_D_IVOIRE, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MALI, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BOSNIAN_BOSNIA_HERZEGOVINA,"bs" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_URDU_INDIA, "ur" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAJIK_TAJIKISTAN, "tg" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YIDDISH_GERMANY, "yi" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KIRGHIZ_KIRGHIZSTAN, "ky" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TURKMEN_TURKMENISTAN, "tk" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA, "mn" },
/* the following seems to be inconsistent;
here is the current "official" way: */
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_BHUTAN, "bo" },
/* and here is what is used by Passport SDK */
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIBETAN_CHINA, "bo" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DZONGHKA_BHUTAN, "dz" },
/* end of inconsistency */
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_WELSH_WALES, "cy" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KHMER_CAMBODIA, "km" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LAO_LAOS, "lo" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BURMESE_MYANMAR, "my" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GALICIAN_SPAIN, "gl" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MANIPURI_INDIA, "mni" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINDHI_INDIA, "sd" },
/* the following one is only encountered in Microsoft RTF specification */
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_PAKISTAN, "ks" },
/* the following one is not in the Passport list, looks like an omission */
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KASHMIRI_INDIA, "ks" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_NEPAL, "ne" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_NEPALI_INDIA, "ne" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRISIAN_NETHERLANDS, "fy" },
/* new as of 2001-03-01 (from Office Xp) */
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_HONG_KONG, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_INDIA, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_MALAYSIA, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_ENGLISH_SINGAPORE, "en" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SYRIAC_SYRIA, "syr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SINHALESE_SRI_LANKA, "si" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_CHEROKEE_UNITED_STATES, "chr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_INUKTITUT_CANADA, "iu" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_AMHARIC_ETHIOPIA, "am" },
#if 0
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TAMAZIGHT_MOROCCO_LATIN },
#endif
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PASHTO_AFGHANISTAN, "ps" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FILIPINO_PHILIPPINES, "phi" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_DHIVEHI_MALDIVES, "div" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_OROMO_ETHIOPIA, "om" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ETHIOPIA, "ti" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_TIGRIGNA_ERYTHREA, "ti" },
/* New additions from Windows Xp/Passport SDK 2001-11-10. */
/* don't ask what this one means... It is commented out currently. */
#if 0
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GREEK_GREECE2 },
#endif
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_UNITED_STATES, "es" },
/* The following two IDs blatantly violate MS specs by using a */
/* sublanguage >,. */
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SPANISH_LATIN_AMERICA, "es" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_NORTH_AFRICA, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_MOROCCO, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FRENCH_HAITI, "fr" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_BENGALI_BANGLADESH, "bn" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PUNJABI_ARABIC_PAKISTAN, "ar" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_MONGOLIAN_MONGOLIA_MONGOLIAN,"mn" },
#if 0
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_EDO_NIGERIA },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_FULFULDE_NIGERIA },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IBIBIO_NIGERIA },
#endif
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAUSA_NIGERIA, "ha" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YORUBA_NIGERIA, "yo" },
/* language codes from, to, are (still) unknown. */
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_IGBO_NIGERIA, "ibo" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_KANURI_NIGERIA, "kau" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_GUARANI_PARAGUAY, "gn" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_HAWAIIAN_UNITED_STATES, "haw" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_LATIN, "la" },
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_SOMALI_SOMALIA, "so" },
#if 0
/* Note: Yi does not have a (proper) ISO 639-2 code, since it is mostly */
/* not written (but OTOH the peculiar writing system is worth */
/* studying). */
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_YI_CHINA },
#endif
{ TT_PLATFORM_MICROSOFT, TT_MS_LANGID_PAPIAMENTU_NETHERLANDS_ANTILLES,"pap" },
};
static const char *
FcSfntNameLanguage (FT_SfntName *sname)
{
int i;
FT_UShort platform_id = sname->platform_id;
FT_UShort language_id = sname->language_id;
for (i = 0; i < G_N_ELEMENTS (ftLanguage); i++)
if (ftLanguage[i].platform_id == platform_id &&
(ftLanguage[i].language_id == TT_LANGUAGE_DONT_CARE ||
ftLanguage[i].language_id == language_id))
{
if (ftLanguage[i].lang[0] == '\0')
return NULL;
else
return ftLanguage[i].lang;
}
return NULL;
}
static char *
FcSfntNameTranscode (FT_SfntName *name)
{
int i;
const char *fromcode;
for (i = 0; i < G_N_ELEMENTS (ftEncoding); i++)
if (ftEncoding[i].platform_id == name->platform_id &&
(ftEncoding[i].encoding_id == TT_ENCODING_DONT_CARE ||
ftEncoding[i].encoding_id == name->encoding_id))
break;
if (i == G_N_ELEMENTS (ftEncoding))
return NULL;
fromcode = ftEncoding[i].fromcode;
return g_convert ((const char *)name->string, name->string_len, "UTF-8", fromcode, NULL, NULL, NULL);
}
static char *
get_sfnt_name (FT_Face ft_face,
guint nameid)
{
guint count;
guint i, j;
const char * const *langs = g_get_language_names ();
char *res = NULL;
guint pos = G_MAXUINT;
count = FT_Get_Sfnt_Name_Count (ft_face);
for (i = 0; i < count; i++)
{
FT_SfntName name;
const char *lang;
if (FT_Get_Sfnt_Name (ft_face, i, &name) != 0)
continue;
if (name.name_id != nameid)
continue;
lang = FcSfntNameLanguage (&name);
for (j = 0; j < pos && langs[j]; j++)
{
if (strcmp (lang, langs[j]) == 0)
{
pos = j;
g_free (res);
res = FcSfntNameTranscode (&name);
}
}
if (pos == 0)
break;
}
return res;
}
static gboolean
is_valid_subfamily_id (guint id)
{
return id == 2 || id == 17 || (255 < id && id < 32768);
}
static void
add_instance (hb_face_t *face,
unsigned int index,
GtkWidget *combo,
int pos)
add_instance (FT_Face ft_face,
FT_MM_Var *ft_mm_var,
FT_Var_Named_Style *ns,
GtkWidget *combo,
int pos)
{
Instance *instance;
hb_ot_name_id_t name_id;
char name[20];
unsigned int name_len = 20;
int i;
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;
if (is_valid_subfamily_id (ns->strid))
instance->name = get_sfnt_name (ft_face, ns->strid);
if (!instance->name)
instance->name = g_strdup_printf ("Instance %d", pos);
g_hash_table_add (instances, instance);
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), instance->name);
instance->n_axes = ft_mm_var->num_axis;
instance->axes = g_new (guint32, ft_mm_var->num_axis);
instance->coords = g_new (float, ft_mm_var->num_axis);
for (i = 0; i < ft_mm_var->num_axis; i++)
{
instance->axes[i] = ft_mm_var->axis[i].tag;
instance->coords[i] = FixedToFloat(ns->coords[i]);
}
}
static void
@@ -901,13 +1439,6 @@ instance_changed (GtkComboBox *combo)
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;
PangoFont *pango_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')
@@ -921,29 +1452,17 @@ instance_changed (GtkComboBox *combo)
goto out;
}
pango_font = get_pango_font ();
hb_font = pango_font_get_hb_font (pango_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++)
for (i = 0; i < instance->n_axes; i++)
{
Axis *axis;
Axis akey;
guint32 tag;
gdouble value;
value = coords[ai[i].axis_index];
tag = instance->axes[i];
value = instance->coords[i];
akey.tag = ai[i].tag;
akey.tag = tag;
axis = g_hash_table_lookup (axes, &akey);
if (axis)
{
@@ -955,31 +1474,17 @@ instance_changed (GtkComboBox *combo)
out:
g_free (text);
g_clear_object (&pango_font);
g_free (ai);
g_free (coords);
}
static gboolean
matches_instance (hb_face_t *hb_face,
unsigned int index,
unsigned int n_axes,
float *coords)
matches_instance (FT_Var_Named_Style *instance,
FT_Fixed *coords,
FT_UInt num_coords)
{
float *instance_coords;
unsigned int coords_length;
int i;
FT_UInt i;
instance_coords = g_new (float, n_axes);
coords_length = n_axes;
hb_ot_var_named_instance_get_design_coords (hb_face,
index,
&coords_length,
instance_coords);
for (i = 0; i < n_axes; i++)
if (instance_coords[i] != coords[i])
for (i = 0; i < num_coords; i++)
if (coords[i] != instance->coords[i])
return FALSE;
return TRUE;
@@ -1010,31 +1515,14 @@ add_font_plane (int i)
}
}
/* FIXME: This doesn't work if the font has an avar table */
static float
denorm_coord (hb_ot_var_axis_info_t *axis, int coord)
{
float r = coord / 16384.0;
if (coord < 0)
return axis->default_value + r * (axis->default_value - axis->min_value);
else
return axis->default_value + r * (axis->max_value - axis->default_value);
}
static void
update_font_variations (void)
{
GtkWidget *child, *next;
PangoFont *pango_font = NULL;
hb_font_t *hb_font;
hb_face_t *hb_face;
unsigned int n_axes;
hb_ot_var_axis_info_t *ai = NULL;
float *design_coords = NULL;
const int *coords;
unsigned int length;
int i;
PangoFont *pango_font;
FT_Face ft_face;
FT_MM_Var *ft_mm_var;
FT_Error ret;
child = gtk_widget_get_first_child (variations_grid);
while (child != NULL)
@@ -1050,82 +1538,81 @@ update_font_variations (void)
g_hash_table_remove_all (instances);
pango_font = get_pango_font ();
hb_font = pango_font_get_hb_font (pango_font);
hb_face = hb_font_get_face (hb_font);
ft_face = pango_fc_font_lock_face (PANGO_FC_FONT (pango_font)),
n_axes = hb_ot_var_get_axis_infos (hb_face, 0, NULL, NULL);
if (n_axes == 0)
goto done;
ai = g_new0 (hb_ot_var_axis_info_t, n_axes);
design_coords = g_new (float, n_axes);
hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, ai);
coords = hb_font_get_var_coords_normalized (hb_font, &length);
for (i = 0; i < length; i++)
design_coords[i] = denorm_coord (&ai[i], coords[i]);
if (hb_ot_var_get_named_instance_count (hb_face) > 0)
ret = FT_Get_MM_Var (ft_face, &ft_mm_var);
if (ret == 0)
{
GtkWidget *label;
GtkWidget *combo;
unsigned int i;
FT_Fixed *coords;
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 (GTK_GRID (variations_grid), label, 0, -1, 2, 1);
coords = g_new (FT_Fixed, ft_mm_var->num_axis);
ret = FT_Get_Var_Design_Coordinates (ft_face, ft_mm_var->num_axis, coords);
combo = gtk_combo_box_text_new ();
gtk_widget_set_valign (combo, GTK_ALIGN_BASELINE);
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 (hb_face, i, combo, i);
for (i = 0; i < hb_ot_var_get_named_instance_count (hb_face); i++)
if (ft_mm_var->num_namedstyles > 0)
{
if (matches_instance (hb_face, i, n_axes, design_coords))
{
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), i + 1);
break;
}
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 (GTK_GRID (variations_grid), label, 0, -1, 2, 1);
combo = gtk_combo_box_text_new ();
gtk_widget_set_valign (combo, GTK_ALIGN_BASELINE);
g_signal_connect (combo, "changed", G_CALLBACK (instance_changed), NULL);
gtk_grid_attach (GTK_GRID (variations_grid), combo, 1, -1, 2, 1);
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "");
for (i = 0; i < ft_mm_var->num_namedstyles; i++)
add_instance (ft_face, ft_mm_var, &ft_mm_var->namedstyle[i], combo, i);
for (i = 0; i < ft_mm_var->num_namedstyles; i++)
{
if (matches_instance (&ft_mm_var->namedstyle[i], coords, ft_mm_var->num_axis))
{
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), i + 1);
break;
}
}
instance_combo = combo;
}
gtk_grid_attach (GTK_GRID (variations_grid), combo, 1, -1, 2, 1);
g_signal_connect (combo, "changed", G_CALLBACK (instance_changed), NULL);
instance_combo = combo;
}
if (ret == 0)
{
for (i = 0; i < ft_mm_var->num_axis; i++)
add_axis (&ft_mm_var->axis[i], coords[i], i);
for (i = 0; i < n_axes; i++)
add_axis (hb_face, &ai[i], design_coords[i], i);
add_font_plane (ft_mm_var->num_axis);
}
g_free (coords);
free (ft_mm_var);
}
add_font_plane (n_axes);
done:
g_clear_object (&pango_font);
g_free (ai);
g_free (design_coords);
pango_fc_font_unlock_face (PANGO_FC_FONT (pango_font));
g_object_unref (pango_font);
}
void
font_features_font_changed (void)
static void
font_changed (void)
{
update_script_combo ();
update_features ();
update_font_variations ();
}
void
font_features_script_changed (void)
static void
script_changed (void)
{
update_features ();
update_display ();
}
void
font_features_reset_features (void)
static void
reset_features (void)
{
GList *l;
@@ -1170,8 +1657,8 @@ switch_to_label (void)
update_display ();
}
void
font_features_toggle_edit (void)
static void
toggle_edit (void)
{
if (strcmp (gtk_stack_get_visible_child_name (GTK_STACK (stack)), "label") == 0)
switch_to_entry ();
@@ -1179,8 +1666,8 @@ font_features_toggle_edit (void)
switch_to_label ();
}
void
font_features_stop_edit (void)
static void
stop_edit (void)
{
g_signal_emit_by_name (edit_toggle, "clicked");
}
@@ -1195,7 +1682,7 @@ entry_key_press (GtkEventController *controller,
if (keyval == GDK_KEY_Escape)
{
gtk_editable_set_text (GTK_EDITABLE (entry), text);
font_features_stop_edit ();
stop_edit ();
return GDK_EVENT_STOP;
}
@@ -1215,6 +1702,14 @@ do_font_features (GtkWidget *do_widget)
builder = gtk_builder_new_from_resource ("/font_features/font-features.ui");
gtk_builder_add_callback_symbol (builder, "update_display", update_display);
gtk_builder_add_callback_symbol (builder, "font_changed", font_changed);
gtk_builder_add_callback_symbol (builder, "script_changed", script_changed);
gtk_builder_add_callback_symbol (builder, "reset", reset_features);
gtk_builder_add_callback_symbol (builder, "stop_edit", G_CALLBACK (stop_edit));
gtk_builder_add_callback_symbol (builder, "toggle_edit", G_CALLBACK (toggle_edit));
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
feature_list = GTK_WIDGET (gtk_builder_get_object (builder, "feature_list"));
label = GTK_WIDGET (gtk_builder_get_object (builder, "label"));
@@ -1331,7 +1826,7 @@ do_font_features (GtkWidget *do_widget)
else
g_hash_table_remove_all (axes);
font_features_font_changed ();
font_changed ();
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);

View File

@@ -19,6 +19,8 @@
#include "fontplane.h"
#include "gtk.h"
enum {
PROP_0,
PROP_WEIGHT_ADJUSTMENT,

View File

@@ -1,287 +0,0 @@
/* Pango/Font rendering
*
* Demonstrates various aspects of font rendering.
*/
#include <gtk/gtk.h>
static GtkWidget *window = NULL;
static GtkWidget *font_button = NULL;
static GtkWidget *entry = NULL;
static GtkWidget *image = NULL;
static GtkWidget *hinting = NULL;
static GtkWidget *hint_metrics = NULL;
static GtkWidget *up_button = NULL;
static GtkWidget *down_button = NULL;
static GtkWidget *text_radio = NULL;
static GtkWidget *show_grid = NULL;
static GtkWidget *show_extents = NULL;
static PangoContext *context;
static int scale = 10;
static void
on_destroy (gpointer data)
{
window = NULL;
}
static void
update_image (void)
{
const char *text;
PangoFontDescription *desc;
PangoLayout *layout;
PangoRectangle ink, pink, logical;
int baseline;
cairo_surface_t *surface;
cairo_t *cr;
GdkPixbuf *pixbuf;
GdkPixbuf *pixbuf2;
const char *hint;
cairo_font_options_t *fopt;
cairo_hint_style_t hintstyle;
cairo_hint_metrics_t hintmetrics;
int i;
if (!context)
context = gtk_widget_create_pango_context (image);
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 (pango_cairo_context_get_font_options (context));
hint = gtk_combo_box_get_active_id (GTK_COMBO_BOX (hinting));
if (strcmp (hint, "none") == 0)
hintstyle = CAIRO_HINT_STYLE_NONE;
else if (strcmp (hint, "slight") == 0)
hintstyle = CAIRO_HINT_STYLE_SLIGHT;
else if (strcmp (hint, "medium") == 0)
hintstyle = CAIRO_HINT_STYLE_MEDIUM;
else if (strcmp (hint, "full") == 0)
hintstyle = CAIRO_HINT_STYLE_FULL;
else
hintstyle = CAIRO_HINT_STYLE_DEFAULT;
cairo_font_options_set_hint_style (fopt, hintstyle);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (hint_metrics)))
hintmetrics = CAIRO_HINT_METRICS_ON;
else
hintmetrics = CAIRO_HINT_METRICS_OFF;
cairo_font_options_set_hint_metrics (fopt, hintmetrics);
pango_cairo_context_set_font_options (context, fopt);
cairo_font_options_destroy (fopt);
pango_context_changed (context);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (text_radio)))
{
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);
pink = ink;
baseline = pango_layout_get_baseline (layout);
pango_extents_to_pixels (&ink, NULL);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ink.width + 20, ink.height + 20);
cr = cairo_create (surface);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_move_to (cr, 10, 10);
pango_cairo_show_layout (cr, layout);
cairo_destroy (cr);
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));
pixbuf2 = gdk_pixbuf_scale_simple (pixbuf, gdk_pixbuf_get_width (pixbuf) * scale, gdk_pixbuf_get_height (pixbuf) * scale, GDK_INTERP_NEAREST);
g_object_unref (pixbuf);
cairo_surface_destroy (surface);
surface = cairo_image_surface_create_for_data (gdk_pixbuf_get_pixels (pixbuf2),
CAIRO_FORMAT_ARGB32,
gdk_pixbuf_get_width (pixbuf2),
gdk_pixbuf_get_height (pixbuf2),
gdk_pixbuf_get_rowstride (pixbuf2));
cr = cairo_create (surface);
cairo_set_line_width (cr, 1);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (show_grid)))
{
cairo_set_source_rgba (cr, 0.2, 0, 0, 0.2);
for (i = 1; i < ink.height + 20; i++)
{
cairo_move_to (cr, 0, scale * i - 0.5);
cairo_line_to (cr, scale * (ink.width + 20), scale * i - 0.5);
cairo_stroke (cr);
}
for (i = 1; i < ink.width + 20; i++)
{
cairo_move_to (cr, scale * i - 0.5, 0);
cairo_line_to (cr, scale * i - 0.5, scale * (ink.height + 20));
cairo_stroke (cr);
}
}
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (show_extents)))
{
cairo_set_source_rgba (cr, 0, 0, 1, 1);
cairo_rectangle (cr,
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 + 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_rgba (cr, 1, 0, 0, 1);
cairo_rectangle (cr,
scale * (10 + pango_units_to_double (pink.x)) + 0.5,
scale * (10 + pango_units_to_double (pink.y)) + 0.5,
scale * pango_units_to_double (pink.width) - 1,
scale * pango_units_to_double (pink.height) - 1);
cairo_stroke (cr);
}
cairo_surface_destroy (surface);
cairo_destroy (cr);
}
else
{
PangoLayoutIter *iter;
PangoLayoutRun *run;
PangoGlyphInfo *g;
int i, j;
layout = pango_layout_new (context);
pango_layout_set_font_description (layout, desc);
pango_layout_set_text (layout, "aaaa", -1);
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 = 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 = &(run->glyphs->glyphs[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 = &(run->glyphs->glyphs[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);
pango_cairo_show_layout (cr, layout);
}
cairo_destroy (cr);
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));
pixbuf2 = gdk_pixbuf_scale_simple (pixbuf, gdk_pixbuf_get_width (pixbuf) * scale, gdk_pixbuf_get_height (pixbuf) * scale, GDK_INTERP_NEAREST);
g_object_unref (pixbuf);
cairo_surface_destroy (surface);
}
gtk_picture_set_pixbuf (GTK_PICTURE (image), pixbuf2);
g_object_unref (pixbuf2);
pango_font_description_free (desc);
}
static void
update_buttons (void)
{
gtk_widget_set_sensitive (up_button, scale < 32);
gtk_widget_set_sensitive (down_button, scale > 1);
}
static void
scale_up (void)
{
scale += 1;
update_buttons ();
update_image ();
}
static void
scale_down (void)
{
scale -= 1;
update_buttons ();
update_image ();
}
GtkWidget *
do_fontrendering (GtkWidget *do_widget)
{
if (!window)
{
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/fontrendering/fontrendering.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (on_destroy), NULL);
g_object_set_data_full (G_OBJECT (window), "builder", builder, g_object_unref);
font_button = GTK_WIDGET (gtk_builder_get_object (builder, "font_button"));
up_button = GTK_WIDGET (gtk_builder_get_object (builder, "up_button"));
down_button = GTK_WIDGET (gtk_builder_get_object (builder, "down_button"));
entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry"));
image = GTK_WIDGET (gtk_builder_get_object (builder, "image"));
hinting = GTK_WIDGET (gtk_builder_get_object (builder, "hinting"));
hint_metrics = GTK_WIDGET (gtk_builder_get_object (builder, "hint_metrics"));
text_radio = GTK_WIDGET (gtk_builder_get_object (builder, "text_radio"));
show_grid = GTK_WIDGET (gtk_builder_get_object (builder, "show_grid"));
show_extents = GTK_WIDGET (gtk_builder_get_object (builder, "show_extents"));
g_signal_connect (up_button, "clicked", G_CALLBACK (scale_up), NULL);
g_signal_connect (down_button, "clicked", G_CALLBACK (scale_down), NULL);
g_signal_connect (entry, "notify::text", G_CALLBACK (update_image), NULL);
g_signal_connect (font_button, "notify::font-desc", G_CALLBACK (update_image), NULL);
g_signal_connect (hinting, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (hint_metrics, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (text_radio, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (show_grid, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (show_extents, "notify::active", G_CALLBACK (update_image), NULL);
update_image ();
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,215 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkAdjustment" id="scale_adj">
<property name="upper">24</property>
<property name="step-increment">1</property>
<property name="page-increment">4</property>
</object>
<object class="GtkWindow" id="window">
<property name="default-width">600</property>
<property name="default-height">300</property>
<property name="title">Font rendering</property>
<child>
<object class="GtkGrid">
<property name="margin-top">10</property>
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<child>
<object class="GtkLabel">
<property name="margin-start">10</property>
<property name="label">Text</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkEntry" id="entry">
<property name="text">Fonts render</property>
<layout>
<property name="left-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="margin-start">10</property>
<property name="label">Font</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkFontButton" id="font_button">
<layout>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Hinting</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
<layout>
<property name="left-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="hinting">
<property name="active">0</property>
<property name="valign">center</property>
<items>
<item translatable="yes" id="none">None</item>
<item translatable="yes" id="slight">Slight</item>
<item translatable="yes" id="medium">Medium</item>
<item translatable="yes" id="full">Full</item>
</items>
<layout>
<property name="left-attach">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="hint_metrics">
<child>
<object class="GtkLabel">
<property name="label">Hint Metrics</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<layout>
<property name="left-attach">3</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="show_extents">
<property name="active">1</property>
<child>
<object class="GtkLabel">
<property name="label">Show Extents</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<layout>
<property name="left-attach">4</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="show_grid">
<property name="active">1</property>
<child>
<object class="GtkLabel">
<property name="label">Show Grid</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<layout>
<property name="left-attach">4</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton" id="up_button">
<property name="icon-name">list-add-symbolic</property>
<style>
<class name="circular"/>
</style>
<layout>
<property name="left-attach">5</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton" id="down_button">
<property name="icon-name">list-remove-symbolic</property>
<style>
<class name="circular"/>
</style>
<layout>
<property name="left-attach">5</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="hexpand">1</property>
<layout>
<property name="left-attach">6</property>
</layout>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="halign">center</property>
<property name="valign">center</property>
<style><class name="linked"/></style>
<child>
<object class="GtkRadioButton" id="text_radio">
<property name="draw-indicator">0</property>
<property name="label">Text</property>
</object>
</child>
<child>
<object class="GtkRadioButton" id="grid_radio">
<property name="draw-indicator">0</property>
<property name="label">Grid</property>
<property name="group">text_radio</property>
</object>
</child>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
<property name="column-span">7</property>
</layout>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="propagate-natural-height">1</property>
<property name="shadow-type">in</property>
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<child>
<object class="GtkPicture" id="image">
<property name="halign">center</property>
<property name="valign">center</property>
<property name="can-shrink">0</property>
</object>
</child>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">4</property>
<property name="column-span">7</property>
</layout>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -829,6 +829,7 @@ draw_spinbutton (GtkWidget *widget,
GtkStyleContext *down_context;
GtkIconTheme *icon_theme;
GtkIconInfo *icon_info;
GdkPixbuf *pixbuf;
GdkTexture *texture;
gint icon_width, icon_height, icon_size;
gint button_width;
@@ -856,22 +857,26 @@ draw_spinbutton (GtkWidget *widget,
"min-width", &icon_width, "min-height", &icon_height, NULL);
icon_size = MIN (icon_width, icon_height);
icon_info = gtk_icon_theme_lookup_icon (icon_theme, "list-add-symbolic", icon_size, 0);
texture = GDK_TEXTURE (gtk_icon_info_load_symbolic_for_context (icon_info, up_context, NULL, NULL));
pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, up_context, NULL, NULL);
texture = gdk_texture_new_for_pixbuf (pixbuf);
g_object_unref (icon_info);
draw_style_common (up_context, cr, x + width - button_width, y, button_width, *height,
&contents_x, &contents_y, &contents_width, &contents_height);
gtk_render_icon (up_context, cr, texture, contents_x, contents_y + (contents_height - icon_size) / 2);
g_object_unref (pixbuf);
g_object_unref (texture);
gtk_style_context_get (down_context,
"min-width", &icon_width, "min-height", &icon_height, NULL);
icon_size = MIN (icon_width, icon_height);
icon_info = gtk_icon_theme_lookup_icon (icon_theme, "list-remove-symbolic", icon_size, 0);
texture = GDK_TEXTURE (gtk_icon_info_load_symbolic_for_context (icon_info, down_context, NULL, NULL));
pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, down_context, NULL, NULL);
texture = gdk_texture_new_for_pixbuf (pixbuf);
g_object_unref (icon_info);
draw_style_common (down_context, cr, x + width - 2 * button_width, y, button_width, *height,
&contents_x, &contents_y, &contents_width, &contents_height);
gtk_render_icon (down_context, cr, texture, contents_x, contents_y + (contents_height - icon_size) / 2);
g_object_unref (pixbuf);
g_object_unref (texture);
g_object_unref (down_context);

View File

@@ -13,16 +13,17 @@ in_files = sys.argv[2:]
file_output = """
typedef GtkWidget *(*GDoDemoFunc) (GtkWidget *do_widget);
typedef struct _DemoData DemoData;
typedef struct _Demo Demo;
struct _DemoData
struct _Demo
{
char *name;
char *title;
char *filename;
gchar *name;
gchar *title;
gchar *filename;
GDoDemoFunc func;
DemoData *children;
Demo *children;
};
"""
# Demo = namedtuple('Demo', ['name', 'title', 'file', 'func'])
@@ -66,7 +67,7 @@ for demo in demos:
i = 0
for parent in parents:
id = parent_ids[i]
file_output += "\nDemoData child" + str(id) + "[] = {\n"
file_output += "\nDemo child" + str(id) + "[] = {\n"
# iterate over all demos and check if the name starts with the given parent name
for child in demos:
if child[1].startswith(parent + "/"):
@@ -81,7 +82,7 @@ for parent in parents:
# Sort demos by title
demos = sorted(demos, key=lambda x: x[1])
file_output += "\nDemoData gtk_demos[] = {\n"
file_output += "\nDemo gtk_demos[] = {\n"
for demo in demos:
# Do not generate one of these for demos with a parent demo
if "/" not in demo[1]:

View File

@@ -241,7 +241,7 @@ realize (GtkWidget *widget)
fragment_path = "/glarea/glarea-gl.fs.glsl";
}
init_buffers (NULL, &position_buffer);
init_buffers (&position_buffer, NULL);
init_shaders (vertex_path, fragment_path, &program, &mvp_location);
}

View File

@@ -53,6 +53,7 @@ enum {
PROP_BENCHMARK,
PROP_COUNT,
PROP_FRAMERATE,
PROP_FRAMERATE_STRING,
PROP_UPDATE_DELAY,
NUM_PROPERTIES
};
@@ -288,6 +289,14 @@ gtk_fishbowl_get_property (GObject *object,
g_value_set_double (value, gtk_fishbowl_get_framerate (fishbowl));
break;
case PROP_FRAMERATE_STRING:
{
char *s = g_strdup_printf ("%.2f", gtk_fishbowl_get_framerate (fishbowl));
g_value_set_string (value, s);
g_free (s);
}
break;
case PROP_UPDATE_DELAY:
g_value_set_int64 (value, gtk_fishbowl_get_update_delay (fishbowl));
break;
@@ -341,6 +350,13 @@ gtk_fishbowl_class_init (GtkFishbowlClass *klass)
0,
G_PARAM_READABLE);
props[PROP_FRAMERATE_STRING] =
g_param_spec_string ("framerate-string",
"Framerate as string",
"Framerate as string, with 2 decimals",
NULL,
G_PARAM_READABLE);
props[PROP_UPDATE_DELAY] =
g_param_spec_int64 ("update-delay",
"Update delay",
@@ -492,6 +508,7 @@ gtk_fishbowl_do_update (GtkFishbowl *fishbowl)
priv->framerate = ((int)(priv->framerate * 100))/100.0;
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_FRAMERATE]);
g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_FRAMERATE_STRING]);
if (!priv->benchmark)
return;

View File

@@ -41,7 +41,6 @@ show_page (GtkTextBuffer *buffer,
gtk_text_buffer_set_text (buffer, "", 0);
gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
gtk_text_buffer_begin_irreversible_action (buffer);
if (page == 1)
{
gtk_text_buffer_insert (buffer, &iter, "Some text to show that simple ", -1);
@@ -74,7 +73,6 @@ show_page (GtkTextBuffer *buffer,
"so that related items of information are connected.\n", -1);
insert_link (buffer, &iter, "Go back", 1);
}
gtk_text_buffer_end_irreversible_action (buffer);
}
/* Looks at all tags covering the position of iter in the text view,
@@ -260,7 +258,6 @@ do_hypertext (GtkWidget *do_widget)
gtk_widget_add_controller (view, controller);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
gtk_text_buffer_set_enable_undo (buffer, TRUE);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),

View File

@@ -1,229 +0,0 @@
/* Benchmark/Scrolling
*
* This demo scrolls a view with various content.
*/
#include <gtk/gtk.h>
static guint tick_cb;
static GtkAdjustment *hadjustment;
static GtkAdjustment *vadjustment;
static GtkWidget *window = NULL;
static GtkWidget *scrolledwindow;
static int selected;
#define N_WIDGET_TYPES 4
static int hincrement = 5;
static int vincrement = 5;
static gboolean
scroll_cb (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer data)
{
double value;
value = gtk_adjustment_get_value (vadjustment);
if (value + vincrement <= gtk_adjustment_get_lower (vadjustment) ||
(value + vincrement >= gtk_adjustment_get_upper (vadjustment) - gtk_adjustment_get_page_size (vadjustment)))
vincrement = - vincrement;
gtk_adjustment_set_value (vadjustment, value + vincrement);
value = gtk_adjustment_get_value (hadjustment);
if (value + hincrement <= gtk_adjustment_get_lower (hadjustment) ||
(value + hincrement >= gtk_adjustment_get_upper (hadjustment) - gtk_adjustment_get_page_size (hadjustment)))
hincrement = - hincrement;
gtk_adjustment_set_value (hadjustment, value + hincrement);
return G_SOURCE_CONTINUE;
}
extern GtkWidget *create_icon (void);
static void
populate_icons (void)
{
GtkWidget *grid;
int top, left;
grid = gtk_grid_new ();
gtk_widget_set_halign (grid, GTK_ALIGN_CENTER);
g_object_set (grid, "margin", 10, NULL);
gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
gtk_grid_set_column_spacing (GTK_GRID (grid), 10);
for (top = 0; top < 100; top++)
for (left = 0; left < 15; left++)
gtk_grid_attach (GTK_GRID (grid), create_icon (), left, top, 1, 1);
hincrement = 0;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (scrolledwindow), grid);
}
static char *content;
static gsize content_len;
extern void fontify (GtkTextBuffer *buffer);
static void
populate_text (gboolean hilight)
{
GtkWidget *textview;
GtkTextBuffer *buffer;
if (!content)
{
GBytes *bytes;
bytes = g_resources_lookup_data ("/sources/font_features.c", 0, NULL);
content = g_bytes_unref_to_data (bytes, &content_len);
}
buffer = gtk_text_buffer_new (NULL);
gtk_text_buffer_set_text (buffer, content, (int)content_len);
if (hilight)
fontify (buffer);
textview = gtk_text_view_new ();
gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview), buffer);
hincrement = 0;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (scrolledwindow), textview);
}
static void
populate_image (void)
{
GtkWidget *image;
if (!content)
{
GBytes *bytes;
bytes = g_resources_lookup_data ("/sources/font_features.c", 0, NULL);
content = g_bytes_unref_to_data (bytes, &content_len);
}
image = gtk_picture_new_for_resource ("/sliding_puzzle/portland-rose.jpg");
gtk_picture_set_can_shrink (GTK_PICTURE (image), FALSE);
hincrement = 5;
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (scrolledwindow), image);
}
static void
set_widget_type (int type)
{
if (tick_cb)
gtk_widget_remove_tick_callback (window, tick_cb);
if (gtk_bin_get_child (GTK_BIN (scrolledwindow)))
gtk_container_remove (GTK_CONTAINER (scrolledwindow),
gtk_bin_get_child (GTK_BIN (scrolledwindow)));
selected = type;
switch (selected)
{
case 0:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling icons");
populate_icons ();
break;
case 1:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling plain text");
populate_text (FALSE);
break;
case 2:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling complex text");
populate_text (TRUE);
break;
case 3:
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a big image");
populate_image ();
break;
default:
g_assert_not_reached ();
}
tick_cb = gtk_widget_add_tick_callback (window, scroll_cb, NULL, NULL);
}
void
iconscroll_next_clicked_cb (GtkButton *source,
gpointer user_data)
{
int new_index;
if (selected + 1 >= N_WIDGET_TYPES)
new_index = 0;
else
new_index = selected + 1;
set_widget_type (new_index);
}
void
iconscroll_prev_clicked_cb (GtkButton *source,
gpointer user_data)
{
int new_index;
if (selected - 1 < 0)
new_index = N_WIDGET_TYPES - 1;
else
new_index = selected - 1;
set_widget_type (new_index);
}
GtkWidget *
do_iconscroll (GtkWidget *do_widget)
{
if (!window)
{
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/iconscroll/iconscroll.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
scrolledwindow = GTK_WIDGET (gtk_builder_get_object (builder, "scrolledwindow"));
gtk_widget_realize (window);
hadjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "hadjustment"));
vadjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "vadjustment"));
set_widget_type (0);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window">
<property name="resizable">0</property>
<property name="default-width">500</property>
<property name="default-height">500</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkBox">
<style>
<class name="linked"/>
</style>
<child>
<object class="GtkButton">
<property name="icon-name">pan-start-symbolic</property>
<signal name="clicked" handler="iconscroll_prev_clicked_cb"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="icon-name">pan-end-symbolic</property>
<signal name="clicked" handler="iconscroll_next_clicked_cb"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow">
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<property name="hadjustment"><object class="GtkAdjustment" id="hadjustment"/></property>
<property name="vadjustment"><object class="GtkAdjustment" id="vadjustment"/></property>
</object>
</child>
</object>
</interface>

View File

@@ -68,7 +68,7 @@ do_infobar (GtkWidget *do_widget)
gtk_container_add (GTK_CONTAINER (vbox), bar);
gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_INFO);
label = gtk_label_new ("This is an info bar with message type GTK_MESSAGE_INFO");
gtk_label_set_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label);
@@ -80,7 +80,7 @@ do_infobar (GtkWidget *do_widget)
gtk_container_add (GTK_CONTAINER (vbox), bar);
gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_WARNING);
label = gtk_label_new ("This is an info bar with message type GTK_MESSAGE_WARNING");
gtk_label_set_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label);
@@ -94,7 +94,7 @@ do_infobar (GtkWidget *do_widget)
gtk_container_add (GTK_CONTAINER (vbox), bar);
gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_QUESTION);
label = gtk_label_new ("This is an info bar with message type GTK_MESSAGE_QUESTION");
gtk_label_set_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label);
@@ -106,7 +106,7 @@ do_infobar (GtkWidget *do_widget)
gtk_container_add (GTK_CONTAINER (vbox), bar);
gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_ERROR);
label = gtk_label_new ("This is an info bar with message type GTK_MESSAGE_ERROR");
gtk_label_set_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label);
@@ -119,7 +119,7 @@ do_infobar (GtkWidget *do_widget)
gtk_container_add (GTK_CONTAINER (vbox), bar);
gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_OTHER);
label = gtk_label_new ("This is an info bar with message type GTK_MESSAGE_OTHER");
gtk_label_set_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label);

View File

@@ -18,10 +18,6 @@
#include "language-names.h"
#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"
@@ -206,7 +202,7 @@ languages_variant_init (const char *variant)
else
g_warning ("Failed to load '%s': %s\n", filename, error->message);
g_clear_error (&error);
g_free (error);
g_free (filename);
g_free (buf);
}

View File

@@ -8,7 +8,6 @@
#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
#include "award.h"
static GdkPixbuf *avatar_pixbuf_other;
static GtkWidget *window = NULL;
@@ -235,9 +234,9 @@ reshare_clicked (GtkMessageRow *row,
{
GtkMessageRowPrivate *priv = row->priv;
award ("listbox-reshare");
priv->message->n_reshares++;
gtk_message_row_update (row);
}
static void
@@ -256,14 +255,11 @@ gtk_message_row_state_flags_changed (GtkWidget *widget,
{
GtkMessageRowPrivate *priv = GTK_MESSAGE_ROW (widget)->priv;
GtkStateFlags flags;
gboolean visible;
flags = gtk_widget_get_state_flags (widget);
visible = flags & (GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_SELECTED) ? TRUE : FALSE;
gtk_widget_set_visible (priv->extra_buttons_box, visible);
if (visible && gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (widget)) % 100 == 99)
award ("listbox-100th-row");
gtk_widget_set_visible (priv->extra_buttons_box,
flags & (GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_SELECTED));
GTK_WIDGET_CLASS (gtk_message_row_parent_class)->state_flags_changed (widget, previous_state_flags);
}

View File

@@ -1,199 +0,0 @@
/* Lists/Application launcher
*
* This demo uses the GtkCoverFlow widget as a fancy application launcher.
*
* It is also a very small introduction to listviews.
*/
#include <gtk/gtk.h>
/* This is the function that creates the #GListModel that we need.
* GTK list widgets need a #GListModel to display, as it support change
* notifications, but various older APIs do not support one.
*/
static GListModel *
create_application_list (void)
{
GListStore *store;
GList *apps, *l;
/* We use a #GListStore here, which is a simple array-like list implementation
* for manual management.
* List models need to know what type of data they provide, so we need to
* provide the type here. As we want to do a list of applications, #GAppInfo
* is the object we provide.
*/
store = g_list_store_new (G_TYPE_APP_INFO);
apps = g_app_info_get_all ();
for (l = apps; l; l = l->next)
{
g_list_store_append (store, l->data);
}
g_list_free_full (apps, g_object_unref);
return G_LIST_MODEL (store);
}
/* This is the function we use for setting up new listitems to display.
* We add just a #GtkImage here to display the application's icon as this is just
* a simple demo.
*/
static void
setup_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *image;
image = gtk_image_new ();
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
gtk_list_item_set_child (list_item, image);
}
/* Here we need to prepare the listitem for displaying its item. We get the
* listitem already set up from the previous function, so we can reuse the
* #GtkImage widget we set up above.
* We get the item - which we know is a #GAppInfo because it comes out of
* the model we set up above, grab its icon and display it.
*/
static void
bind_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *image;
GAppInfo *app_info;
image = gtk_list_item_get_child (list_item);
app_info = gtk_list_item_get_item (list_item);
gtk_image_set_from_gicon (GTK_IMAGE (image), g_app_info_get_icon (app_info));
}
/* In more complex code, we would also need functions to unbind and teardown
* the listitem, but this is simple code, so the default implemntations are
* enough. If we had connected signals, this step would have been necessary.
*
* The #GtkSignalListItemFactory documentation contains more information about
* this step.
*/
/* This function is called whenever an item in the list is activated. This is
* the simple way to allow reacting to the Enter key or double-clicking on a
* listitem.
* Of course, it is possible to use far more complex interactions by turning
* off activation and adding buttons or other widgets in the setup function
* above, but this is a simple demo, so we'll use the simple way.
*/
static void
activate_cb (GtkCoverFlow *coverflow,
guint position,
gpointer unused)
{
GAppInfo *app_info;
GdkAppLaunchContext *context;
GError *error = NULL;
app_info = g_list_model_get_item (gtk_cover_flow_get_model (coverflow), position);
/* Prepare the context for launching the application and launch it. This
* code is explained in detail in the documentation for #GdkAppLaunchContext
* and #GAppInfo.
*/
context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (coverflow)));
if (!g_app_info_launch (app_info,
NULL,
G_APP_LAUNCH_CONTEXT (context),
&error))
{
GtkWidget *dialog;
/* And because error handling is important, even a simple demo has it:
* We display an error dialog that something went wrong.
*/
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (coverflow))),
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Could not launch %s", g_app_info_get_display_name (app_info));
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
g_clear_error (&error);
gtk_widget_show (dialog);
}
g_object_unref (context);
g_object_unref (app_info);
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_applauncher (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *coverflow, *sw;;
GListModel *model;
GtkListItemFactory *factory;
/* Create a window and set a few defaults */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 640, 320);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Application Launcher");
g_signal_connect (window, "destroy",
G_CALLBACK(gtk_widget_destroyed), &window);
/* The #GtkListitemFactory is what is used to create #GtkListItems
* to display the data from the model. So it is absolutely necessary
* to create one.
* We will use a #GtkSignalListitemFactory because it is the simplest
* one to use. Different ones are available for different use cases.
* The most powerful one being the #GtkBuilderListItemFactory which
* will to everything without requiring any code and just using a
* #GtkBuilder .ui file.
*/
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind_listitem_cb), NULL);
/* Create the list widget here: We use a coverflow widgets, because it's
* the coolest one. We could just as well use other list widgets such
* as a #GtkListView or a #GtkGridView and the code would look quite
* the same.
*/
coverflow = gtk_cover_flow_new_with_factory (factory);
/* We connect the activate signal here. It's the function you remember
* from above for launching the selected application.
*/
g_signal_connect (coverflow, "activate", G_CALLBACK (activate_cb), NULL);
/* And of course we need to set the data model. Here we call the function
* we wrote above that gives us the list of applications and then we set
* it on the coverflow list widget.
* The coverflow will now take items from the model and use the factory
* to create as many listitems as it needs to show itself to the user.
*/
model = create_application_list ();
gtk_cover_flow_set_model (GTK_COVER_FLOW (coverflow), model);
g_object_unref (model);
/* List widgets should always be contained in a #GtkScrolledWindow,
* because otherwise they might get too large or they might not
* be scrollable.
*/
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), sw);
gtk_container_add (GTK_CONTAINER (sw), coverflow);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,488 +0,0 @@
/* Lists/Clocks
*
* This demo displays the time in different timezones.
*
* The goal is to show how to set up expressions that track changes
* in objects and make them update widgets.
*
* For that, we create a GtkClock object that updates its time every
* second and then use various ways to display that time.
*
* Typically, this will be done using GtkBuilder .ui files with the
* help of the <binding> tag, but this demo shows the code that runs
* behind that.
*/
#include <gtk/gtk.h>
#define GTK_TYPE_CLOCK (gtk_clock_get_type ())
G_DECLARE_FINAL_TYPE (GtkClock, gtk_clock, GTK, CLOCK, GObject)
/* This is our object. It's just a timezone */
typedef struct _GtkClock GtkClock;
struct _GtkClock
{
GObject parent_instance;
/* We allow this to be NULL for the local timezone */
GTimeZone *timezone;
/* Name of the location we're displaying time for */
char *location;
};
enum {
PROP_0,
PROP_LOCATION,
PROP_TIME,
PROP_TIMEZONE,
N_PROPS
};
/* This function returns the current time in the clock's timezone.
* Note that this returns a new object every time, so we need to
* remember to unref it after use. */
static GDateTime *
gtk_clock_get_time (GtkClock *clock)
{
if (clock->timezone)
return g_date_time_new_now (clock->timezone);
else
return g_date_time_new_now_local ();
}
/* Here, we implement the functionality required by the GdkPaintable interface.
* This way we have a trivial way to display an analog clock.
* It also allows demonstrating how to directly use objects in the listview
* later by making this object do something interesting. */
static void
gtk_clock_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GtkClock *self = GTK_CLOCK (paintable);
GDateTime *time;
GskRoundedRect outline;
#define BLACK ((GdkRGBA) { 0, 0, 0, 1 })
/* save/restore() is necessary so we can undo the transforms we start
* out with. */
gtk_snapshot_save (snapshot);
/* First, we move the (0, 0) point to the center of the area so
* we can draw everything relative to it. */
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width / 2, height / 2));
/* Next we scale it, so that we can pretend that the clock is
* 100px in size. That way, we don't need to do any complicated
* math later.
* We use MIN() here so that we use the smaller dimension for sizing.
* That way we don't overdraw but keep the aspect ratio. */
gtk_snapshot_scale (snapshot, MIN (width, height) / 100.0, MIN (width, height) / 100.0);
/* Now we have a circle with diameter 100px (and radius 50px) that
* has its (0, 0) point at the center.
* Let's draw a simple clock into it. */
time = gtk_clock_get_time (self);
/* First, draw a circle. This is a neat little trick to draw a circle
* without requiring Cairo. */
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-50, -50, 100, 100), 50);
gtk_snapshot_append_border (snapshot,
&outline,
(float[4]) { 4, 4, 4, 4 },
(GdkRGBA [4]) { BLACK, BLACK, BLACK, BLACK });
/* Next, draw the hour hand.
* We do this using tranforms again: Instead of computing where the angle points
* to, we just rotate everything and then draw the hand as if if was :00.
* We don't even need to care about am/pm here because rotations just work. */
gtk_snapshot_save (snapshot);
gtk_snapshot_rotate (snapshot, 30 * g_date_time_get_hour (time) + 0.5 * g_date_time_get_minute (time));
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-2, -23, 4, 25), 2);
gtk_snapshot_push_rounded_clip (snapshot, &outline);
gtk_snapshot_append_color (snapshot, &BLACK, &outline.bounds);
gtk_snapshot_pop (snapshot);
gtk_snapshot_restore (snapshot);
/* And the same as above for the minute hand. Just make this one longer
* so people can tell the hands apart. */
gtk_snapshot_save (snapshot);
gtk_snapshot_rotate (snapshot, 6 * g_date_time_get_minute (time));
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-2, -43, 4, 45), 2);
gtk_snapshot_push_rounded_clip (snapshot, &outline);
gtk_snapshot_append_color (snapshot, &BLACK, &outline.bounds);
gtk_snapshot_pop (snapshot);
gtk_snapshot_restore (snapshot);
/* and finally, the second indicator. */
gtk_snapshot_save (snapshot);
gtk_snapshot_rotate (snapshot, 6 * g_date_time_get_second (time));
gsk_rounded_rect_init_from_rect (&outline, &GRAPHENE_RECT_INIT(-2, -43, 4, 10), 2);
gtk_snapshot_push_rounded_clip (snapshot, &outline);
gtk_snapshot_append_color (snapshot, &BLACK, &outline.bounds);
gtk_snapshot_pop (snapshot);
gtk_snapshot_restore (snapshot);
/* And finally, don't forget to restore the initial save() that we did for
* the initial transformations. */
gtk_snapshot_restore (snapshot);
g_date_time_unref (time);
}
/* Our desired size is 100px. That sounds okay for an analog clock */
static int
gtk_clock_get_intrinsic_width (GdkPaintable *paintable)
{
return 100;
}
static int
gtk_clock_get_intrinsic_height (GdkPaintable *paintable)
{
return 100;
}
/* Initialize the paintable interface. This way we turn our clock objects
* into objects that can be drawn.
* There are more functions to this interface to define desired size,
* but this is enough.
*/
static void
gtk_clock_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = gtk_clock_snapshot;
iface->get_intrinsic_width = gtk_clock_get_intrinsic_width;
iface->get_intrinsic_height = gtk_clock_get_intrinsic_height;
}
/* Finally, we define the type. The important part is adding the paintable
* interface, so GTK knows that this object can indeed be drawm.
*/
G_DEFINE_TYPE_WITH_CODE (GtkClock, gtk_clock, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_clock_paintable_init))
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
gtk_clock_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkClock *self = GTK_CLOCK (object);
switch (property_id)
{
case PROP_LOCATION:
g_value_set_string (value, self->location);
break;
case PROP_TIME:
g_value_take_boxed (value, gtk_clock_get_time (self));
break;
case PROP_TIMEZONE:
g_value_set_boxed (value, self->timezone);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gtk_clock_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GtkClock *self = GTK_CLOCK (object);
switch (property_id)
{
case PROP_LOCATION:
self->location = g_value_dup_string (value);
break;
case PROP_TIMEZONE:
self->timezone = g_value_dup_boxed (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/* This is the list of all the ticking clocks */
static GSList *ticking_clocks = NULL;
/* This is the id of the timeout source that is updating all ticking clocks */
static guint ticking_clock_id = 0;
/* Every second, this function is called to tell everybody that the
* clocks are ticking.
*/
static gboolean
gtk_clock_tick (gpointer unused)
{
GSList *l;
for (l = ticking_clocks; l; l = l->next)
{
GtkClock *clock = l->data;
/* We will now return a different value for the time porperty,
* so notify about that.
*/
g_object_notify_by_pspec (G_OBJECT (clock), properties[PROP_TIME]);
/* We will also draw the hands of the clock differently.
* So notify about that, too.
*/
gdk_paintable_invalidate_contents (GDK_PAINTABLE (clock));
}
return G_SOURCE_CONTINUE;
}
static void
gtk_clock_stop_ticking (GtkClock *self)
{
ticking_clocks = g_slist_remove (ticking_clocks, self);
/* If no clock is remaining, stop running the tick updates */
if (ticking_clocks == NULL && ticking_clock_id != 0)
g_clear_handle_id (&ticking_clock_id, g_source_remove);
}
static void
gtk_clock_start_ticking (GtkClock *self)
{
/* if no clock is ticking yet, start */
if (ticking_clock_id == 0)
ticking_clock_id = g_timeout_add_seconds (1, gtk_clock_tick, NULL);
ticking_clocks = g_slist_prepend (ticking_clocks, self);
}
static void
gtk_clock_finalize (GObject *object)
{
GtkClock *self = GTK_CLOCK (object);
gtk_clock_stop_ticking (self);
g_free (self->location);
g_clear_pointer (&self->timezone, g_time_zone_unref);
G_OBJECT_CLASS (gtk_clock_parent_class)->finalize (object);
}
static void
gtk_clock_class_init (GtkClockClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gtk_clock_get_property;
gobject_class->set_property = gtk_clock_set_property;
gobject_class->finalize = gtk_clock_finalize;
properties[PROP_LOCATION] =
g_param_spec_string ("location", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_TIME] =
g_param_spec_boxed ("time", NULL, NULL, G_TYPE_DATE_TIME, G_PARAM_READABLE);
properties[PROP_TIMEZONE] =
g_param_spec_boxed ("timezone", NULL, NULL, G_TYPE_TIME_ZONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gtk_clock_init (GtkClock *self)
{
gtk_clock_start_ticking (self);
}
static GtkClock *
gtk_clock_new (const char *location,
GTimeZone *timezone)
{
GtkClock *result;
result = g_object_new (GTK_TYPE_CLOCK,
"location", location,
"timezone", timezone,
NULL);
g_clear_pointer (&timezone, g_time_zone_unref);
return result;
}
static GListModel *
create_clocks_model (void)
{
GListStore *result;
GtkClock *clock;
result = g_list_store_new (GTK_TYPE_CLOCK);
/* local time */
clock = gtk_clock_new ("local", NULL);
g_list_store_append (result, clock);
g_object_unref (clock);
/* UTC time */
clock = gtk_clock_new ("UTC", g_time_zone_new_utc ());
g_list_store_append (result, clock);
g_object_unref (clock);
/* A bunch of timezones with GTK hackers */
clock = gtk_clock_new ("San Francisco", g_time_zone_new ("America/Los_Angeles"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Boston", g_time_zone_new ("America/New_York"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("London", g_time_zone_new ("Europe/London"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Berlin", g_time_zone_new ("Europe/Berlin"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Moscow", g_time_zone_new ("Europe/Moscow"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("New Delhi", g_time_zone_new ("Asia/Kolkata"));
g_list_store_append (result, clock);
g_object_unref (clock);
clock = gtk_clock_new ("Shanghai", g_time_zone_new ("Asia/Shanghai"));
g_list_store_append (result, clock);
g_object_unref (clock);
return G_LIST_MODEL (result);
}
static char *
convert_time_to_string (GObject *image,
GDateTime *time,
gpointer unused)
{
return g_date_time_format (time, "%x\n%X");
}
/* And this function is the crux for this whole demo.
* It shows how to use expressions to set up bindings.
*/
static void
setup_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *box, *picture, *location_label, *time_label;
GtkExpression *clock_expression, *expression;
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_list_item_set_child (list_item, box);
/* First, we create an expression that gets us the clock from the listitem:
* 1. Create an expression that gets the list item.
* 2. Use that expression's "item" property to get the clock
*/
expression = gtk_constant_expression_new (GTK_TYPE_LIST_ITEM, list_item);
clock_expression = gtk_property_expression_new (GTK_TYPE_LIST_ITEM, expression, "item");
/* Bind the clock's location to a label.
* This is easy: We just get the "location" property of the clock.
*/
expression = gtk_property_expression_new (GTK_TYPE_CLOCK,
gtk_expression_ref (clock_expression),
"location");
/* Now create the label and bind the expression to it. */
location_label = gtk_label_new (NULL);
gtk_expression_bind (expression, location_label, location_label, "label");
gtk_container_add (GTK_CONTAINER (box), location_label);
/* Here we bind the item itself to a GdkPicture.
* This is simply done by using the clock expression itself.
*/
expression = gtk_expression_ref (clock_expression);
/* Now create the widget and bind the expression to it. */
picture = gtk_picture_new ();
gtk_expression_bind (expression, picture, picture, "paintable");
gtk_container_add (GTK_CONTAINER (box), picture);
/* And finally, everything comes together.
* We create a label for displaying the time as text.
* For that, we need to transform the "GDateTime" of the
* time property into a string so that the label can display it.
*/
expression = gtk_property_expression_new (GTK_TYPE_CLOCK,
gtk_expression_ref (clock_expression),
"time");
expression = gtk_cclosure_expression_new (G_TYPE_STRING,
NULL,
1, (GtkExpression *[1]) { expression },
G_CALLBACK (convert_time_to_string),
NULL, NULL);
/* Now create the label and bind the expression to it. */
time_label = gtk_label_new (NULL);
gtk_expression_bind (expression, time_label, time_label, "label");
gtk_container_add (GTK_CONTAINER (box), time_label);
gtk_expression_unref (clock_expression);
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_clocks (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *gridview, *sw;
GtkListItemFactory *factory;
GListModel *model;
GtkNoSelection *selection;
/* This is the normal window setup code every demo does */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
/* List widgets go into a scrolled window. Always. */
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), sw);
/* Create the factory that creates the listitems. Because we
* used bindings above during setup, we only need to connect
* to the setup signal.
* The bindings take care of the bind step.
*/
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
gridview = gtk_grid_view_new_with_factory (factory);
gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
gtk_scrollable_set_vscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
model = create_clocks_model ();
selection = gtk_no_selection_new (model);
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), G_LIST_MODEL (selection));
gtk_container_add (GTK_CONTAINER (sw), gridview);
g_object_unref (selection);
g_object_unref (model);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,255 +0,0 @@
/* Lists/File browser
*
* This demo shows off the different layouts that are quickly achievable
* with GtkGridView by implementing a file browser with different views.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
static GtkWidget *window = NULL;
/* Create a simple object that holds the data for the different views */
typedef struct _FileBrowserView FileBrowserView;
struct _FileBrowserView
{
GObject parent_instance;
GtkListItemFactory *factory;
char *icon_name;
GtkOrientation orientation;
};
enum {
PROP_0,
PROP_FACTORY,
PROP_ICON_NAME,
PROP_ORIENTATION,
N_PROPS
};
#define FILE_BROWSER_TYPE_VIEW (file_browser_view_get_type ())
G_DECLARE_FINAL_TYPE (FileBrowserView, file_browser_view, FILE_BROWSER, VIEW, GObject);
G_DEFINE_TYPE (FileBrowserView, file_browser_view, G_TYPE_OBJECT);
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
file_browser_view_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
FileBrowserView *self = FILE_BROWSER_VIEW (object);
switch (property_id)
{
case PROP_FACTORY:
g_value_set_object (value, self->factory);
break;
case PROP_ICON_NAME:
g_value_set_string (value, self->icon_name);
break;
case PROP_ORIENTATION:
g_value_set_enum (value, self->orientation);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
file_browser_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
FileBrowserView *self = FILE_BROWSER_VIEW (object);
switch (prop_id)
{
case PROP_FACTORY:
g_set_object (&self->factory, g_value_get_object (value));
break;
case PROP_ICON_NAME:
g_free (self->icon_name);
self->icon_name = g_value_dup_string (value);
break;
case PROP_ORIENTATION:
self->orientation = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
file_browser_view_finalize (GObject *object)
{
FileBrowserView *self = FILE_BROWSER_VIEW (object);
g_object_unref (self->factory);
g_free (self->icon_name);
G_OBJECT_CLASS (file_browser_view_parent_class)->dispose (object);
}
static void
file_browser_view_class_init (FileBrowserViewClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = file_browser_view_get_property;
gobject_class->set_property = file_browser_view_set_property;
gobject_class->finalize = file_browser_view_finalize;
properties[PROP_FACTORY] =
g_param_spec_object ("factory",
"factory",
"factory to use in the main view",
GTK_TYPE_LIST_ITEM_FACTORY,
G_PARAM_READWRITE);
properties[PROP_ICON_NAME] =
g_param_spec_string ("icon-name",
"icon name",
"icon to display for selecting this view",
NULL,
G_PARAM_READWRITE);
properties[PROP_ORIENTATION] =
g_param_spec_enum ("orientation",
"orientation",
"orientation of the view",
GTK_TYPE_ORIENTATION,
GTK_ORIENTATION_VERTICAL,
G_PARAM_READWRITE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void file_browser_view_init (FileBrowserView *self)
{
}
char *
filebrowser_get_display_name (GObject *object,
GFileInfo *info)
{
if (!info)
return NULL;
return g_strdup (g_file_info_get_attribute_string (info, "standard::display-name"));
}
char *
filebrowser_get_content_type (GObject *object,
GFileInfo *info)
{
if (!info)
return NULL;
return g_strdup (g_file_info_get_attribute_string (info, "standard::content-type"));
}
char *
filebrowser_get_size (GObject *object,
GFileInfo *info)
{
if (!info)
return NULL;
return g_format_size (g_file_info_get_attribute_uint64 (info, "standard::size"));
}
GIcon *
filebrowser_get_icon (GObject *object,
GFileInfo *info)
{
GIcon *icon;
if (info)
icon = G_ICON (g_file_info_get_attribute_object (info, "standard::icon"));
else
icon = NULL;
if (icon)
g_object_ref (icon);
return icon;
}
void
filebrowser_up_clicked_cb (GtkButton *button,
GtkDirectoryList *list)
{
GFile *file;
file = g_file_get_parent (gtk_directory_list_get_file (list));
if (file == NULL)
return;
gtk_directory_list_set_file (list, file);
}
void
filebrowser_view_activated_cb (GtkGridView *view,
guint pos,
GtkDirectoryList *list)
{
GFileInfo *info;
info = g_list_model_get_item (gtk_grid_view_get_model (view), pos);
if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
gtk_directory_list_set_file (list, G_FILE (g_file_info_get_attribute_object (info, "standard::file")));
g_object_unref (info);
}
GtkWidget *
do_listview_filebrowser (GtkWidget *do_widget)
{
if (!window)
{
GtkWidget *view;
GtkBuilder *builder;
GtkDirectoryList *dirlist;
GFile *file;
char *cwd;
builder = gtk_builder_new_from_resource ("/listview_filebrowser/listview_filebrowser.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
/* Create the model and fill it with the contents of the current directory */
cwd = g_get_current_dir ();
file = g_file_new_for_path (cwd);
g_free (cwd);
dirlist = GTK_DIRECTORY_LIST (gtk_builder_get_object (builder, "dirlist"));
gtk_directory_list_set_file (dirlist, file);
g_object_unref (file);
/* grab focus in the view */
view = GTK_WIDGET (gtk_builder_get_object (builder, "view"));
gtk_widget_grab_focus (view);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,240 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GListStore" id="viewlist">
<property name="item-type">FileBrowserView</property>
<child>
<object class="FileBrowserView">
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkBox">
<child>
<object class="GtkImage">
<binding name="gicon">
<closure type="GIcon" function="filebrowser_get_icon">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_display_name">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
<property name="icon-name">view-list-symbolic</property>
<property name="orientation">horizontal</property>
</object>
</child>
<child>
<object class="FileBrowserView">
<property name="icon-name">view-grid-symbolic</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkImage">
<property name="icon-size">large</property>
<binding name="gicon">
<closure type="GIcon" function="filebrowser_get_icon">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="wrap">1</property>
<property name="wrap-mode">word-char</property>
<property name="lines">2</property>
<property name="ellipsize">end</property>
<property name="width-chars">10</property>
<property name="max-width-chars">30</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_display_name">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
<property name="orientation">vertical</property>
</object>
</child>
<child>
<object class="FileBrowserView">
<property name="icon-name">view-paged-symbolic</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkBox">
<child>
<object class="GtkImage">
<property name="icon-size">large</property>
<binding name="gicon">
<closure type="GIcon" function="filebrowser_get_icon">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_display_name">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_size">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<closure type="gchararray" function="filebrowser_get_content_type">
<lookup name="item">GtkListItem</lookup>
</closure>
</binding>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
</object>
</child>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
<property name="orientation">horizontal</property>
</object>
</child>
</object>
<object class="GtkDirectoryList" id="dirlist">
<property name="attributes">standard::name,standard::display-name,standard::icon,standard::size,standard::content-type</property>
</object>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">File browser</property>
<property name="default-width">600</property>
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton">
<property name="icon-name">go-up</property>
<signal name="clicked" handler="filebrowser_up_clicked_cb" object="dirlist" swapped="no"/>
</object>
</child>
<child type="end">
<object class="GtkListView">
<property name="valign">center</property>
<property name="orientation">horizontal</property>
<style>
<class name="linked"/>
</style>
<property name="model">
<object class="GtkSingleSelection" id="selected-view">
<property name="model">viewlist</property>
</object>
</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkImage">
<binding name="icon-name">
<lookup type="FileBrowserView" name="icon-name">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="can-focus">1</property>
<child>
<object class="GtkGridView" id="view">
<property name="model">dirlist</property>
<property name="max-columns">15</property>
<binding name="factory">
<lookup name="factory" type="FileBrowserView">
<lookup name="selected-item">selected-view</lookup>
</lookup>
</binding>
<binding name="orientation">
<lookup name="orientation" type="FileBrowserView">
<lookup name="selected-item">selected-view</lookup>
</lookup>
</binding>
<signal name="activate" handler="filebrowser_view_activated_cb" object="dirlist" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -1,473 +0,0 @@
/* Lists/Minesweeper
*
* This demo shows how to develop a user interface for small game using a
* gridview.
*
* It demonstrates how to use the activate signal and single-press behavior
* to implement rather different interaction behavior to a typical list.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
/*** The cell object ***/
/* Create an object that holds the data for a cell in the game */
typedef struct _SweeperCell SweeperCell;
struct _SweeperCell
{
GObject parent_instance;
gboolean is_mine;
gboolean is_visible;
guint neighbor_mines;
};
enum {
CELL_PROP_0,
CELL_PROP_LABEL,
N_CELL_PROPS
};
#define SWEEPER_TYPE_CELL (sweeper_cell_get_type ())
G_DECLARE_FINAL_TYPE (SweeperCell, sweeper_cell, SWEEPER, CELL, GObject);
G_DEFINE_TYPE (SweeperCell, sweeper_cell, G_TYPE_OBJECT);
static GParamSpec *cell_properties[N_CELL_PROPS] = { NULL, };
static const char *
sweeper_cell_get_label (SweeperCell *self)
{
static const char *minecount_labels[10] = { "", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
if (!self->is_visible)
return "?";
if (self->is_mine)
return "💣";
return minecount_labels[self->neighbor_mines];
}
static void
sweeper_cell_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
SweeperCell *self = SWEEPER_CELL (object);
switch (property_id)
{
case CELL_PROP_LABEL:
g_value_set_string (value, sweeper_cell_get_label (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
sweeper_cell_class_init (SweeperCellClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = sweeper_cell_get_property;
cell_properties[CELL_PROP_LABEL] =
g_param_spec_string ("label",
"label",
"label to display for this row",
NULL,
G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_CELL_PROPS, cell_properties);
}
static void
sweeper_cell_init (SweeperCell *self)
{
}
static void
sweeper_cell_reveal (SweeperCell *self)
{
if (self->is_visible)
return;
self->is_visible = TRUE;
g_object_notify_by_pspec (G_OBJECT (self), cell_properties[CELL_PROP_LABEL]);
}
static SweeperCell *
sweeper_cell_new ()
{
return g_object_new (SWEEPER_TYPE_CELL, NULL);
}
/*** The board object ***/
/* Create an object that holds the data for the game */
typedef struct _SweeperGame SweeperGame;
struct _SweeperGame
{
GObject parent_instance;
GPtrArray *cells;
guint width;
guint height;
gboolean playing;
gboolean win;
};
enum {
GAME_PROP_0,
GAME_PROP_HEIGHT,
GAME_PROP_PLAYING,
GAME_PROP_WIDTH,
GAME_PROP_WIN,
N_GAME_PROPS
};
#define SWEEPER_TYPE_GAME (sweeper_game_get_type ())
G_DECLARE_FINAL_TYPE (SweeperGame, sweeper_game, SWEEPER, GAME, GObject);
static GType
sweeper_game_list_model_get_item_type (GListModel *model)
{
return SWEEPER_TYPE_GAME;
}
static guint
sweeper_game_list_model_get_n_items (GListModel *model)
{
SweeperGame *self = SWEEPER_GAME (model);
return self->width * self->height;
}
static gpointer
sweeper_game_list_model_get_item (GListModel *model,
guint position)
{
SweeperGame *self = SWEEPER_GAME (model);
return g_object_ref (g_ptr_array_index (self->cells, position));
}
static void
sweeper_game_list_model_init (GListModelInterface *iface)
{
iface->get_item_type = sweeper_game_list_model_get_item_type;
iface->get_n_items = sweeper_game_list_model_get_n_items;
iface->get_item = sweeper_game_list_model_get_item;
}
G_DEFINE_TYPE_WITH_CODE (SweeperGame, sweeper_game, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, sweeper_game_list_model_init))
static GParamSpec *game_properties[N_GAME_PROPS] = { NULL, };
static void
sweeper_game_dispose (GObject *object)
{
SweeperGame *self = SWEEPER_GAME (object);
g_clear_pointer (&self->cells, g_ptr_array_unref);
G_OBJECT_CLASS (sweeper_game_parent_class)->dispose (object);
}
static void
sweeper_game_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
SweeperGame *self = SWEEPER_GAME (object);
switch (property_id)
{
case GAME_PROP_HEIGHT:
g_value_set_uint (value, self->height);
break;
case GAME_PROP_PLAYING:
g_value_set_boolean (value, self->playing);
break;
case GAME_PROP_WIDTH:
g_value_set_uint (value, self->width);
break;
case GAME_PROP_WIN:
g_value_set_boolean (value, self->win);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
sweeper_game_class_init (SweeperGameClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = sweeper_game_dispose;
gobject_class->get_property = sweeper_game_get_property;
game_properties[GAME_PROP_HEIGHT] =
g_param_spec_uint ("height",
"height",
"height of the game grid",
1, G_MAXUINT, 8,
G_PARAM_READABLE);
game_properties[GAME_PROP_PLAYING] =
g_param_spec_boolean ("playing",
"playing",
"if the game is still going on",
FALSE,
G_PARAM_READABLE);
game_properties[GAME_PROP_WIDTH] =
g_param_spec_uint ("width",
"width",
"width of the game grid",
1, G_MAXUINT, 8,
G_PARAM_READABLE);
game_properties[GAME_PROP_WIN] =
g_param_spec_boolean ("win",
"win",
"if the game was won",
FALSE,
G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_GAME_PROPS, game_properties);
}
static void
sweeper_game_reset_board (SweeperGame *self,
guint width,
guint height)
{
guint i;
g_ptr_array_set_size (self->cells, 0);
for (i = 0; i < width * height; i++)
{
g_ptr_array_add (self->cells, sweeper_cell_new ());
}
if (self->width != width)
{
self->width = width;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_WIDTH]);
}
if (self->height != height)
{
self->height = height;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_HEIGHT]);
}
if (!self->playing)
{
self->playing = TRUE;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_PLAYING]);
}
if (self->win)
{
self->win = FALSE;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_WIN]);
}
}
static void
sweeper_game_place_mines (SweeperGame *self,
guint n_mines)
{
guint i;
for (i = 0; i < n_mines; i++)
{
SweeperCell *cell;
do {
cell = g_ptr_array_index (self->cells, g_random_int_range (0, self->cells->len));
} while (cell->is_mine);
cell->is_mine = TRUE;
}
}
static SweeperCell *
get_cell (SweeperGame *self,
guint x,
guint y)
{
return g_ptr_array_index (self->cells, y * self->width + x);
}
static void
sweeper_game_count_neighbor_mines (SweeperGame *self,
guint width,
guint height)
{
guint x, y, x2, y2;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
SweeperCell *cell = get_cell (self, x, y);
for (y2 = MAX (1, y) - 1; y2 < MIN (height, y + 2); y2++)
{
for (x2 = MAX (1, x) - 1; x2 < MIN (width, x + 2); x2++)
{
SweeperCell *other = get_cell (self, x2, y2);
if (other->is_mine)
cell->neighbor_mines++;
}
}
}
}
}
static void
sweeper_game_new_game (SweeperGame *self,
guint width,
guint height,
guint n_mines)
{
guint n_items_before;
g_return_if_fail (n_mines <= width * height);
n_items_before = self->width * self->height;
g_object_freeze_notify (G_OBJECT (self));
sweeper_game_reset_board (self, width, height);
sweeper_game_place_mines (self, n_mines);
sweeper_game_count_neighbor_mines (self, width, height);
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items_before, width * height);
g_object_thaw_notify (G_OBJECT (self));
}
static void
sweeper_game_init (SweeperGame *self)
{
self->cells = g_ptr_array_new_with_free_func (g_object_unref);
sweeper_game_new_game (self, 8, 8, 10);
}
static void
sweeper_game_end (SweeperGame *self,
gboolean win)
{
if (self->playing)
{
self->playing = FALSE;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_PLAYING]);
}
if (self->win != win)
{
self->win = win;
g_object_notify_by_pspec (G_OBJECT (self), game_properties[GAME_PROP_WIN]);
}
}
static void
sweeper_game_check_finished (SweeperGame *self)
{
guint i;
if (!self->playing)
return;
for (i = 0; i < self->cells->len; i++)
{
SweeperCell *cell = g_ptr_array_index (self->cells, i);
/* There's still a non-revealed cell that isn't a mine */
if (!cell->is_visible && !cell->is_mine)
return;
}
sweeper_game_end (self, TRUE);
}
static void
sweeper_game_reveal_cell (SweeperGame *self,
guint position)
{
SweeperCell *cell;
if (!self->playing)
return;
cell = g_ptr_array_index (self->cells, position);
sweeper_cell_reveal (cell);
if (cell->is_mine)
sweeper_game_end (self, FALSE);
sweeper_game_check_finished (self);
}
void
minesweeper_cell_clicked_cb (GtkGridView *gridview,
guint pos,
SweeperGame *game)
{
sweeper_game_reveal_cell (game, pos);
}
void
minesweeper_new_game_cb (GtkButton *button,
SweeperGame *game)
{
sweeper_game_new_game (game, 8, 8, 10);
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_minesweeper (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkBuilder *builder;
g_type_ensure (SWEEPER_TYPE_GAME);
builder = gtk_builder_new_from_resource ("/listview_minesweeper/listview_minesweeper.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="SweeperGame" id="game">
</object>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">Minesweeper</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton">
<property name="label">New Game</property>
<signal name="clicked" handler="minesweeper_new_game_cb" object="game" swapped="no"/>
</object>
</child>
<child type="title">
<object class="GtkImage">
<property name="icon-name">trophy-gold</property>
<binding name="visible">
<lookup name="win">game</lookup>
</binding>
</object>
</child>
</object>
</child>
<child>
<object class="GtkGridView" id="view">
<property name="model">
<object class="GtkNoSelection">
<property name="model">game</property>
</object>
</property>
<binding name="max-columns">
<lookup name="width">game</lookup>
</binding>
<binding name="min-columns">
<lookup name="width">game</lookup>
</binding>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="resource">/listview_minesweeper/listview_minesweeper_cell.ui</property>
</object>
</property>
<signal name="activate" handler="minesweeper_cell_clicked_cb" object="game" swapped="no"/>
</object>
</child>
</object>
</interface>

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="halign">center</property>
<property name="valign">center</property>
<binding name="label">
<lookup name="label" type="SweeperCell">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>

View File

@@ -1,256 +0,0 @@
/* Lists/Settings
*
* This demo shows a settings viewer for GSettings.
*
* It demonstrates how to implement support for trees with listview.
*/
#include <gtk/gtk.h>
/* Create an object that wraps GSettingsSchemaKey because that's a boxed type */
typedef struct _SettingsKey SettingsKey;
struct _SettingsKey
{
GObject parent_instance;
GSettings *settings;
GSettingsSchemaKey *key;
};
enum {
PROP_0,
PROP_NAME,
PROP_SUMMARY,
PROP_DESCRIPTION,
PROP_VALUE,
N_PROPS
};
#define SETTINGS_TYPE_KEY (settings_key_get_type ())
G_DECLARE_FINAL_TYPE (SettingsKey, settings_key, SETTINGS, KEY, GObject);
G_DEFINE_TYPE (SettingsKey, settings_key, G_TYPE_OBJECT);
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
settings_key_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
SettingsKey *self = SETTINGS_KEY (object);
switch (property_id)
{
case PROP_DESCRIPTION:
g_value_set_string (value, g_settings_schema_key_get_description (self->key));
break;
case PROP_NAME:
g_value_set_string (value, g_settings_schema_key_get_name (self->key));
break;
case PROP_SUMMARY:
g_value_set_string (value, g_settings_schema_key_get_summary (self->key));
break;
case PROP_VALUE:
{
GVariant *variant = g_settings_get_value (self->settings, g_settings_schema_key_get_name (self->key));
g_value_take_string (value, g_variant_print (variant, FALSE));
g_variant_unref (variant);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
settings_key_class_init (SettingsKeyClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = settings_key_get_property;
properties[PROP_DESCRIPTION] =
g_param_spec_string ("description", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_NAME] =
g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_SUMMARY] =
g_param_spec_string ("summary", NULL, NULL, NULL, G_PARAM_READABLE);
properties[PROP_VALUE] =
g_param_spec_string ("value", NULL, NULL, NULL, G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
settings_key_init (SettingsKey *self)
{
}
static SettingsKey *
settings_key_new (GSettings *settings,
GSettingsSchemaKey *key)
{
SettingsKey *result = g_object_new (SETTINGS_TYPE_KEY, NULL);
result->settings = g_object_ref (settings);
result->key = g_settings_schema_key_ref (key);
return result;
}
static int
strvcmp (gconstpointer p1,
gconstpointer p2)
{
const char * const *s1 = p1;
const char * const *s2 = p2;
return strcmp (*s1, *s2);
}
static gboolean
transform_settings_to_keys (GBinding *binding,
const GValue *from_value,
GValue *to_value,
gpointer unused)
{
GtkTreeListRow *treelistrow;
GSettings *settings;
GSettingsSchema *schema;
GListStore *store;
char **keys;
guint i;
treelistrow = g_value_get_object (from_value);
if (treelistrow == NULL)
return TRUE;
settings = gtk_tree_list_row_get_item (treelistrow);
g_object_get (settings, "settings-schema", &schema, NULL);
store = g_list_store_new (SETTINGS_TYPE_KEY);
keys = g_settings_schema_list_keys (schema);
qsort (keys, g_strv_length (keys), sizeof (char *), strvcmp);
for (i = 0; keys[i] != NULL; i++)
{
GSettingsSchemaKey *almost_there = g_settings_schema_get_key (schema, keys[i]);
SettingsKey *finally = settings_key_new (settings, almost_there);
g_list_store_append (store, finally);
g_object_unref (finally);
g_settings_schema_key_unref (almost_there);
}
g_strfreev (keys);
g_settings_schema_unref (schema);
g_object_unref (settings);
g_value_take_object (to_value, store);
return TRUE;
}
static GListModel *
create_settings_model (gpointer item,
gpointer unused)
{
GSettings *settings = item;
char **schemas;
GListStore *result;
guint i;
if (settings == NULL)
{
g_settings_schema_source_list_schemas (g_settings_schema_source_get_default (),
TRUE,
&schemas,
NULL);
}
else
{
schemas = g_settings_list_children (settings);
}
if (schemas == NULL || schemas[0] == NULL)
{
g_free (schemas);
return NULL;
}
qsort (schemas, g_strv_length (schemas), sizeof (char *), strvcmp);
result = g_list_store_new (G_TYPE_SETTINGS);
for (i = 0; schemas[i] != NULL; i++)
{
GSettings *child;
if (settings == NULL)
child = g_settings_new (schemas[i]);
else
child = g_settings_get_child (settings, schemas[i]);
g_list_store_append (result, child);
g_object_unref (child);
}
return G_LIST_MODEL (result);
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_settings (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *listview, *columnview;
GListModel *model;
GtkTreeListModel *treemodel;
GtkSingleSelection *selection;
GtkBuilder *builder;
g_type_ensure (SETTINGS_TYPE_KEY);
builder = gtk_builder_new_from_resource ("/listview_settings/listview_settings.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
listview = GTK_WIDGET (gtk_builder_get_object (builder, "listview"));
columnview = GTK_WIDGET (gtk_builder_get_object (builder, "columnview"));
model = create_settings_model (NULL, NULL);
treemodel = gtk_tree_list_model_new (FALSE,
model,
TRUE,
create_settings_model,
NULL,
NULL);
selection = gtk_single_selection_new (G_LIST_MODEL (treemodel));
g_object_bind_property_full (selection, "selected-item",
columnview, "model",
G_BINDING_SYNC_CREATE,
transform_settings_to_keys,
NULL,
NULL, NULL);
gtk_list_view_set_model (GTK_LIST_VIEW (listview), G_LIST_MODEL (selection));
g_object_unref (selection);
g_object_unref (treemodel);
g_object_unref (model);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,108 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">Settings</property>
<property name="default-width">600</property>
<property name="default-height">400</property>
<child>
<object class="GtkPaned">
<child>
<object class="GtkScrolledWindow">
<child>
<object class="GtkListView" id="listview">
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkTreeExpander" id="expander">
<binding name="list-row">
<lookup name="item">GtkListItem</lookup>
</binding>
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="schema" type="GSettings">
<lookup name="item">expander</lookup>
</lookup>
</binding>
</object>
</property>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<child>
<object class="GtkColumnView" id="columnview">
<child>
<object class="GtkColumnViewColumn">
<property name="title">Name</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="name" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn">
<property name="title">Value</property>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkLabel">
<property name="xalign">0</property>
<binding name="label">
<lookup name="value" type="SettingsKey">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</property>
</template>
</interface>
]]></property>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -1,316 +0,0 @@
/* Lists/Weather
*
* This demo shows a few of the rarer features of GtkListView and
* how they can be used to display weather information.
*
* The hourly weather info uses a horizontal listview. This is easy
* to achieve because GtkListView implements the GtkOrientable interface.
*
* To make the items in the list stand out more, the listview uses
* separators.
*
* A GtkNoSelectionModel is used to make sure no item in the list can be
* selected. All other interactions with the items is still possible.
*/
#include <gtk/gtk.h>
#define GTK_TYPE_WEATHER_INFO (gtk_weather_info_get_type ())
G_DECLARE_FINAL_TYPE (GtkWeatherInfo, gtk_weather_info, GTK, WEATHER_INFO, GObject)
typedef enum {
GTK_WEATHER_CLEAR,
GTK_WEATHER_FEW_CLOUDS,
GTK_WEATHER_FOG,
GTK_WEATHER_OVERCAST,
GTK_WEATHER_SCATTERED_SHOWERS,
GTK_WEATHER_SHOWERS,
GTK_WEATHER_SNOW,
GTK_WEATHER_STORM
} GtkWeatherType;
struct _GtkWeatherInfo
{
GObject parent_instance;
gint64 timestamp;
int temperature;
GtkWeatherType weather_type;
};
struct _GtkWeatherInfoClass
{
GObjectClass parent_class;
};
static void
gtk_weather_info_class_init (GtkWeatherInfoClass *klass)
{
}
static void
gtk_weather_info_init (GtkWeatherInfo *self)
{
}
G_DEFINE_TYPE (GtkWeatherInfo, gtk_weather_info, G_TYPE_OBJECT);
static GtkWeatherInfo *
gtk_weather_info_new (GDateTime *timestamp,
GtkWeatherInfo *copy_from)
{
GtkWeatherInfo *result;
result = g_object_new (GTK_TYPE_WEATHER_INFO, NULL);
result->timestamp = g_date_time_to_unix (timestamp);
if (copy_from)
{
result->temperature = copy_from->temperature;
result->weather_type = copy_from->weather_type;
g_object_unref (copy_from);
}
return result;
}
static GDateTime *
parse_timestamp (const char *string,
GTimeZone *timezone)
{
char *with_seconds;
GDateTime *result;
with_seconds = g_strconcat (string, ":00", NULL);
result = g_date_time_new_from_iso8601 (with_seconds, timezone);
g_free (with_seconds);
return result;
}
static GtkWeatherType
parse_weather_type (const char *clouds,
const char *precip,
GtkWeatherType fallback)
{
if (strstr (precip, "SN"))
return GTK_WEATHER_SNOW;
if (strstr (precip, "TS"))
return GTK_WEATHER_STORM;
if (strstr (precip, "DZ"))
return GTK_WEATHER_SCATTERED_SHOWERS;
if (strstr (precip, "SH") || strstr (precip, "RA"))
return GTK_WEATHER_SHOWERS;
if (strstr (precip, "FG"))
return GTK_WEATHER_FOG;
if (g_str_equal (clouds, "M") ||
g_str_equal (clouds, ""))
return fallback;
if (strstr (clouds, "OVC") ||
strstr (clouds, "BKN"))
return GTK_WEATHER_OVERCAST;
if (strstr (clouds, "BKN") ||
strstr (clouds, "SCT"))
return GTK_WEATHER_FEW_CLOUDS;
if (strstr (clouds, "VV"))
return GTK_WEATHER_FOG;
return GTK_WEATHER_CLEAR;
}
static double
parse_temperature (const char *s,
double fallback)
{
char *endptr;
double d;
d = g_ascii_strtod (s, &endptr);
if (*endptr != '\0')
return fallback;
return d;
}
static GListModel *
create_weather_model (void)
{
GListStore *store;
GTimeZone *utc;
GDateTime *timestamp;
GtkWeatherInfo *info;
GBytes *data;
char **lines;
guint i;
store = g_list_store_new (GTK_TYPE_WEATHER_INFO);
data = g_resources_lookup_data ("/listview_weather/listview_weather.txt", 0, NULL);
lines = g_strsplit (g_bytes_get_data (data, NULL), "\n", 0);
utc = g_time_zone_new_utc ();
timestamp = g_date_time_new (utc, 2011, 1, 1, 0, 0, 0);
info = gtk_weather_info_new (timestamp, NULL);
g_list_store_append (store, info);
for (i = 0; lines[i] != NULL && *lines[i]; i++)
{
char **fields;
GDateTime *date;
fields = g_strsplit (lines[i], ",", 0);
date = parse_timestamp (fields[0], utc);
while (g_date_time_difference (date, timestamp) > 30 * G_TIME_SPAN_MINUTE)
{
GDateTime *new_timestamp = g_date_time_add_hours (timestamp, 1);
g_date_time_unref (timestamp);
timestamp = new_timestamp;
info = gtk_weather_info_new (timestamp, info);
g_list_store_append (store, info);
}
info->temperature = parse_temperature (fields[1], info->temperature);
info->weather_type = parse_weather_type (fields[2], fields[3], info->weather_type);
g_date_time_unref (date);
g_strfreev (fields);
}
g_strfreev (lines);
g_bytes_unref (data);
g_time_zone_unref (utc);
return G_LIST_MODEL (store);
}
static void
setup_widget (GtkListItem *list_item,
gpointer unused)
{
GtkWidget *box, *child;
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_list_item_set_child (list_item, box);
child = gtk_label_new (NULL);
gtk_label_set_width_chars (GTK_LABEL (child), 5);
gtk_container_add (GTK_CONTAINER (box), child);
child = gtk_image_new ();
gtk_image_set_icon_size (GTK_IMAGE (child), GTK_ICON_SIZE_LARGE);
gtk_container_add (GTK_CONTAINER (box), child);
child = gtk_label_new (NULL);
gtk_widget_set_vexpand (child, TRUE);
gtk_widget_set_valign (child, GTK_ALIGN_END);
gtk_label_set_width_chars (GTK_LABEL (child), 4);
gtk_container_add (GTK_CONTAINER (box), child);
}
static void
bind_widget (GtkListItem *list_item,
gpointer unused)
{
GtkWidget *box, *child;
GtkWeatherInfo *info;
GDateTime *timestamp;
char *s;
box = gtk_list_item_get_child (list_item);
info = gtk_list_item_get_item (list_item);
child = gtk_widget_get_first_child (box);
timestamp = g_date_time_new_from_unix_utc (info->timestamp);
s = g_date_time_format (timestamp, "%R");
gtk_label_set_text (GTK_LABEL (child), s);
g_free (s);
g_date_time_unref (timestamp);
child = gtk_widget_get_next_sibling (child);
switch (info->weather_type)
{
case GTK_WEATHER_CLEAR:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-clear-symbolic");
break;
case GTK_WEATHER_FEW_CLOUDS:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-few-clouds-symbolic");
break;
case GTK_WEATHER_FOG:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-fog-symbolic");
break;
case GTK_WEATHER_OVERCAST:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-overcast-symbolic");
break;
case GTK_WEATHER_SCATTERED_SHOWERS:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-showers-scattered-symbolic");
break;
case GTK_WEATHER_SHOWERS:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-showers-symbolic");
break;
case GTK_WEATHER_SNOW:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-snow-symbolic");
break;
case GTK_WEATHER_STORM:
gtk_image_set_from_icon_name (GTK_IMAGE (child), "weather-storm-symbolic");
break;
default:
gtk_image_clear (GTK_IMAGE (child));
break;
}
child = gtk_widget_get_next_sibling (child);
s = g_strdup_printf ("%d°", info->temperature);
gtk_label_set_text (GTK_LABEL (child), s);
g_free (s);
}
static GtkWidget *window = NULL;
GtkWidget *
do_listview_weather (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *listview, *sw;;
GListModel *model, *selection;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Weather");
g_signal_connect (window, "destroy",
G_CALLBACK(gtk_widget_destroyed), &window);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), sw);
listview = gtk_list_view_new_with_factory (
gtk_functions_list_item_factory_new (setup_widget,
bind_widget,
NULL, NULL));
gtk_orientable_set_orientation (GTK_ORIENTABLE (listview), GTK_ORIENTATION_HORIZONTAL);
gtk_list_view_set_show_separators (GTK_LIST_VIEW (listview), TRUE);
model = create_weather_model ();
selection = G_LIST_MODEL (gtk_no_selection_new (model));
gtk_list_view_set_model (GTK_LIST_VIEW (listview), selection);
g_object_unref (selection);
g_object_unref (model);
gtk_container_add (GTK_CONTAINER (sw), listview);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="child">
<object class="GtkTreeExpander" id="expander">
<binding name="list-row">
<lookup name="item">GtkListItem</lookup>
</binding>
<property name="child">
<object class="GtkLabel">
<property name="halign">start</property>
<binding name="label">
<lookup name="title" type="GtkDemo">
<lookup name="item">expander</lookup>
</lookup>
</binding>
</object>
</property>
</object>
</property>
</template>
</interface>

View File

@@ -8,7 +8,6 @@
#include <gtk/gtk.h>
#include <glib/gstdio.h>
#include "award.h"
#include "demos.h"
static GtkWidget *info_view;
@@ -16,99 +15,19 @@ static GtkWidget *source_view;
static gchar *current_file = NULL;
static GtkWidget *window;
static GtkWidget *notebook;
static GtkWidget *listview;
static GtkSingleSelection *selection;
static GtkWidget *treeview;
static GtkWidget *headerbar;
typedef struct _GtkDemo GtkDemo;
struct _GtkDemo
{
GObject parent_instance;
const char *name;
const char *title;
const char *filename;
GDoDemoFunc func;
GListModel *children_model;
};
enum {
PROP_0,
PROP_FILENAME,
PROP_NAME,
PROP_TITLE,
N_PROPS
NAME_COLUMN,
TITLE_COLUMN,
FILENAME_COLUMN,
FUNC_COLUMN,
STYLE_COLUMN,
NUM_COLUMNS
};
# define GTK_TYPE_DEMO (gtk_demo_get_type ())
G_DECLARE_FINAL_TYPE (GtkDemo, gtk_demo, GTK, DEMO, GObject);
G_DEFINE_TYPE (GtkDemo, gtk_demo, G_TYPE_OBJECT);
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
gtk_demo_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkDemo *self = GTK_DEMO (object);
switch (property_id)
{
case PROP_FILENAME:
g_value_set_string (value, self->filename);
break;
case PROP_NAME:
g_value_set_string (value, self->name);
break;
case PROP_TITLE:
g_value_set_string (value, self->title);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void gtk_demo_class_init (GtkDemoClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = gtk_demo_get_property;
properties[PROP_FILENAME] =
g_param_spec_string ("filename",
"filename",
"filename",
NULL,
G_PARAM_READABLE);
properties[PROP_NAME] =
g_param_spec_string ("name",
"name",
"name",
NULL,
G_PARAM_READABLE);
properties[PROP_TITLE] =
g_param_spec_string ("title",
"title",
"title",
NULL,
G_PARAM_READABLE);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void gtk_demo_init (GtkDemo *self)
{
}
typedef struct _CallbackData CallbackData;
struct _CallbackData
{
@@ -116,27 +35,6 @@ struct _CallbackData
GtkTreePath *path;
};
static gboolean
gtk_demo_run (GtkDemo *self,
GtkWidget *window)
{
GtkWidget *result;
if (!self->func)
return FALSE;
result = self->func (window);
if (result == NULL)
return FALSE;
if (GTK_IS_WINDOW (result))
{
gtk_window_set_transient_for (GTK_WINDOW (result), GTK_WINDOW (window));
gtk_window_set_modal (GTK_WINDOW (result), TRUE);
}
return TRUE;
}
static void
activate_about (GSimpleAction *action,
GVariant *parameter,
@@ -213,7 +111,69 @@ activate_inspector (GSimpleAction *action,
gpointer user_data)
{
gtk_window_set_interactive_debugging (TRUE);
award ("demo-inspector");
}
static void
window_closed_cb (GtkWidget *window, gpointer data)
{
CallbackData *cbdata = data;
GtkTreeIter iter;
PangoStyle style;
gtk_tree_model_get_iter (cbdata->model, &iter, cbdata->path);
gtk_tree_model_get (GTK_TREE_MODEL (cbdata->model), &iter,
STYLE_COLUMN, &style,
-1);
if (style == PANGO_STYLE_ITALIC)
gtk_tree_store_set (GTK_TREE_STORE (cbdata->model), &iter,
STYLE_COLUMN, PANGO_STYLE_NORMAL,
-1);
gtk_tree_path_free (cbdata->path);
g_free (cbdata);
}
static void
run_example_for_row (GtkWidget *window,
GtkTreeModel *model,
GtkTreeIter *iter)
{
PangoStyle style;
GDoDemoFunc func;
GtkWidget *demo;
gtk_tree_model_get (GTK_TREE_MODEL (model),
iter,
FUNC_COLUMN, &func,
STYLE_COLUMN, &style,
-1);
if (func)
{
gtk_tree_store_set (GTK_TREE_STORE (model),
iter,
STYLE_COLUMN, (style == PANGO_STYLE_ITALIC ? PANGO_STYLE_NORMAL : PANGO_STYLE_ITALIC),
-1);
demo = (func) (window);
if (demo != NULL)
{
CallbackData *cbdata;
cbdata = g_new (CallbackData, 1);
cbdata->model = model;
cbdata->path = gtk_tree_model_get_path (model, iter);
if (GTK_IS_WINDOW (demo))
{
gtk_window_set_transient_for (GTK_WINDOW (demo), GTK_WINDOW (window));
gtk_window_set_modal (GTK_WINDOW (demo), TRUE);
}
g_signal_connect (demo, "destroy",
G_CALLBACK (window_closed_cb), cbdata);
}
}
}
static void
@@ -221,10 +181,14 @@ activate_run (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkTreeListRow *row = gtk_single_selection_get_selected_item (selection);
GtkDemo *demo = gtk_tree_list_row_get_item (row);
GtkWidget *window = user_data;
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
gtk_demo_run (demo, window);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
if (gtk_tree_selection_get_selected (selection, &model, &iter))
run_example_for_row (window, model, &iter);
}
/* Stupid syntax highlighting.
@@ -523,7 +487,7 @@ parse_chars (gchar *text,
}
/* While not as cool as c-mode, this will do as a quick attempt at highlighting */
void
static void
fontify (GtkTextBuffer *source_buffer)
{
GtkTextIter start_iter, next_iter, tmp_iter;
@@ -675,7 +639,7 @@ display_nothing (const char *resource)
str = g_strdup_printf ("The lazy GTK developers forgot to add a way to display the resource '%s'", resource);
widget = gtk_label_new (str);
gtk_label_set_wrap (GTK_LABEL (widget), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
g_free (str);
@@ -784,9 +748,6 @@ load_file (const gchar *demoname,
source_buffer = gtk_text_buffer_new (NULL);
gtk_text_buffer_begin_irreversible_action (info_buffer);
gtk_text_buffer_begin_irreversible_action (source_buffer);
resource_filename = g_strconcat ("/sources/", filename, NULL);
bytes = g_resources_lookup_data (resource_filename, 0, &err);
g_free (resource_filename);
@@ -919,82 +880,89 @@ load_file (const gchar *demoname,
fontify (source_buffer);
gtk_text_buffer_end_irreversible_action (source_buffer);
gtk_text_view_set_buffer (GTK_TEXT_VIEW (source_view), source_buffer);
g_object_unref (source_buffer);
gtk_text_buffer_end_irreversible_action (info_buffer);
gtk_text_view_set_buffer (GTK_TEXT_VIEW (info_view), info_buffer);
g_object_unref (info_buffer);
}
static void
selection_cb (GtkSingleSelection *selection,
GParamSpec *pspec,
gpointer user_data)
selection_cb (GtkTreeSelection *selection,
GtkTreeModel *model)
{
GtkTreeListRow *row = gtk_single_selection_get_selected_item (selection);
GtkDemo *demo = gtk_tree_list_row_get_item (row);
GtkTreeIter iter;
char *name;
char *filename;
char *title;
if (demo->filename)
load_file (demo->name, demo->filename);
if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
return;
gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar), demo->title);
gtk_tree_model_get (model, &iter,
NAME_COLUMN, &name,
TITLE_COLUMN, &title,
FILENAME_COLUMN, &filename,
-1);
if (filename)
load_file (name, filename);
gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar), title);
g_free (name);
g_free (title);
g_free (filename);
}
static GListModel *
create_demo_model (void)
static void
populate_model (GtkTreeModel *model)
{
GListStore *store = g_list_store_new (GTK_TYPE_DEMO);
DemoData *demo = gtk_demos;
Demo *d = gtk_demos;
while (demo->title)
/* this code only supports 1 level of children. If we
* want more we probably have to use a recursing function.
*/
while (d->title)
{
GtkDemo *d = GTK_DEMO (g_object_new (GTK_TYPE_DEMO, NULL));
DemoData *children = demo->children;
Demo *children = d->children;
GtkTreeIter iter;
d->name = demo->name;
d->title = demo->title;
d->filename = demo->filename;
d->func = demo->func;
gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
g_list_store_append (store, d);
gtk_tree_store_set (GTK_TREE_STORE (model),
&iter,
NAME_COLUMN, d->name,
TITLE_COLUMN, d->title,
FILENAME_COLUMN, d->filename,
FUNC_COLUMN, d->func,
STYLE_COLUMN, PANGO_STYLE_NORMAL,
-1);
if (children)
d++;
if (!children)
continue;
while (children->title)
{
d->children_model = G_LIST_MODEL (g_list_store_new (GTK_TYPE_DEMO));
GtkTreeIter child_iter;
while (children->title)
{
GtkDemo *child = GTK_DEMO (g_object_new (GTK_TYPE_DEMO, NULL));
gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &iter);
child->name = children->name;
child->title = children->title;
child->filename = children->filename;
child->func = children->func;
gtk_tree_store_set (GTK_TREE_STORE (model),
&child_iter,
NAME_COLUMN, children->name,
TITLE_COLUMN, children->title,
FILENAME_COLUMN, children->filename,
FUNC_COLUMN, children->func,
STYLE_COLUMN, PANGO_STYLE_NORMAL,
-1);
g_list_store_append (G_LIST_STORE (d->children_model), child);
children++;
}
children++;
}
demo++;
}
return G_LIST_MODEL (store);
}
static GListModel *
get_child_model (gpointer item,
gpointer user_data)
{
GtkDemo *demo = item;
if (demo->children_model)
return g_object_ref (G_LIST_MODEL (demo->children_model));
return NULL;
}
static void
@@ -1014,6 +982,22 @@ startup (GApplication *app)
g_object_unref (builder);
}
static void
row_activated_cb (GtkWidget *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column)
{
GtkTreeIter iter;
GtkWidget *window;
GtkTreeModel *model;
window = GTK_WIDGET (gtk_widget_get_root (tree_view));
model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view));
gtk_tree_model_get_iter (model, &iter, path);
run_example_for_row (window, model, &iter);
}
static void
start_cb (GtkMenuItem *item, GtkWidget *scrollbar)
{
@@ -1040,36 +1024,34 @@ scrollbar_popup (GtkWidget *scrollbar, GtkWidget *menu)
return TRUE;
}
void
main_activate_cb (GtkListView *listview,
guint position,
gpointer user_data)
{
GtkTreeListRow *row = g_list_model_get_item (gtk_list_view_get_model (listview), position);
GtkDemo *demo = gtk_tree_list_row_get_item (row);
gtk_demo_run (demo, window);
}
static void
activate (GApplication *app)
{
GtkBuilder *builder;
GtkWindow *window;
GtkWidget *widget;
GtkTreeModel *model;
GtkTreeIter iter;
GError *error = NULL;
GtkWidget *sw;
GtkWidget *scrollbar;
GtkWidget *menu;
GtkWidget *item;
GListModel *listmodel;
GtkTreeListModel *treemodel;
static GActionEntry win_entries[] = {
{ "run", activate_run, NULL, NULL, NULL }
};
builder = gtk_builder_new_from_resource ("/ui/main.ui");
builder = gtk_builder_new ();
gtk_builder_add_from_resource (builder, "/ui/main.ui", &error);
if (error != NULL)
{
g_critical ("%s", error->message);
exit (1);
}
window = (GtkWidget *)gtk_builder_get_object (builder, "window");
gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (window));
window = (GtkWindow *)gtk_builder_get_object (builder, "window");
gtk_application_add_window (GTK_APPLICATION (app), window);
g_action_map_add_action_entries (G_ACTION_MAP (window),
win_entries, G_N_ELEMENTS (win_entries),
window);
@@ -1079,7 +1061,8 @@ activate (GApplication *app)
info_view = (GtkWidget *)gtk_builder_get_object (builder, "info-textview");
source_view = (GtkWidget *)gtk_builder_get_object (builder, "source-textview");
headerbar = (GtkWidget *)gtk_builder_get_object (builder, "headerbar");
listview = (GtkWidget *)gtk_builder_get_object (builder, "listview");
treeview = (GtkWidget *)gtk_builder_get_object (builder, "treeview");
model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
sw = (GtkWidget *)gtk_builder_get_object (builder, "source-scrolledwindow");
scrollbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (sw));
@@ -1098,19 +1081,17 @@ activate (GApplication *app)
load_file (gtk_demos[0].name, gtk_demos[0].filename);
listmodel = create_demo_model ();
treemodel = gtk_tree_list_model_new (FALSE,
G_LIST_MODEL (listmodel),
FALSE,
get_child_model,
NULL,
NULL);
selection = gtk_single_selection_new (G_LIST_MODEL (treemodel));
g_signal_connect (selection, "notify::selected-item", G_CALLBACK (selection_cb), NULL);
gtk_list_view_set_model (GTK_LIST_VIEW (listview),
G_LIST_MODEL (selection));
populate_model (model);
award ("demo-start");
g_signal_connect (treeview, "row-activated", G_CALLBACK (row_activated_cb), model);
widget = (GtkWidget *)gtk_builder_get_object (builder, "treeview-selection");
g_signal_connect (widget, "changed", G_CALLBACK (selection_cb), model);
gtk_tree_model_get_iter_first (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)), &iter);
gtk_tree_selection_select_iter (GTK_TREE_SELECTION (widget), &iter);
gtk_tree_view_collapse_all (GTK_TREE_VIEW (treeview));
gtk_widget_show (GTK_WIDGET (window));
@@ -1127,7 +1108,7 @@ auto_quit (gpointer data)
static void
list_demos (void)
{
DemoData *d, *c;
Demo *d, *c;
d = gtk_demos;
@@ -1154,7 +1135,7 @@ command_line (GApplication *app,
const gchar *name = NULL;
gboolean autoquit = FALSE;
gboolean list = FALSE;
DemoData *d, *c;
Demo *d, *c;
GDoDemoFunc func = 0;
GtkWidget *window, *demo;

View File

@@ -28,6 +28,7 @@
<property name="default-width">800</property>
<property name="default-height">600</property>
<property name="title">GTK Demo</property>
<signal name="destroy" handler="gtk_main_quit" swapped="no"/>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
<property name="show-title-buttons">1</property>
@@ -65,15 +66,32 @@
<property name="can-focus">1</property>
<property name="hscrollbar-policy">never</property>
<property name="min-content-width">150</property>
<child>
<object class="GtkListView" id="listview">
<signal name="activate" handler="main_activate_cb" swapped="no" />
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="resource">/ui/main-listitem.ui</property>
<object class="GtkTreeView" id="treeview">
<property name="can-focus">1</property>
<property name="model">treestore</property>
<property name="headers-visible">0</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection">
<property name="mode">browse</property>
</object>
</property>
</child>
<child>
<object class="GtkTreeViewColumn">
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="style">4</attribute>
<attribute name="text">1</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererText">
<property name="text"> </property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>

View File

@@ -29,10 +29,8 @@ source_toggled (GtkToggleButton *button)
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
gtk_text_buffer_get_bounds (buffer, &start, &end);
gtk_text_buffer_begin_irreversible_action (buffer);
gtk_text_buffer_delete (buffer, &start, &end);
gtk_text_buffer_insert_markup (buffer, &start, markup, -1);
gtk_text_buffer_end_irreversible_action (buffer);
g_free (markup);
gtk_stack_set_visible_child_name (GTK_STACK (stack), "formatted");
@@ -108,15 +106,11 @@ do_markup (GtkWidget *do_widget)
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
gtk_text_buffer_get_start_iter (buffer, &iter);
gtk_text_buffer_begin_irreversible_action (buffer);
gtk_text_buffer_insert_markup (buffer, &iter, markup, -1);
gtk_text_buffer_end_irreversible_action (buffer);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view2));
gtk_text_buffer_get_start_iter (buffer, &iter);
gtk_text_buffer_begin_irreversible_action (buffer);
gtk_text_buffer_insert (buffer, &iter, markup, -1);
gtk_text_buffer_end_irreversible_action (buffer);
g_bytes_unref (bytes);

View File

@@ -3,7 +3,6 @@
demos = files([
'application_demo.c',
'assistant.c',
'awardview.c',
'builder.c',
'changedisplay.c',
'clipboard.c',
@@ -11,7 +10,6 @@ demos = files([
'combobox.c',
'constraints.c',
'constraints2.c',
'constraints3.c',
'css_accordion.c',
'css_basics.c',
'css_blendmodes.c',
@@ -23,19 +21,17 @@ demos = files([
'drawingarea.c',
'dnd.c',
'editable_cells.c',
'entry_buffer.c',
'entry_completion.c',
'entry_undo.c',
'expander.c',
'filtermodel.c',
'fishbowl.c',
'fixed.c',
'fontrendering.c',
'foreigndrawing.c',
'gestures.c',
'glarea.c',
'headerbar.c',
'hypertext.c',
'iconscroll.c',
'iconview.c',
'iconview_edit.c',
'images.c',
@@ -44,12 +40,6 @@ demos = files([
'listbox.c',
'flowbox.c',
'list_store.c',
'listview_applauncher.c',
'listview_clocks.c',
'listview_filebrowser.c',
'listview_minesweeper.c',
'listview_settings.c',
'listview_weather.c',
'markup.c',
'menus.c',
'modelbutton.c',
@@ -80,7 +70,6 @@ demos = files([
'tabs.c',
'tagged_entry.c',
'textmask.c',
'textundo.c',
'textview.c',
'textscroll.c',
'themes.c',
@@ -93,7 +82,6 @@ demos = files([
gtkdemo_deps = [ libgtk_dep, ]
extra_demo_sources = files(['main.c',
'award.c',
'gtkfishbowl.c',
'fontplane.c',
'gtkgears.c',
@@ -104,7 +92,7 @@ extra_demo_sources = files(['main.c',
if harfbuzz_dep.found() and pangoft_dep.found()
demos += files('font_features.c')
extra_demo_sources += files(['script-names.c', 'language-names.c'])
gtkdemo_deps += [ harfbuzz_dep, epoxy_dep ]
gtkdemo_deps += [ harfbuzz_dep, ]
endif
if os_unix

View File

@@ -378,7 +378,7 @@
378|GTK+ and friends|GTKtoolkit|#GNUStep gets #GTK+ theming http://is.gd/95vHl more at http://is.gd/95wt8|1267029498|0||0|1
379|GTK+ and friends|GTKtoolkit|GTK+ 2.19.6 released: http://mail.gnome.org/archives/gtk-devel-list/2010-February/msg00050.html #gtk|1266966985|0||0|0
380|GTK+ and friends|GTKtoolkit|Did you know that #GTK+ is the official toolkit for the #LiMo software stack? http://bit.ly/cuEdHx|1266925406|0||0|0
381|GTK+ and friends|GTKtoolkit|@lmedinas publishes a #javascript #example on how to put a status icon with #Gtk+ http://bit.ly/9py1uC Thanks a lot Luis!|1266886644|0||1|1
381|GTK+ and friends|GTKtoolkit|@lmedinas publishes a #javascript #example on how to put an status icon with #Gtk+ http://bit.ly/9py1uC Thanks a lot Luis!|1266886644|0||1|1
382|GTK+ and friends|GTKtoolkit|♺ @ebassi: I should really finish up the GDom API as well|1266880653|0||0|0
383|GTK+ and friends|GTKtoolkit|♺ @ebassi: I hope to work on this for the next GIO release, and the GTK+ side for 3.0|1266880641|0||0|0
384|GTK+ and friends|GTKtoolkit|♺ @ebassi: just updated the ApplicationClass design wiki page with the stuff @Cwiiis did for Mx - http://bit.ly/cfAOJk|1266880559|0||0|0

View File

@@ -14,8 +14,8 @@
#include <gtk/gtk.h>
void
modelbutton_tool_clicked (GtkButton *button)
static void
tool_clicked (GtkButton *button)
{
gboolean active;
@@ -40,6 +40,8 @@ do_modelbutton (GtkWidget *do_widget)
GActionGroup *actions;
builder = gtk_builder_new_from_resource ("/modelbutton/modelbutton.ui");
gtk_builder_add_callback_symbol (builder, "tool_clicked", G_CALLBACK (tool_clicked));
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -14,19 +14,34 @@
<child>
<object class="GtkMenuButton">
<property name="popover">thing_a</property>
<property name="label">Color</property>
<child>
<object class="GtkLabel">
<property name="label">Color</property>
<property name="hexpand">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuButton">
<property name="popover">thing_b</property>
<property name="label">Flavors</property>
<child>
<object class="GtkLabel">
<property name="label">Flavors</property>
<property name="hexpand">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuButton">
<property name="popover">thing_c</property>
<property name="label">Tools</property>
<child>
<object class="GtkLabel">
<property name="label">Tools</property>
<property name="hexpand">1</property>
</object>
</child>
</object>
</child>
</object>
@@ -42,6 +57,7 @@
<property name="action-name">win.color</property>
<property name="action-target">&apos;red&apos;</property>
<property name="text">Red</property>
<property name="inverted">1</property>
</object>
</child>
<child>
@@ -49,6 +65,7 @@
<property name="action-name">win.color</property>
<property name="action-target">&apos;green&apos;</property>
<property name="text">Green</property>
<property name="inverted">1</property>
</object>
</child>
<child>
@@ -56,6 +73,7 @@
<property name="action-name">win.color</property>
<property name="action-target">&apos;blue&apos;</property>
<property name="text">Blue</property>
<property name="inverted">1</property>
</object>
</child>
</object>
@@ -101,21 +119,21 @@
<object class="GtkModelButton">
<property name="text">Hammer</property>
<property name="role">check</property>
<signal name="clicked" handler="modelbutton_tool_clicked"/>
<signal name="clicked" handler="tool_clicked"/>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Screwdriver</property>
<property name="role">check</property>
<signal name="clicked" handler="modelbutton_tool_clicked"/>
<signal name="clicked" handler="tool_clicked"/>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Drill</property>
<property name="role">check</property>
<signal name="clicked" handler="modelbutton_tool_clicked"/>
<signal name="clicked" handler="tool_clicked"/>
</object>
</child>
</object>

View File

@@ -6,7 +6,7 @@
* GTK uses for videos. This allows treating the icon like a
* regular video, so we can for example attach controls to it.
*
* After all, what good is a media_stream if one cannot pause
* After all, what good is an media_stream if one cannot pause
* it.
*/

View File

@@ -11,8 +11,6 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "award.h"
static GtkWidget *entry;
static GtkWidget *entry2;
static GtkWidget *button;
@@ -27,18 +25,6 @@ update_button (GObject *object,
gtk_widget_set_sensitive (button,
text[0] != '\0' && g_str_equal (text, text2));
if (g_str_equal (text, text2) &&
g_ascii_strcasecmp (text, "12345") == 0)
award ("password-best");
}
static void
button_pressed (GtkButton *button,
GtkWidget *window)
{
award ("password-correct");
gtk_widget_destroy (window);
}
GtkWidget *
@@ -86,7 +72,7 @@ do_password_entry (GtkWidget *do_widget)
button = gtk_button_new_with_mnemonic ("_Done");
gtk_style_context_add_class (gtk_widget_get_style_context (button), "suggested-action");
g_signal_connect (button, "clicked", G_CALLBACK (button_pressed), window);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_widget_set_sensitive (button, FALSE);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button);

View File

@@ -69,6 +69,7 @@ do_revealer (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/revealer/revealer.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -18,6 +18,7 @@ do_scale (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/scale/scale.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -25,44 +25,44 @@ show_shortcuts (GtkWidget *window,
g_object_unref (builder);
}
void
shortcuts_builder_shortcuts (GtkWidget *window)
static void
builder_shortcuts (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-builder", NULL);
}
void
shortcuts_gedit_shortcuts (GtkWidget *window)
static void
gedit_shortcuts (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-gedit", NULL);
}
void
shortcuts_clocks_shortcuts (GtkWidget *window)
static void
clocks_shortcuts (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-clocks", NULL);
}
void
shortcuts_clocks_shortcuts_stopwatch (GtkWidget *window)
static void
clocks_shortcuts_stopwatch (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-clocks", "stopwatch");
}
void
shortcuts_boxes_shortcuts (GtkWidget *window)
static void
boxes_shortcuts (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-boxes", NULL);
}
void
shortcuts_boxes_shortcuts_wizard (GtkWidget *window)
static void
boxes_shortcuts_wizard (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-boxes", "wizard");
}
void
shortcuts_boxes_shortcuts_display (GtkWidget *window)
static void
boxes_shortcuts_display (GtkWidget *window)
{
show_shortcuts (window, "shortcuts-boxes", "display");
}
@@ -86,6 +86,16 @@ do_shortcuts (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/shortcuts/shortcuts.ui");
gtk_builder_add_callback_symbols (builder,
"builder_shortcuts", G_CALLBACK (builder_shortcuts),
"gedit_shortcuts", G_CALLBACK (gedit_shortcuts),
"clocks_shortcuts", G_CALLBACK (clocks_shortcuts),
"clocks_shortcuts_stopwatch", G_CALLBACK (clocks_shortcuts_stopwatch),
"boxes_shortcuts", G_CALLBACK (boxes_shortcuts),
"boxes_shortcuts_wizard", G_CALLBACK (boxes_shortcuts_wizard),
"boxes_shortcuts_display", G_CALLBACK (boxes_shortcuts_display),
NULL);
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -10,43 +10,43 @@
<child>
<object class="GtkButton">
<property name="label">Builder</property>
<signal name="clicked" handler="shortcuts_builder_shortcuts" swapped="1" object="window1"/>
<signal name="clicked" handler="builder_shortcuts" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">GEdit</property>
<signal name="clicked" handler="shortcuts_gedit_shortcuts" swapped="1" object="window1"/>
<signal name="clicked" handler="gedit_shortcuts" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Clocks - All</property>
<signal name="clicked" handler="shortcuts_clocks_shortcuts" swapped="1" object="window1"/>
<signal name="clicked" handler="clocks_shortcuts" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Clocks - Stopwatch</property>
<signal name="clicked" handler="shortcuts_clocks_shortcuts_stopwatch" swapped="1" object="window1"/>
<signal name="clicked" handler="clocks_shortcuts_stopwatch" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Boxes</property>
<signal name="clicked" handler="shortcuts_boxes_shortcuts" swapped="1" object="window1"/>
<signal name="clicked" handler="boxes_shortcuts" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Boxes - Wizard</property>
<signal name="clicked" handler="shortcuts_boxes_shortcuts_wizard" swapped="1" object="window1"/>
<signal name="clicked" handler="boxes_shortcuts_wizard" swapped="1" object="window1"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Boxes - Display</property>
<signal name="clicked" handler="shortcuts_boxes_shortcuts_display" swapped="1" object="window1"/>
<signal name="clicked" handler="boxes_shortcuts_display" swapped="1" object="window1"/>
</object>
</child>
</object>

View File

@@ -54,7 +54,10 @@ do_sidebar (GtkWidget *do_widget)
stack = gtk_stack_new ();
gtk_stack_set_transition_type (GTK_STACK (stack), GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN);
gtk_stack_sidebar_set_stack (GTK_STACK_SIDEBAR (sidebar), GTK_STACK (stack));
gtk_widget_set_hexpand (stack, TRUE);
/* Separator between sidebar and stack */
widget = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
gtk_container_add (GTK_CONTAINER(box), widget);
gtk_container_add (GTK_CONTAINER (box), stack);
@@ -63,7 +66,6 @@ do_sidebar (GtkWidget *do_widget)
if (i == 0)
{
widget = gtk_image_new_from_icon_name ("org.gtk.Demo4");
gtk_style_context_add_class (gtk_widget_get_style_context (widget), "icon-dropshadow");
gtk_image_set_pixel_size (GTK_IMAGE (widget), 256);
}
else

View File

@@ -11,9 +11,6 @@
#include "puzzlepiece.h"
#include "paintable.h"
/* Give out awards */
#include "award.h"
static GtkWidget *window = NULL;
static GtkWidget *frame = NULL;
static GtkWidget *choices = NULL;
@@ -159,14 +156,6 @@ check_solved (GtkWidget *grid)
picture = gtk_grid_get_child_at (GTK_GRID (grid), pos_x, pos_y);
gtk_picture_set_paintable (GTK_PICTURE (picture), piece);
/* Hand out a bunch of awards
*/
award ("puzzle-solve");
if ((gdk_paintable_get_flags (piece) & GDK_PAINTABLE_STATIC_CONTENTS) == 0)
award ("puzzle-solve-animated");
if (height * width > 20)
award ("puzzle-solve-large");
return TRUE;
}
@@ -412,18 +401,6 @@ add_choice (GtkWidget *choices,
gtk_container_add (GTK_CONTAINER (choices), icon);
}
static void
widget_destroyed (GtkWidget *widget,
GtkWidget **widget_pointer)
{
if (widget_pointer)
*widget_pointer = NULL;
if (!solved)
award ("puzzle-give-up");
}
GtkWidget *
do_sliding_puzzle (GtkWidget *do_widget)
{
@@ -492,7 +469,7 @@ do_sliding_puzzle (GtkWidget *do_widget)
gtk_window_set_titlebar (GTK_WINDOW (window), header);
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
g_signal_connect (window, "destroy",
G_CALLBACK (widget_destroyed), &window);
G_CALLBACK (gtk_widget_destroyed), &window);
frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, (float) gdk_paintable_get_intrinsic_aspect_ratio (puzzle), FALSE);
gtk_container_add (GTK_CONTAINER (window), frame);

View File

@@ -11,9 +11,9 @@
#include <math.h>
#include <stdlib.h>
gint
spinbutton_hex_spin_input (GtkSpinButton *spin_button,
gdouble *new_val)
static gint
hex_spin_input (GtkSpinButton *spin_button,
gdouble *new_val)
{
const gchar *buf;
gchar *err;
@@ -28,8 +28,8 @@ spinbutton_hex_spin_input (GtkSpinButton *spin_button,
return TRUE;
}
gint
spinbutton_hex_spin_output (GtkSpinButton *spin_button)
static gint
hex_spin_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
gchar *buf;
@@ -48,9 +48,9 @@ spinbutton_hex_spin_output (GtkSpinButton *spin_button)
return TRUE;
}
gint
spinbutton_time_spin_input (GtkSpinButton *spin_button,
gdouble *new_val)
static gint
time_spin_input (GtkSpinButton *spin_button,
gdouble *new_val)
{
const gchar *text;
gchar **str;
@@ -87,8 +87,8 @@ spinbutton_time_spin_input (GtkSpinButton *spin_button,
return TRUE;
}
gint
spinbutton_time_spin_output (GtkSpinButton *spin_button)
static gint
time_spin_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
gchar *buf;
@@ -121,9 +121,9 @@ static gchar *month[12] = {
"December"
};
gint
spinbutton_month_spin_input (GtkSpinButton *spin_button,
gdouble *new_val)
static gint
month_spin_input (GtkSpinButton *spin_button,
gdouble *new_val)
{
gint i;
gchar *tmp1, *tmp2;
@@ -150,8 +150,8 @@ spinbutton_month_spin_input (GtkSpinButton *spin_button,
return TRUE;
}
gint
spinbutton_month_spin_output (GtkSpinButton *spin_button)
static gint
month_spin_output (GtkSpinButton *spin_button)
{
GtkAdjustment *adjustment;
gdouble value;
@@ -191,6 +191,15 @@ do_spinbutton (GtkWidget *do_widget)
GtkWidget *label;
builder = gtk_builder_new_from_resource ("/spinbutton/spinbutton.ui");
gtk_builder_add_callback_symbols (builder,
"hex_spin_input", G_CALLBACK (hex_spin_input),
"hex_spin_output", G_CALLBACK (hex_spin_output),
"time_spin_input", G_CALLBACK (time_spin_input),
"time_spin_output", G_CALLBACK (time_spin_output),
"month_spin_input", G_CALLBACK (month_spin_input),
"month_spin_output", G_CALLBACK (month_spin_output),
NULL);
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -83,8 +83,8 @@
<property name="halign">start</property>
<property name="width-chars">4</property>
<property name="adjustment">hex_adjustment</property>
<signal name="input" handler="spinbutton_hex_spin_input"/>
<signal name="output" handler="spinbutton_hex_spin_output"/>
<signal name="input" handler="hex_spin_input"/>
<signal name="output" handler="hex_spin_output"/>
<property name="wrap">1</property>
<layout>
<property name="left-attach">1</property>
@@ -119,8 +119,8 @@
<property name="halign">start</property>
<property name="width-chars">5</property>
<property name="adjustment">time_adjustment</property>
<signal name="input" handler="spinbutton_time_spin_input"/>
<signal name="output" handler="spinbutton_time_spin_output"/>
<signal name="input" handler="time_spin_input"/>
<signal name="output" handler="time_spin_output"/>
<property name="wrap">1</property>
<layout>
<property name="left-attach">1</property>
@@ -154,8 +154,8 @@
<object class="GtkSpinButton" id="month_spin">
<property name="halign">start</property>
<property name="width-chars">9</property>
<signal name="input" handler="spinbutton_month_spin_input"/>
<signal name="output" handler="spinbutton_month_spin_output"/>
<signal name="input" handler="month_spin_input"/>
<signal name="output" handler="month_spin_output"/>
<property name="adjustment">month_adjustment</property>
<property name="wrap">1</property>
<property name="update-policy">if-valid</property>

View File

@@ -18,6 +18,7 @@ do_stack (GtkWidget *do_widget)
GtkBuilder *builder;
builder = gtk_builder_new_from_resource ("/stack/stack.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -1,71 +0,0 @@
/* Text View/Undo and Redo
*
* The GtkTextView supports undo and redo through the use of a
* GtkTextBuffer. You can enable or disable undo support using
* gtk_text_buffer_set_enable_undo().
*
* Use Primary+Z to undo and Primary+Shift+Z or Primary+Y to
* redo previously undone operations.
*/
#include <gtk/gtk.h>
#include <stdlib.h> /* for exit() */
GtkWidget *
do_textundo (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *view;
GtkWidget *sw;
GtkTextBuffer *buffer;
GtkTextIter iter;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window),
450, 450);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
gtk_window_set_title (GTK_WINDOW (window), "TextView Undo");
view = gtk_text_view_new ();
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), GTK_WRAP_WORD);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
gtk_text_buffer_set_enable_undo (buffer, TRUE);
/* this text cannot be undone */
gtk_text_buffer_begin_irreversible_action (buffer);
gtk_text_buffer_get_start_iter (buffer, &iter);
gtk_text_buffer_insert (buffer, &iter,
"Type to add more text.\n"
"Use Primary+Z to undo and Primary+Shift+Z to redo a previously undone action.\n"
"\n",
-1);
gtk_text_buffer_end_irreversible_action (buffer);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (window), sw);
gtk_container_add (GTK_CONTAINER (sw), view);
}
if (!gtk_widget_get_visible (window))
{
gtk_widget_show (window);
}
else
{
gtk_widget_destroy (window);
window = NULL;
}
return window;
}

View File

@@ -128,23 +128,24 @@ insert_text (GtkTextBuffer *buffer)
{
GtkTextIter iter;
GtkTextIter start, end;
GdkPixbuf *pixbuf;
GdkTexture *texture;
GtkIconTheme *icon_theme;
icon_theme = gtk_icon_theme_get_default ();
texture = GDK_TEXTURE (gtk_icon_theme_load_icon (icon_theme,
"gtk3-demo",
32,
GTK_ICON_LOOKUP_GENERIC_FALLBACK,
NULL));
g_assert (texture);
pixbuf = gtk_icon_theme_load_icon (icon_theme,
"gtk3-demo",
32,
GTK_ICON_LOOKUP_GENERIC_FALLBACK,
NULL);
g_assert (pixbuf);
texture = gdk_texture_new_for_pixbuf (pixbuf);
/* get start of buffer; each insertion will revalidate the
* iterator to point to just after the inserted text.
*/
gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
gtk_text_buffer_begin_irreversible_action (buffer);
gtk_text_buffer_insert (buffer, &iter,
"The text widget can display text with all kinds of nifty attributes. "
"It also supports multiple views of the same buffer; this demo is "
@@ -378,8 +379,7 @@ insert_text (GtkTextBuffer *buffer)
gtk_text_buffer_get_bounds (buffer, &start, &end);
gtk_text_buffer_apply_tag_by_name (buffer, "word_wrap", &start, &end);
gtk_text_buffer_end_irreversible_action (buffer);
g_object_unref (pixbuf);
g_object_unref (texture);
}

View File

@@ -285,7 +285,7 @@ user-trash=The icon for the user's “Trash” place in the file system
user-trash-full=The icon for the user's “Trash” in the file system, when there are items in the “Trash” waiting for disposal or recovery
emblem-system=The icon used as an emblem for directories that contain system libraries, settings, and data
avatar-default=The generic avatar icon, which is used to represent a user that doesn't have a personalized avatar
emblem-synchronizing=The icon used as an emblem to indicate that a synchronizing operation is in process
emblem-synchronizing=The icon used as an emblem to indicate that a a synchronizing operation is in process
emblem-shared=The icon used as an emblem for files and directories that are shared to other users
help-browser=The icon used for the desktop's help browsing application

View File

@@ -81,14 +81,11 @@ get_icon (GtkWidget *image, const gchar *name, gint size)
{
GtkIconInfo *info;
GtkStyleContext *context;
GdkTexture *texture;
GdkPixbuf *pixbuf;
context = gtk_widget_get_style_context (image);
info = gtk_icon_theme_lookup_icon (gtk_icon_theme_get_default (), name, size, 0);
texture = GDK_TEXTURE (gtk_icon_info_load_symbolic_for_context (info, context, NULL, NULL));
pixbuf = gdk_pixbuf_get_from_texture (texture);
g_object_unref (texture);
pixbuf = gtk_icon_info_load_symbolic_for_context (info, context, NULL, NULL);
g_object_unref (info);
return pixbuf;

View File

@@ -1,4 +1,3 @@
subdir('constraint-editor')
subdir('gtk-demo')
subdir('icon-browser')
subdir('node-editor')

View File

@@ -26,9 +26,9 @@
static const char *css =
"textview.editor {"
" color: rgb(192, 197, 206);"
" caret-color: currentColor;"
" caret-color: white;"
"}"
"textview.editor > text {"
"textview.editor text {"
" background-color: rgb(43, 48, 59);"
"}"
;

View File

@@ -707,14 +707,6 @@ static void
node_editor_window_unrealize (GtkWidget *widget)
{
NodeEditorWindow *self = NODE_EDITOR_WINDOW (widget);
guint i;
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->renderers)); i ++)
{
gpointer item = g_list_model_get_item (G_LIST_MODEL (self->renderers), i);
gsk_renderer_unrealize (gtk_renderer_paintable_get_renderer (item));
g_object_unref (item);
}
g_list_store_remove_all (self->renderers);

View File

@@ -1003,9 +1003,6 @@ populate_flowbox (GtkWidget *flowbox)
while ((name = g_dir_read_name (dir)) != NULL)
{
if (g_str_has_suffix (name, ".xml"))
continue;
filename = g_build_filename (location, name, NULL);
file = g_file_new_for_path (filename);
stream = G_INPUT_STREAM (g_file_read (file, NULL, &error));
@@ -1020,7 +1017,7 @@ populate_flowbox (GtkWidget *flowbox)
bd = g_new (BackgroundData, 1);
bd->flowbox = flowbox;
bd->filename = filename;
gdk_pixbuf_new_from_stream_at_scale_async (stream, 110, 110, TRUE, NULL,
gdk_pixbuf_new_from_stream_at_scale_async (stream, 110, 110, TRUE, NULL,
background_loaded_cb, bd);
}
@@ -1408,10 +1405,8 @@ text_view_add_to_context_menu (GtkTextView *text_view)
item = g_menu_item_new (_("Underline"), "format.underline");
g_menu_item_set_attribute (item, "touch-icon", "s", "format-text-underline-symbolic");
g_menu_append_item (G_MENU (menu), item);
g_object_unref (item);
gtk_text_view_set_extra_menu (text_view, G_MENU_MODEL (menu));
g_object_unref (menu);
g_signal_connect (gtk_text_view_get_buffer (text_view), "changed", G_CALLBACK (text_changed), NULL);
g_signal_connect (gtk_text_view_get_buffer (text_view), "mark-set", G_CALLBACK (text_changed), NULL);
@@ -1606,14 +1601,14 @@ reset_icon_size (GtkWidget *iv)
gtk_widget_queue_resize (iv);
}
static char *
scale_format_value_blank (GtkScale *scale, double value, gpointer user_data)
static gchar *
scale_format_value_blank (GtkScale *scale, gdouble value)
{
return g_strdup (" ");
}
static char *
scale_format_value (GtkScale *scale, double value, gpointer user_data)
static gchar *
scale_format_value (GtkScale *scale, gdouble value)
{
return g_strdup_printf ("%0.*f", 1, value);
}
@@ -1652,7 +1647,7 @@ set_up_context_popover (GtkWidget *widget,
GtkWidget *popover = gtk_popover_menu_new_from_model (widget, model);
GtkGesture *gesture;
gtk_popover_set_has_arrow (GTK_POPOVER (popover), FALSE);
g_object_set (popover, "has-arrow", FALSE, 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 (clicked_cb), popover);
@@ -1663,7 +1658,6 @@ static void
activate (GApplication *app)
{
GtkBuilder *builder;
GtkBuilderScope *scope;
GtkWindow *window;
GtkWidget *widget;
GtkWidget *widget2;
@@ -1713,28 +1707,26 @@ activate (GApplication *app)
gtk_css_provider_load_from_resource (provider, "/org/gtk/WidgetFactory4/widget-factory.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
GTK_STYLE_PROVIDER_PRIORITY_USER);
g_object_unref (provider);
builder = gtk_builder_new ();
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback_symbols (GTK_BUILDER_CSCOPE (scope),
"on_entry_icon_release", (GCallback)on_entry_icon_release,
"on_scale_button_value_changed", (GCallback)on_scale_button_value_changed,
"on_scale_button_query_tooltip", (GCallback)on_scale_button_query_tooltip,
"on_record_button_toggled", (GCallback)on_record_button_toggled,
"on_page_combo_changed", (GCallback)on_page_combo_changed,
"on_range_from_changed", (GCallback)on_range_from_changed,
"on_range_to_changed", (GCallback)on_range_to_changed,
"tab_close_cb", (GCallback)tab_close_cb,
"increase_icon_size", (GCallback)increase_icon_size,
"decrease_icon_size", (GCallback)decrease_icon_size,
"reset_icon_size", (GCallback)reset_icon_size,
"osd_frame_pressed", (GCallback)osd_frame_pressed,
NULL);
gtk_builder_set_scope (builder, scope);
g_object_unref (scope);
gtk_builder_add_from_resource (builder, "/org/gtk/WidgetFactory4/widget-factory.ui", NULL);
builder = gtk_builder_new_from_resource ("/org/gtk/WidgetFactory4/widget-factory.ui");
gtk_builder_add_callback_symbol (builder, "on_entry_icon_release", (GCallback)on_entry_icon_release);
gtk_builder_add_callback_symbol (builder, "on_scale_button_value_changed", (GCallback)on_scale_button_value_changed);
gtk_builder_add_callback_symbol (builder, "on_scale_button_query_tooltip", (GCallback)on_scale_button_query_tooltip);
gtk_builder_add_callback_symbol (builder, "on_record_button_toggled", (GCallback)on_record_button_toggled);
gtk_builder_add_callback_symbol (builder, "on_page_combo_changed", (GCallback)on_page_combo_changed);
gtk_builder_add_callback_symbol (builder, "on_range_from_changed", (GCallback)on_range_from_changed);
gtk_builder_add_callback_symbol (builder, "on_range_to_changed", (GCallback)on_range_to_changed);
gtk_builder_add_callback_symbol (builder, "tab_close_cb", (GCallback)tab_close_cb);
gtk_builder_add_callback_symbol (builder, "increase_icon_size", (GCallback)increase_icon_size);
gtk_builder_add_callback_symbol (builder, "decrease_icon_size", (GCallback)decrease_icon_size);
gtk_builder_add_callback_symbol (builder, "reset_icon_size", (GCallback)reset_icon_size);
gtk_builder_add_callback_symbol (builder, "scale_format_value", (GCallback)scale_format_value);
gtk_builder_add_callback_symbol (builder, "scale_format_value_blank", (GCallback)scale_format_value_blank);
gtk_builder_add_callback_symbol (builder, "osd_frame_pressed", (GCallback)osd_frame_pressed);
gtk_builder_connect_signals (builder, NULL);
window = (GtkWindow *)gtk_builder_get_object (builder, "window");
gtk_application_add_window (GTK_APPLICATION (app), window);
@@ -1951,12 +1943,6 @@ activate (GApplication *app)
widget = (GtkWidget *)gtk_builder_get_object (builder, "extra_info_entry");
g_timeout_add (100, (GSourceFunc)pulse_it, widget);
widget = (GtkWidget *)gtk_builder_get_object (builder, "scale3");
gtk_scale_set_format_value_func (GTK_SCALE (widget), scale_format_value, NULL, NULL);
widget = (GtkWidget *)gtk_builder_get_object (builder, "scale4");
gtk_scale_set_format_value_func (GTK_SCALE (widget), scale_format_value_blank, NULL, NULL);
widget = (GtkWidget *)gtk_builder_get_object (builder, "box_for_context");
model = (GMenuModel *)gtk_builder_get_object (builder, "new_style_context_menu_model");
set_up_context_popover (widget, model);

View File

@@ -598,6 +598,10 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="label" translatable="yes">checkbutton</property>
<property name="can-focus">1</property>
<property name="active">1</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
@@ -662,8 +666,8 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="can-focus">1</property>
<property name="active">1</property>
<layout>
<property name="left-attach">0</property>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
@@ -736,6 +740,7 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="active">1</property>
<layout>
<property name="left-attach">2</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
@@ -966,11 +971,11 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="adjustment">adjustment3</property>
<property name="restrict-to-fill-level">0</property>
<marks>
<mark value="0" position="bottom"></mark>
<mark value="1" position="bottom"></mark>
<mark value="2" position="bottom"></mark>
<mark value="3" position="bottom"></mark>
<mark value="4" position="bottom"></mark>
<mark value="0" position="bottom"/>
<mark value="1" position="bottom"/>
<mark value="2" position="bottom"/>
<mark value="3" position="bottom"/>
<mark value="4" position="bottom"/>
</marks>
</object>
</child>
@@ -1014,6 +1019,7 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="fill-level">75</property>
<property name="digits">-1</property>
<property name="halign">end</property>
<signal name="format-value" handler="scale_format_value"/>
</object>
</child>
<child>
@@ -1027,6 +1033,7 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="fill-level">75</property>
<property name="digits">-1</property>
<property name="halign">start</property>
<signal name="format-value" handler="scale_format_value_blank"/>
</object>
</child>
</object>
@@ -1500,6 +1507,10 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="valign">center</property>
<property name="value">.5</property>
<property name="halign">center</property>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
@@ -1515,6 +1526,7 @@ microphone-sensitivity-medium-symbolic</property>
<signal name="query-tooltip" handler="on_scale_button_query_tooltip" swapped="no"/>
<signal name="value-changed" handler="on_scale_button_value_changed" swapped="no"/>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
@@ -1565,7 +1577,7 @@ microphone-sensitivity-medium-symbolic</property>
<property name="icon-name">org.gtk.WidgetFactory4</property>
<property name="pixel-size">256</property>
<style>
<class name="icon-dropshadow"/>
<class name="icon-dropshadow" />
</style>
</object>
</property>
@@ -1716,11 +1728,15 @@ microphone-sensitivity-medium-symbolic</property>
</object>
</child>
<child>
<object class="GtkSpinButton">
<property name="adjustment">adjustment1</property>
<property name="hexpand">1</property>
<object class="GtkImage">
<property name="icon-name">object-select-symbolic</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="opacity">0</property>
</object>
</child>
</object>
@@ -1895,11 +1911,11 @@ microphone-sensitivity-medium-symbolic</property>
</object>
</child>
<child>
<object class="GtkMenuItem" id="checksmenuitem">
<property name="label">_Checks</property>
<object class="GtkMenuItem" id="togglesmenuitem">
<property name="label">Checks &amp; Radios</property>
<property name="use-underline">1</property>
<child type="submenu">
<object class="GtkMenu" id="checkssubmenu">
<object class="GtkMenu" id="togglessubmenu">
<child>
<object class="GtkCheckMenuItem" id="checkmenuitem1">
<property name="label">_Check</property>
@@ -1943,16 +1959,9 @@ microphone-sensitivity-medium-symbolic</property>
<property name="use-underline">1</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuItem" id="radiosmenuitem">
<property name="label">_Radios</property>
<property name="use-underline">1</property>
<child type="submenu">
<object class="GtkMenu" id="radiossubmenu">
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem"/>
</child>
<child>
<object class="GtkRadioMenuItem" id="radiomenuitem1">
<property name="label">_Radio</property>
@@ -2111,7 +2120,7 @@ microphone-sensitivity-medium-symbolic</property>
<object class="GtkInfoBar" id="infobar">
<property name="visible">0</property>
<property name="show-close-button">1</property>
<child>
<child internal-child="content_area">
<object class="GtkBox">
<child>
<object class="GtkLabel">
@@ -2122,11 +2131,9 @@ microphone-sensitivity-medium-symbolic</property>
</child>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="shadow-type">in</property>
<property name="vexpand">1</property>
<child>
<object class="MyTextView" id="text3">
@@ -2140,9 +2147,6 @@ microphone-sensitivity-medium-symbolic</property>
</child>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkStatusbar" id="statusbar"/>
</child>
@@ -2433,9 +2437,11 @@ microphone-sensitivity-medium-symbolic</property>
<property name="spacing">10</property>
<child>
<object class="GtkBox">
<property name="halign">fill</property>
<property name="spacing">6</property>
<child>
<object class="GtkBox" id="lockbox">
<property name="halign">fill</property>
<property name="hexpand">1</property>
<property name="spacing">6</property>
<child>
@@ -2512,6 +2518,9 @@ microphone-sensitivity-medium-symbolic</property>
<object class="GtkMenuButton">
<property name="icon-name">view-more-symbolic</property>
<property name="popover">new_style_menu</property>
<!--
<property name="menu-model">new_style_menu_model</property>
-->
</object>
</child>
</object>
@@ -3346,6 +3355,10 @@ bad things might happen.</property>
<accessibility>
<relation type="label-for" target="open_popover_entry"/>
</accessibility>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
@@ -3357,6 +3370,7 @@ bad things might happen.</property>
<relation type="label-for" target="open_popover_textview"/>
</accessibility>
<layout>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
@@ -3391,6 +3405,7 @@ bad things might happen.</property>
</accessibility>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
<property name="column-span">2</property>
</layout>
</object>
@@ -3420,7 +3435,6 @@ bad things might happen.</property>
<property name="halign">end</property>
<property name="icon-name">emblem-system-symbolic</property>
<property name="menu-model">gear_menu</property>
<property name="tooltip-text">This is a menu button</property>
<layout>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
@@ -3429,6 +3443,7 @@ bad things might happen.</property>
</child>
<child>
<object class="GtkButton" id="open_popover_button">
<property name="halign">fill</property>
<property name="label">_Open</property>
<property name="use-underline">1</property>
<property name="sensitive">0</property>
@@ -3477,7 +3492,7 @@ bad things might happen.</property>
<property name="autohide">0</property>
<child>
<object class="GtkLabel">
<property name="label">You&apos;re in too deep!</property>
<property name="label">You're in too deep!</property>
<accessibility>
<role type="static"/>
</accessibility>
@@ -3488,6 +3503,7 @@ bad things might happen.</property>
<property name="autohide">0</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<child>
<object class="GtkLabel">
<property name="label">Hidden gems:</property>
@@ -3507,246 +3523,222 @@ bad things might happen.</property>
</object>
</child>
</object>
<object class="GtkPopover" id="new_style_menu">
<object class="GtkPopoverMenu" id="new_style_menu">
<child>
<object class="GtkStack">
<object class="GtkBox">
<property name="name">main</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkStackPage">
<property name="name">main</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<style>
<class name="circular-buttons"/>
</style>
<child>
<object class="GtkModelButton">
<property name="icon">
<object class="GThemedIcon">
<property name="name">printer-symbolic</property>
</object>
</property>
<property name="iconic">1</property>
<property name="action-name">app.print</property>
<property name="hexpand">1</property>
<property name="halign">center</property>
<style>
<class name="circular"/>
</style>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon">
<object class="GThemedIcon">
<property name="name">emblem-shared-symbolic</property>
</object>
</property>
<property name="iconic">1</property>
<property name="action-name">app.share</property>
<property name="hexpand">1</property>
<property name="halign">center</property>
<style>
<class name="circular"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Open in New Window</property>
<property name="action-name">app.open-in</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkBox">
<style>
<class name="inline-buttons"/>
</style>
<child>
<object class="GtkLabel" id="cut_copy_paste_filler"/>
</child>
<child>
<object class="GtkLabel">
<property name="label">Edit</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon">
<object class="GThemedIcon">
<property name="name">edit-cut-symbolic</property>
</object>
</property>
<property name="iconic">1</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon">
<object class="GThemedIcon">
<property name="name">edit-copy-symbolic</property>
</object>
</property>
<property name="iconic">1</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon">
<object class="GThemedIcon">
<property name="name">edit-paste-symbolic</property>
</object>
</property>
<property name="iconic">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Pin</property>
<property name="action-name">app.pin</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Select Labels…</property>
<property name="action-name">app.labels</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Share…</property>
<property name="action-name">app.share</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Basement</property>
<property name="menu-name">basement</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Large</property>
<property name="action-name">app.size</property>
<property name="action-target">&apos;large&apos;</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Medium</property>
<property name="action-name">app.size</property>
<property name="action-target">&apos;medium&apos;</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Small</property>
<property name="action-name">app.size</property>
<property name="action-target">&apos;small&apos;</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Move to Trash</property>
<property name="action-name">win.delete</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<object class="GtkBox">
<property name="halign">fill</property>
<style>
<class name="circular-buttons"/>
</style>
<child>
<object class="GtkModelButton">
<property name="icon"><object class="GThemedIcon"><property name="name">printer-symbolic</property></object></property>
<property name="iconic">1</property>
<property name="action-name">app.print</property>
<property name="hexpand">1</property>
<property name="halign">center</property>
<style>
<class name="circular"/>
</style>
</object>
</property>
</child>
<child>
<object class="GtkModelButton">
<property name="icon"><object class="GThemedIcon"><property name="name">emblem-shared-symbolic</property></object></property>
<property name="iconic">1</property>
<property name="action-name">app.share</property>
<property name="hexpand">1</property>
<property name="halign">center</property>
<style>
<class name="circular"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">basement</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkModelButton">
<property name="text">Basement</property>
<property name="role">title</property>
<property name="menu-name">main</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Berk</property>
<property name="action-name">app.berk</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Broni</property>
<property name="action-name">app.broni</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Drutt</property>
<property name="action-name">app.drutt</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">The Thing Upstairs</property>
<property name="action-name">app.upstairs</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Open in New Window</property>
<property name="action-name">app.open-in</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkBox">
<style>
<class name="inline-buttons"/>
</style>
<child>
<object class="GtkLabel" id="cut_copy_paste_filler">
</object>
</property>
</child>
<child>
<object class="GtkLabel">
<property name="label">Edit</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon"><object class="GThemedIcon"><property name="name">edit-cut-symbolic</property></object></property>
<property name="iconic">1</property>
<property name="relief">none</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon"><object class="GThemedIcon"><property name="name">edit-copy-symbolic</property></object></property>
<property name="iconic">1</property>
<property name="relief">none</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="icon"><object class="GThemedIcon"><property name="name">edit-paste-symbolic</property></object></property>
<property name="iconic">1</property>
<property name="relief">none</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Pin</property>
<property name="action-name">app.pin</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Select Labels…</property>
<property name="action-name">app.labels</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Share…</property>
<property name="action-name">app.share</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Basement</property>
<property name="menu-name">basement</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Large</property>
<property name="action-name">app.size</property>
<property name="action-target">'large'</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Medium</property>
<property name="action-name">app.size</property>
<property name="action-target">'medium'</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Small</property>
<property name="action-name">app.size</property>
<property name="action-target">'small'</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Move to Trash</property>
<property name="action-name">win.delete</property>
<property name="indicator-size-group">main-indicators</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="name">basement</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkModelButton">
<property name="text">Basement</property>
<property name="role">title</property>
<property name="menu-name">main</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Berk</property>
<property name="action-name">app.berk</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Broni</property>
<property name="action-name">app.broni</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">Drutt</property>
<property name="action-name">app.drutt</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
<child>
<object class="GtkModelButton">
<property name="text">The Thing Upstairs</property>
<property name="action-name">app.upstairs</property>
<property name="indicator-size-group">basement-indicators</property>
</object>
</child>
</object>
</child>
</object>
<object class="GtkSizeGroup" id="main-indicators">
<property name="mode">horizontal</property>
<widgets>
<widget name="cut_copy_paste_filler"/>
</widgets>
</object>
<object class="GtkSizeGroup" id="basement-indicators"/>
<object class="GtkSizeGroup" id="basement-indicators">
<property name="mode">horizontal</property>
</object>
<menu id="new_style_menu_model">
<section>
<attribute name="display-hint">circular-buttons</attribute>
@@ -3836,10 +3828,10 @@ bad things might happen.</property>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Move to Trash</attribute>
<attribute name="action">win.delete</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Move to Trash</attribute>
<attribute name="action">win.delete</attribute>
</item>
</section>
</menu>
<menu id="new_style_context_menu_model">
@@ -3953,7 +3945,7 @@ bad things might happen.</property>
</section>
<section>
<submenu>
<attribute name="label" translatable="yes">C_hecks</attribute>
<attribute name="label" translatable="yes">Checks &amp; Radios</attribute>
<section>
<item>
<attribute name="label" translatable="yes">Check</attribute>
@@ -3977,9 +3969,6 @@ bad things might happen.</property>
<attribute name="hidden-when">action-missing</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_Radios</attribute>
<section>
<item>
<attribute name="label" translatable="yes">Radio</attribute>
@@ -4030,13 +4019,14 @@ bad things might happen.</property>
<attribute name="action">win.background</attribute>
</item>
</section>
</submenu>
<submenu>
<attribute name="label" translatable="yes">_Help</attribute>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.about</attribute>
</item>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.about</attribute>
</item>
</submenu>
</menu>
</interface>

View File

@@ -192,8 +192,8 @@ gdk_surface_is_destroyed
gdk_surface_is_visible
gdk_surface_is_viewable
gdk_surface_get_state
gdk_surface_minimize
gdk_surface_unminimize
gdk_surface_iconify
gdk_surface_deiconify
gdk_surface_stick
gdk_surface_unstick
gdk_surface_maximize
@@ -789,6 +789,8 @@ gdk_drop_get_type
</SECTION>
<SECTION>
<INCLUDE>gdk/gdkx.h</INCLUDE>
<TITLE>X Window System Interaction</TITLE>
<FILE>x_interaction</FILE>
GDK_SURFACE_XID
GDK_DISPLAY_XDISPLAY
@@ -939,6 +941,8 @@ gdk_surface_impl_x11_get_type
</SECTION>
<SECTION>
<INCLUDE>gdk/gdkwayland.h</INCLUDE>
<TITLE>Wayland Interaction</TITLE>
<FILE>wayland_interaction</FILE>
gdk_wayland_seat_get_wl_seat
gdk_wayland_device_get_wl_keyboard
@@ -1124,7 +1128,6 @@ gdk_monitor_get_width_mm
gdk_monitor_get_height_mm
gdk_monitor_get_manufacturer
gdk_monitor_get_model
gdk_monitor_get_connector
gdk_monitor_get_scale_factor
gdk_monitor_get_refresh_rate
GdkSubpixelLayout

View File

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

View File

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

View File

@@ -258,11 +258,9 @@
</para>
<para>
Actions are added to their relevant scope (application,
window or widget) either using the GActionMap interface,
or by using gtk_widget_insert_action_group(). Actions that
will be the same for all instances of a widget class can
be added globally using gtk_widget_class_install_action().
Actions are added to their relevant scope (application or
window) either using the GActionMap interface, or by using
gtk_widget_insert_action_group().
</para>
</refsect2>
@@ -319,8 +317,8 @@
</para>
<para>
Another way of obtaining widgets that are connected to actions
is to create a menu using a GMenu menu model. GMenu provides an
Another of obtaining widgets that are connected to actions is
to create a menu using a GMenu menu model. GMenu provides an
abstract way to describe typical menus: nested groups of items
where each item can have a label, and icon, and an action.
</para>
@@ -366,25 +364,6 @@
(typically a GtkWindow, GtkDialog or GtkPopover)
</para></listitem>
</varlistentry>
<varlistentry>
<term>clipboard.cut, clipboard.copy, clipboard.paste</term>
<listitem><para>Clipboard operations on entries, text view
and labels, typically used in the context menu
</para></listitem>
</varlistentry>
<varlistentry>
<term>selection.delete, selection.select-all</term>
<listitem><para>Selection operations on entries, text view
and labels
</para></listitem>
</varlistentry>
<varlistentry>
<term>color.select, color.customize</term>
<listitem><para>Operations on colors in GtkColorChooserWidget.
These actions are unusual in that they have the non-trivial
parameter type (dddd).
</para></listitem>
</varlistentry>
</variablelist>
</para>

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