Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b8d7777cc4 | |||
| c4edc28542 | |||
| b4e0bae7dc |
@@ -1,11 +0,0 @@
|
||||
# See https://wiki.apertis.org/Guidelines/Coding_conventions#Code_formatting
|
||||
BasedOnStyle: GNU
|
||||
AlwaysBreakAfterDefinitionReturnType: All
|
||||
BreakBeforeBinaryOperators: None
|
||||
BinPackParameters: false
|
||||
SpaceAfterCStyleCast: true
|
||||
# Our column limit is actually 80, but setting that results in clang-format
|
||||
# making a lot of dubious hanging-indent choices; disable it and assume the
|
||||
# developer will line wrap appropriately. clang-format will still check
|
||||
# existing hanging indents.
|
||||
ColumnLimit: 0
|
||||
+28
-156
@@ -1,7 +1,5 @@
|
||||
stages:
|
||||
- build
|
||||
- analysis
|
||||
- docs
|
||||
- flatpak
|
||||
- deploy
|
||||
|
||||
@@ -14,114 +12,40 @@ stages:
|
||||
- subprojects/libepoxy/
|
||||
- subprojects/pango/
|
||||
|
||||
# Common variables
|
||||
variables:
|
||||
COMMON_MESON_FLAGS: "--fatal-meson-warnings --werror"
|
||||
MESON_TEST_TIMEOUT_MULTIPLIER: 2
|
||||
|
||||
.only-default:
|
||||
only:
|
||||
- branches
|
||||
except:
|
||||
- tags
|
||||
|
||||
style-check-diff:
|
||||
extends: .only-default
|
||||
image: registry.gitlab.gnome.org/gnome/gtk/fedora:v17
|
||||
stage: .pre
|
||||
allow_failure: true
|
||||
fedora-x86_64:
|
||||
image: registry.gitlab.gnome.org/gnome/gtk/master:v2
|
||||
stage: build
|
||||
script:
|
||||
- .gitlab-ci/run-style-check-diff.sh
|
||||
|
||||
.build-fedora-default:
|
||||
image: registry.gitlab.gnome.org/gnome/gtk/fedora:v17
|
||||
- bash -x ./.gitlab-ci/test-docker.sh
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
junit:
|
||||
- "${CI_PROJECT_DIR}/_build/report-x11.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-wayland.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-broadway.xml"
|
||||
when: on_failure
|
||||
name: "gtk-${CI_COMMIT_REF_NAME}"
|
||||
paths:
|
||||
- "${CI_PROJECT_DIR}/_build/meson-logs"
|
||||
- "${CI_PROJECT_DIR}/_build/report*.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report*.html"
|
||||
- "${CI_PROJECT_DIR}/_build/testsuite/reftests/output/*/*.png"
|
||||
- "${CI_PROJECT_DIR}/_build/testsuite/gsk/compare/*/*/*.png"
|
||||
- "${CI_PROJECT_DIR}/_build/testsuite/css/output/*/*.syscap"
|
||||
cache:
|
||||
key: "$CI_JOB_NAME"
|
||||
paths:
|
||||
- _ccache/
|
||||
- subprojects/gdk-pixbuf/
|
||||
- subprojects/glib/
|
||||
- subprojects/graphene/
|
||||
- subprojects/libepoxy/
|
||||
- subprojects/pango/
|
||||
<<: *cache-paths
|
||||
|
||||
fedora-x86_64:
|
||||
extends: .build-fedora-default
|
||||
stage: build
|
||||
variables:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=debug --default-library=both"
|
||||
script:
|
||||
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS}
|
||||
-Dx11-backend=true
|
||||
-Dwayland-backend=true
|
||||
-Dbroadway-backend=true
|
||||
-Dvulkan=yes
|
||||
-Dprofiler=true
|
||||
_build
|
||||
- ninja -C _build
|
||||
- .gitlab-ci/run-tests.sh _build x11
|
||||
- .gitlab-ci/run-tests.sh _build wayland
|
||||
- .gitlab-ci/run-tests.sh _build broadway
|
||||
|
||||
release-build:
|
||||
extends: .build-fedora-default
|
||||
stage: build
|
||||
variables:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=release"
|
||||
script:
|
||||
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS}
|
||||
-Dx11-backend=true
|
||||
-Dwayland-backend=true
|
||||
-Dbroadway-backend=true
|
||||
-Dvulkan=yes
|
||||
_build
|
||||
- ninja -C _build
|
||||
- .gitlab-ci/run-tests.sh _build x11
|
||||
|
||||
.mingw-defaults:
|
||||
.mingw-defaults: &mingw-defaults
|
||||
stage: build
|
||||
tags:
|
||||
- win32-ps
|
||||
- win32
|
||||
script:
|
||||
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
|
||||
- C:\msys64\usr\bin\bash -lc "bash -x ./.gitlab-ci/test-msys2.sh"
|
||||
cache:
|
||||
key: "$CI_JOB_NAME"
|
||||
paths:
|
||||
- _ccache/
|
||||
- subprojects/gdk-pixbuf/
|
||||
- subprojects/glib/
|
||||
- subprojects/graphene/
|
||||
- subprojects/libepoxy/
|
||||
- subprojects/pango/
|
||||
key: "%CI_JOB_NAME%"
|
||||
<<: *cache-paths
|
||||
|
||||
msys2-mingw32:
|
||||
extends: .mingw-defaults
|
||||
variables:
|
||||
MSYSTEM: "MINGW32"
|
||||
CHERE_INVOKING: "yes"
|
||||
<<: *mingw-defaults
|
||||
|
||||
.flatpak-defaults:
|
||||
.flatpak-defaults: &flatpak-defaults
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master
|
||||
stage: flatpak
|
||||
allow_failure: true
|
||||
tags:
|
||||
- flatpak
|
||||
artifacts:
|
||||
paths:
|
||||
- "${APPID}-dev.flatpak"
|
||||
@@ -129,80 +53,28 @@ msys2-mingw32:
|
||||
script:
|
||||
- bash -x ./.gitlab-ci/flatpak-build.sh "${APPID}"
|
||||
|
||||
# Manual jobs, for branches and MRs
|
||||
.flatpak-manual:
|
||||
extends: .flatpak-defaults
|
||||
when: manual
|
||||
|
||||
# Only build Flatpak bundles automatically on master
|
||||
.flatpak-master:
|
||||
extends: .flatpak-defaults
|
||||
only:
|
||||
- master
|
||||
|
||||
flatpak-manual:demo:
|
||||
extends: .flatpak-manual
|
||||
flatpak:demo:
|
||||
variables:
|
||||
APPID: org.gtk.Demo4
|
||||
APPID: org.gtk.Demo
|
||||
<<: *flatpak-defaults
|
||||
|
||||
flatpak-master:demo:
|
||||
extends: .flatpak-master
|
||||
flatpak:widget-factory:
|
||||
variables:
|
||||
APPID: org.gtk.Demo4
|
||||
|
||||
flatpak-manual:widget-factory:
|
||||
extends: .flatpak-manual
|
||||
variables:
|
||||
APPID: org.gtk.WidgetFactory4
|
||||
|
||||
flatpak-master:widget-factory:
|
||||
extends: .flatpak-master
|
||||
variables:
|
||||
APPID: org.gtk.WidgetFactory4
|
||||
|
||||
flatpak-manual:icon-browser:
|
||||
extends: .flatpak-manual
|
||||
variables:
|
||||
APPID: org.gtk.IconBrowser4
|
||||
|
||||
flatpak-master:icon-browser:
|
||||
extends: .flatpak-master
|
||||
variables:
|
||||
APPID: org.gtk.IconBrowser4
|
||||
|
||||
static-scan:
|
||||
image: registry.gitlab.gnome.org/gnome/gtk/fedora:v16
|
||||
stage: analysis
|
||||
variables:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=debug"
|
||||
script:
|
||||
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} _scan_build
|
||||
- ninja -C _scan_build scan-build
|
||||
artifacts:
|
||||
paths:
|
||||
- _scan_build/meson-logs
|
||||
allow_failure: true
|
||||
|
||||
reference:
|
||||
image: registry.gitlab.gnome.org/gnome/gtk/fedora-docs:v19
|
||||
stage: docs
|
||||
variables:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=release"
|
||||
script:
|
||||
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} -Dgtk_doc=true _build
|
||||
- ninja -C _build gdk4-doc gsk4-doc gtk4-doc
|
||||
- mkdir -p _reference/
|
||||
- mv _build/docs/reference/gdk/html/ _reference/gdk/
|
||||
- mv _build/docs/reference/gsk/html/ _reference/gsk/
|
||||
- mv _build/docs/reference/gtk/html/ _reference/gtk/
|
||||
artifacts:
|
||||
paths:
|
||||
- _reference
|
||||
APPID: org.gtk.WidgetFactory
|
||||
<<: *flatpak-defaults
|
||||
|
||||
pages:
|
||||
stage: deploy
|
||||
image: registry.gitlab.gnome.org/gnome/gtk/master:v2
|
||||
stage: deploy
|
||||
script:
|
||||
- mv _reference/ public/
|
||||
- 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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
FROM fedora:31
|
||||
FROM fedora:29
|
||||
|
||||
RUN dnf -y install \
|
||||
hicolor-icon-theme \
|
||||
adwaita-icon-theme \
|
||||
atk-devel \
|
||||
at-spi2-atk-devel \
|
||||
@@ -8,15 +9,9 @@ RUN dnf -y install \
|
||||
cairo-devel \
|
||||
cairo-gobject-devel \
|
||||
ccache \
|
||||
clang \
|
||||
clang-analyzer \
|
||||
colord-devel \
|
||||
cups-devel \
|
||||
dbus-daemon \
|
||||
dbus-x11 \
|
||||
dejavu-sans-mono-fonts \
|
||||
desktop-file-utils \
|
||||
diffutils \
|
||||
elfutils-libelf-devel \
|
||||
fribidi-devel \
|
||||
gcc \
|
||||
@@ -26,7 +21,6 @@ RUN dnf -y install \
|
||||
gettext \
|
||||
git \
|
||||
glib2-devel \
|
||||
glib2-static \
|
||||
glibc-devel \
|
||||
glibc-headers \
|
||||
gobject-introspection-devel \
|
||||
@@ -36,7 +30,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 \
|
||||
@@ -57,7 +50,6 @@ RUN dnf -y install \
|
||||
libxkbcommon-devel \
|
||||
libXrandr-devel \
|
||||
libXrender-devel \
|
||||
libXtst-devel \
|
||||
libxslt \
|
||||
mesa-dri-drivers \
|
||||
mesa-libEGL-devel \
|
||||
@@ -65,24 +57,26 @@ RUN dnf -y install \
|
||||
ninja-build \
|
||||
pango-devel \
|
||||
pcre-devel \
|
||||
pcre-static \
|
||||
python3 \
|
||||
python3-jinja2 \
|
||||
python3-pip \
|
||||
python3-pygments \
|
||||
python3-wheel \
|
||||
redhat-rpm-config \
|
||||
sassc \
|
||||
sysprof-devel \
|
||||
systemtap-sdt-devel \
|
||||
vulkan-devel \
|
||||
wayland-devel \
|
||||
wayland-protocols-devel \
|
||||
weston \
|
||||
weston-libs \
|
||||
which \
|
||||
xorg-x11-server-Xvfb \
|
||||
&& dnf clean all
|
||||
|
||||
RUN pip3 install meson==0.53.1
|
||||
RUN pip3 install meson==0.49.0
|
||||
|
||||
ARG HOST_USER_ID=5555
|
||||
ENV HOST_USER_ID ${HOST_USER_ID}
|
||||
RUN useradd -u $HOST_USER_ID -ms /bin/bash user
|
||||
|
||||
USER user
|
||||
WORKDIR /home/user
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
@@ -1,38 +0,0 @@
|
||||
## GTK CI infrastructure
|
||||
|
||||
GTK uses different CI images depending on platform and jobs.
|
||||
|
||||
The CI images are Docker containers, generated either using `docker` or
|
||||
`podman`, and pushed to the GitLab [container registry][registry].
|
||||
|
||||
Each Docker image has a tag composed of two parts:
|
||||
|
||||
- `${image}`: the base image for a given platform, like "fedora" or
|
||||
"debian-stable"
|
||||
- `${number}`: an incremental version number, or `latest`
|
||||
|
||||
See the [container registry][registry] for the available images for each
|
||||
branch, as well as their available versions.
|
||||
|
||||
### Checklist for Updating a CI image
|
||||
|
||||
- [ ] Update the `${image}.Dockerfile` file with the dependencies
|
||||
- [ ] Run `./run-docker.sh build --base ${image} --base-version ${number}`
|
||||
- [ ] Run `./run-docker.sh push --base ${image} --base-version ${number}`
|
||||
once the Docker image is built; you may need to log in by using
|
||||
`docker login` or `podman login`
|
||||
- [ ] Update the `image` keys in the `.gitlab-ci.yml` file with the new
|
||||
image tag
|
||||
- [ ] Open a merge request with your changes and let it run
|
||||
|
||||
### Checklist for Adding a new CI image
|
||||
|
||||
- [ ] Write a new `${image}.Dockerfile` with the instructions to set up
|
||||
a build environment
|
||||
- [ ] Add the `pip3 install meson` incantation
|
||||
- [ ] Run `./run-docker.sh build --base ${image} --base-version ${number}`
|
||||
- [ ] Run `./run-docker.sh push --base ${image} --base-version ${number}`
|
||||
- [ ] Add the new job to `.gitlab-ci.yml` referencing the image
|
||||
- [ ] Open a merge request with your changes and let it run
|
||||
|
||||
[registry]: https://gitlab.gnome.org/GNOME/gtk/container_registry
|
||||
@@ -1,133 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# === clang-format-diff.py - ClangFormat Diff Reformatter ---*- python -*-=== #
|
||||
#
|
||||
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
#
|
||||
# ===---------------------------------------------------------------------=== #
|
||||
|
||||
"""
|
||||
This script reads input from a unified diff and reformats all the changed
|
||||
lines. This is useful to reformat all the lines touched by a specific patch.
|
||||
Example usage for git/svn users:
|
||||
|
||||
git diff -U0 --no-color HEAD^ | clang-format-diff.py -p1 -i
|
||||
svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import argparse
|
||||
import difflib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
if sys.version_info.major >= 3:
|
||||
from io import StringIO
|
||||
else:
|
||||
from io import BytesIO as StringIO
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.add_argument('-i', action='store_true', default=False,
|
||||
help='apply edits to files instead of displaying a '
|
||||
'diff')
|
||||
parser.add_argument('-p', metavar='NUM', default=0,
|
||||
help='strip the smallest prefix containing P slashes')
|
||||
parser.add_argument('-regex', metavar='PATTERN', default=None,
|
||||
help='custom pattern selecting file paths to reformat '
|
||||
'(case sensitive, overrides -iregex)')
|
||||
parser.add_argument('-iregex', metavar='PATTERN',
|
||||
default=r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hh|hpp|m|mm|inc'
|
||||
r'|js|ts|proto|protodevel|java|cs)',
|
||||
help='custom pattern selecting file paths to reformat '
|
||||
'(case insensitive, overridden by -regex)')
|
||||
parser.add_argument('-sort-includes', action='store_true', default=False,
|
||||
help='let clang-format sort include blocks')
|
||||
parser.add_argument('-v', '--verbose', action='store_true',
|
||||
help='be more verbose, ineffective without -i')
|
||||
parser.add_argument('-style',
|
||||
help='formatting style to apply (LLVM, Google, '
|
||||
'Chromium, Mozilla, WebKit)')
|
||||
parser.add_argument('-binary', default='clang-format',
|
||||
help='location of binary to use for clang-format')
|
||||
args = parser.parse_args()
|
||||
|
||||
# Extract changed lines for each file.
|
||||
filename = None
|
||||
lines_by_file = {}
|
||||
for line in sys.stdin:
|
||||
match = re.search(r'^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line)
|
||||
if match:
|
||||
filename = match.group(2)
|
||||
if filename is None:
|
||||
continue
|
||||
|
||||
if args.regex is not None:
|
||||
if not re.match('^%s$' % args.regex, filename):
|
||||
continue
|
||||
else:
|
||||
if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
|
||||
continue
|
||||
|
||||
match = re.search(r'^@@.*\+(\d+)(,(\d+))?', line)
|
||||
if match:
|
||||
start_line = int(match.group(1))
|
||||
line_count = 1
|
||||
if match.group(3):
|
||||
line_count = int(match.group(3))
|
||||
if line_count == 0:
|
||||
continue
|
||||
end_line = start_line + line_count - 1
|
||||
lines_by_file.setdefault(filename, []).extend(
|
||||
['-lines', str(start_line) + ':' + str(end_line)])
|
||||
|
||||
# Reformat files containing changes in place.
|
||||
# We need to count amount of bytes generated in the output of
|
||||
# clang-format-diff. If clang-format-diff doesn't generate any bytes it
|
||||
# means there is nothing to format.
|
||||
format_line_counter = 0
|
||||
for filename, lines in lines_by_file.items():
|
||||
if args.i and args.verbose:
|
||||
print('Formatting {}'.format(filename))
|
||||
command = [args.binary, filename]
|
||||
if args.i:
|
||||
command.append('-i')
|
||||
if args.sort_includes:
|
||||
command.append('-sort-includes')
|
||||
command.extend(lines)
|
||||
if args.style:
|
||||
command.extend(['-style', args.style])
|
||||
p = subprocess.Popen(command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=None,
|
||||
stdin=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
stdout, _ = p.communicate()
|
||||
if p.returncode != 0:
|
||||
sys.exit(p.returncode)
|
||||
|
||||
if not args.i:
|
||||
with open(filename) as f:
|
||||
code = f.readlines()
|
||||
formatted_code = StringIO(stdout).readlines()
|
||||
diff = difflib.unified_diff(code, formatted_code,
|
||||
filename, filename,
|
||||
'(before formatting)',
|
||||
'(after formatting)')
|
||||
diff_string = ''.join(diff)
|
||||
if diff_string:
|
||||
format_line_counter += sys.stdout.write(diff_string)
|
||||
|
||||
if format_line_counter > 0:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,12 +0,0 @@
|
||||
FROM registry.gitlab.gnome.org/gnome/gtk/fedora-base:v19
|
||||
|
||||
RUN dnf -y install pandoc
|
||||
|
||||
ARG HOST_USER_ID=5555
|
||||
ENV HOST_USER_ID ${HOST_USER_ID}
|
||||
RUN useradd -u $HOST_USER_ID -ms /bin/bash user
|
||||
|
||||
USER user
|
||||
WORKDIR /home/user
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
@@ -1,10 +0,0 @@
|
||||
FROM registry.gitlab.gnome.org/gnome/gtk/fedora-base:v19
|
||||
|
||||
ARG HOST_USER_ID=5555
|
||||
ENV HOST_USER_ID ${HOST_USER_ID}
|
||||
RUN useradd -u $HOST_USER_ID -ms /bin/bash user
|
||||
|
||||
USER user
|
||||
WORKDIR /home/user
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
+13
-11
@@ -4,19 +4,20 @@ set -e
|
||||
|
||||
appid=$1
|
||||
|
||||
builddir=flatpak_app
|
||||
builddir=app
|
||||
repodir=repo
|
||||
|
||||
flatpak-builder \
|
||||
--user --disable-rofiles-fuse \
|
||||
--stop-at=gtk \
|
||||
${builddir} \
|
||||
build-aux/flatpak/${appid}.json
|
||||
|
||||
flatpak build ${builddir} meson \
|
||||
--prefix=/app \
|
||||
--libdir=/app/lib \
|
||||
--buildtype=release \
|
||||
flatpak-builder \
|
||||
--run ${builddir} build-aux/flatpak/${appid}.json \
|
||||
meson \
|
||||
--prefix /app \
|
||||
--libdir /app/lib \
|
||||
--buildtype debug \
|
||||
-Dx11-backend=true \
|
||||
-Dwayland-backend=true \
|
||||
-Dprint-backends=file \
|
||||
@@ -24,12 +25,13 @@ flatpak build ${builddir} meson \
|
||||
-Dbuild-examples=false \
|
||||
-Dintrospection=false \
|
||||
-Ddemos=true \
|
||||
_flatpak_build
|
||||
|
||||
flatpak build ${builddir} ninja -C _flatpak_build install
|
||||
_build .
|
||||
|
||||
flatpak-builder \
|
||||
--run ${builddir} build-aux/flatpak/${appid}.json \
|
||||
ninja -C _build install
|
||||
|
||||
flatpak-builder \
|
||||
--user --disable-rofiles-fuse \
|
||||
--finish-only \
|
||||
--repo=${repodir} \
|
||||
${builddir} \
|
||||
@@ -38,5 +40,5 @@ flatpak-builder \
|
||||
flatpak build-bundle \
|
||||
${repodir} \
|
||||
${appid}-dev.flatpak \
|
||||
--runtime-repo=https://nightly.gnome.org/gnome-nightly.flatpakrepo \
|
||||
--runtime-repo=https://flathub.org/repo/flathub.flatpakrepo \
|
||||
${appid}
|
||||
|
||||
@@ -1,371 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Turns a Mason testlog.json file into an HTML report
|
||||
#
|
||||
# Copyright 2019 GNOME Foundation
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# Original author: Emmanuele Bassi
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from jinja2 import Template
|
||||
|
||||
REPORT_TEMPLATE = '''
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ report.project_name }} Test Report</title>
|
||||
<meta charset="utf-8" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
background: white;
|
||||
color: #333;
|
||||
font-family: 'Cantarell', sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333333;
|
||||
font-size: 1.9em;
|
||||
font-weight: normal;
|
||||
margin-bottom: 1em;
|
||||
border-bottom: 1px solid #333333;
|
||||
}
|
||||
|
||||
header {
|
||||
position: fixed;
|
||||
padding-bottom: 12px;
|
||||
margin-bottom: 24px;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
box-shadow: 0 0 1px rgba(0, 0, 0, 0.15);
|
||||
z-index: 500;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
color: rgba(0, 0, 0, 0.3);
|
||||
transform: translateY(0px);
|
||||
transition: .2s background-color, color;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
visibility: visible;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
article {
|
||||
padding-top: 200px;
|
||||
margin: 2em;
|
||||
}
|
||||
|
||||
div.report-meta {
|
||||
width: auto;
|
||||
border: 1px solid #ccc;
|
||||
padding: .5em 2em;
|
||||
color: #3c3c3c;
|
||||
}
|
||||
|
||||
span.result {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span.pass {
|
||||
color: rgb(51, 209, 122);
|
||||
}
|
||||
|
||||
span.skip {
|
||||
color: rgb(255, 163, 72);
|
||||
}
|
||||
|
||||
span.fail {
|
||||
color: rgb(224, 27, 36);
|
||||
}
|
||||
|
||||
span.xfail {
|
||||
color: rgb(163, 71, 186);
|
||||
}
|
||||
|
||||
div.result {
|
||||
border-top: 1px solid #c0c0c0;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.result h4 {
|
||||
border-bottom: 1px solid #c0c0c0;
|
||||
margin-bottom: 0.7em;
|
||||
}
|
||||
|
||||
pre {
|
||||
color: #fafafa;
|
||||
background-color: black;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0px 5px 8px 0px rgba(0, 0, 0, 0.25);
|
||||
font-family: monospace;
|
||||
line-height: 1.2em;
|
||||
border: none;
|
||||
padding: 10px 1em;
|
||||
font-size: 0.9em;
|
||||
overflow: auto;
|
||||
white-space: pre;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
ul.passed li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
ul.passed li:after {
|
||||
content: ",";
|
||||
}
|
||||
|
||||
ul.passed li:last-child:after {
|
||||
content: "";
|
||||
}
|
||||
|
||||
ul.images {
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
ul.images li {
|
||||
display: inline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>{{ report.project_name }}/{{ report.backend }}/{{ report.branch_name }} :: Test Reports</h1>
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<section>
|
||||
<div class="report-meta">
|
||||
<p><strong>Backend:</strong> {{ report.backend }}</p>
|
||||
<p><strong>Branch:</strong> {{ report.branch_name }}</p>
|
||||
<p><strong>Date:</strong> <time datetime="{{ report.date.isoformat() }}">{{ report.locale_date }}</time></p>
|
||||
{% if report.job_id %}<p><strong>Job ID:</strong> {{ report.job_id }}</p>{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<div class="summary">
|
||||
<h3><a name="summary">Summary</a></h3>
|
||||
<ul>
|
||||
<li><strong>Total units:</strong> {{ report.total_units }}</li>
|
||||
<li><strong>Failed:</strong> {{ report.total_failures }}</li>
|
||||
<li><strong>Passed:</strong> {{ report.total_successes }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% for suite_result in report.results_list %}
|
||||
<section>
|
||||
<div class="result">
|
||||
<h3><a name="results">Suite: {{ suite_result.suite_name }}</a></h3>
|
||||
<ul>
|
||||
<li><strong>Units:</strong> {{ suite_result.n_units }}</li>
|
||||
<li><strong>Failed:</strong> <a href="#{{ suite_result.suite_name }}-failed">{{ suite_result.n_failures }}</a></li>
|
||||
<li><strong>Passed:</strong> <a href="#{{ suite_result.suite_name }}-passed">{{ suite_result.n_successes }}</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="failures">
|
||||
<h4><a name="{{ suite_result.suite_name }}-failed">Failures</a></h4>
|
||||
<ul class="failed">
|
||||
{% for failure in suite_result.failures if failure.result in [ 'ERROR', 'FAIL', 'UNEXPECTEDPASS' ] %}
|
||||
<li><a name="{{ failure.name }}">{{ failure.name }}</a> - result: <span class="result fail">{{ failure.result }}</span><br/>
|
||||
{% if failure.stdout %}
|
||||
Output: <pre>{{ failure.stdout }}</pre>
|
||||
{% endif %}
|
||||
{% if failure.image_data is defined %}
|
||||
<ul class="images">
|
||||
<li><img alt="ref" src="{{ failure.image_data.ref }}" /></li>
|
||||
<li><img alt="out" src="{{ failure.image_data.out }}" /></li>
|
||||
<li><img alt="diff" src="{{ failure.image_data.diff }}" /></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% else %}
|
||||
<li>None</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h4><a name="{{ suite_result.suite_name }}-timed-out">Timed out</a></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/>
|
||||
{% if failure.stdout %}
|
||||
Output: <pre>{{ failure.stdout }}</pre>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% else %}
|
||||
<li>None</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="successes">
|
||||
<h4><a name="{{ suite_result.suite_name }}-expected-fail">Expected failures</a></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/>
|
||||
{% if success.stdout %}
|
||||
Output: <pre>{{ success.stdout }}</pre>
|
||||
{% endif %}
|
||||
{% if success.image_data is defined %}
|
||||
<ul class="images">
|
||||
<li><img alt="ref" src="{{ success.image_data.ref }}" /></li>
|
||||
<li><img alt="out" src="{{ success.image_data.out }}" /></li>
|
||||
<li><img alt="diff" src="{{ success.image_data.diff }}" /></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% else %}
|
||||
<li>None</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h4><a name="{{ suite_result.suite_name }}-skipped">Skipped</a></h4>
|
||||
<ul>
|
||||
{% for success in suite_result.successes if success.result == 'SKIP' %}
|
||||
<li>{{ success.name }} - result: <span class="result skip">{{ success.result }}</li>
|
||||
{% else %}
|
||||
<li>None</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h4><a name="{{ suite_result.suite_name }}-passed">Passed</a></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>
|
||||
{% else %}
|
||||
<li>None</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
|
||||
aparser = argparse.ArgumentParser(description='Turns a Meson test log into an HTML report')
|
||||
aparser.add_argument('--project-name', metavar='NAME',
|
||||
help='The project name',
|
||||
default='Unknown')
|
||||
aparser.add_argument('--backend', metavar='NAME',
|
||||
help='The used backend',
|
||||
default='unknown')
|
||||
aparser.add_argument('--job-id', metavar='ID',
|
||||
help='The job ID for the report',
|
||||
default=None)
|
||||
aparser.add_argument('--branch', metavar='NAME',
|
||||
help='Branch of the project being tested',
|
||||
default='master')
|
||||
aparser.add_argument('--output', metavar='FILE',
|
||||
help='The output HTML file, stdout by default',
|
||||
type=argparse.FileType('w', encoding='UTF-8'),
|
||||
default=sys.stdout)
|
||||
aparser.add_argument('--reftest-suite', metavar='NAME',
|
||||
help='The name of the reftests suite',
|
||||
default='reftest')
|
||||
aparser.add_argument('--reftest-output-dir', metavar='DIR',
|
||||
help='The output directory for reftests data',
|
||||
default=None)
|
||||
aparser.add_argument('infile', metavar='FILE',
|
||||
help='The input testlog.json, stdin by default',
|
||||
type=argparse.FileType('r', encoding='UTF-8'),
|
||||
default=sys.stdin)
|
||||
|
||||
args = aparser.parse_args()
|
||||
|
||||
outfile = args.output
|
||||
|
||||
suites = {}
|
||||
for line in args.infile:
|
||||
data = json.loads(line)
|
||||
(full_suite, unit_name) = data['name'].split(' / ')
|
||||
(project_name, suite_name) = full_suite.split(':')
|
||||
|
||||
unit = {
|
||||
'project-name': project_name,
|
||||
'suite': suite_name,
|
||||
'name': unit_name,
|
||||
'duration': data['duration'],
|
||||
'returncode': data['returncode'],
|
||||
'result': data['result'],
|
||||
'stdout': data['stdout'],
|
||||
}
|
||||
|
||||
if args.reftest_output_dir is not None and suite_name == args.reftest_suite:
|
||||
filename = unit_name.split(' ')[1]
|
||||
basename = os.path.splitext(filename)[0]
|
||||
|
||||
image_data = {
|
||||
'ref': os.path.join(args.reftest_output_dir, '{}.ref.png'.format(basename)),
|
||||
'out': os.path.join(args.reftest_output_dir, '{}.out.png'.format(basename)),
|
||||
'diff': os.path.join(args.reftest_output_dir, '{}.diff.png'.format(basename)),
|
||||
}
|
||||
|
||||
unit['image_data'] = image_data
|
||||
|
||||
units = suites.setdefault(full_suite, [])
|
||||
units.append(unit)
|
||||
|
||||
report = {}
|
||||
report['date'] = datetime.datetime.utcnow()
|
||||
report['locale_date'] = report['date'].strftime("%c")
|
||||
report['project_name'] = args.project_name
|
||||
report['backend'] = args.backend
|
||||
report['job_id'] = args.job_id
|
||||
report['branch_name'] = args.branch
|
||||
report['total_successes'] = 0
|
||||
report['total_failures'] = 0
|
||||
report['total_units'] = 0
|
||||
report['results_list'] = []
|
||||
|
||||
for name, units in suites.items():
|
||||
(project_name, suite_name) = name.split(':')
|
||||
print('Processing {} suite {}:'.format(project_name, suite_name))
|
||||
|
||||
def if_failed(unit):
|
||||
if unit['result'] in ['FAIL', 'UNEXPECTEDPASS', 'TIMEOUT', 'ERROR',]:
|
||||
return True
|
||||
return False
|
||||
|
||||
def if_succeded(unit):
|
||||
if unit['result'] in ['OK', 'EXPECTEDFAIL', 'SKIP']:
|
||||
return True
|
||||
return False
|
||||
|
||||
successes = list(filter(if_succeded, units))
|
||||
failures = list(filter(if_failed, units))
|
||||
|
||||
n_units = len(units)
|
||||
n_successes = len(successes)
|
||||
n_failures = len(failures)
|
||||
|
||||
report['total_units'] += n_units
|
||||
report['total_successes'] += n_successes
|
||||
report['total_failures'] += n_failures
|
||||
print(' - {}: {} total, {} pass, {} fail'.format(suite_name, n_units, n_successes, n_failures))
|
||||
|
||||
suite_report = {
|
||||
'suite_name': suite_name,
|
||||
'n_units': n_units,
|
||||
'successes': successes,
|
||||
'n_successes': n_successes,
|
||||
'failures': failures,
|
||||
'n_failures': n_failures,
|
||||
}
|
||||
report['results_list'].append(suite_report)
|
||||
|
||||
template = Template(REPORT_TEMPLATE)
|
||||
outfile.write(template.render({'report': report}))
|
||||
@@ -1,114 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Turns a Meson testlog.json file into a JUnit XML report
|
||||
#
|
||||
# Copyright 2019 GNOME Foundation
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# Original author: Emmanuele Bassi
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
aparser = argparse.ArgumentParser(description='Turns a Meson test log into a JUnit report')
|
||||
aparser.add_argument('--project-name', metavar='NAME',
|
||||
help='The project name',
|
||||
default='unknown')
|
||||
aparser.add_argument('--backend', metavar='NAME',
|
||||
help='The used backend',
|
||||
default='unknown')
|
||||
aparser.add_argument('--job-id', metavar='ID',
|
||||
help='The job ID for the report',
|
||||
default='Unknown')
|
||||
aparser.add_argument('--branch', metavar='NAME',
|
||||
help='Branch of the project being tested',
|
||||
default='master')
|
||||
aparser.add_argument('--output', metavar='FILE',
|
||||
help='The output file, stdout by default',
|
||||
type=argparse.FileType('w', encoding='UTF-8'),
|
||||
default=sys.stdout)
|
||||
aparser.add_argument('infile', metavar='FILE',
|
||||
help='The input testlog.json, stdin by default',
|
||||
type=argparse.FileType('r', encoding='UTF-8'),
|
||||
default=sys.stdin)
|
||||
|
||||
args = aparser.parse_args()
|
||||
|
||||
outfile = args.output
|
||||
|
||||
testsuites = ET.Element('testsuites')
|
||||
testsuites.set('id', '{}/{}'.format(args.job_id, args.branch))
|
||||
testsuites.set('package', args.project_name)
|
||||
testsuites.set('timestamp', datetime.datetime.utcnow().isoformat(timespec='minutes'))
|
||||
|
||||
suites = {}
|
||||
for line in args.infile:
|
||||
data = json.loads(line)
|
||||
(full_suite, unit_name) = data['name'].split(' / ')
|
||||
(project_name, suite_name) = full_suite.split(':')
|
||||
|
||||
duration = data['duration']
|
||||
return_code = data['returncode']
|
||||
result = data['result']
|
||||
log = data['stdout']
|
||||
|
||||
unit = {
|
||||
'suite': suite_name,
|
||||
'name': unit_name,
|
||||
'duration': duration,
|
||||
'returncode': return_code,
|
||||
'result': result,
|
||||
'stdout': log,
|
||||
}
|
||||
|
||||
units = suites.setdefault(suite_name, [])
|
||||
units.append(unit)
|
||||
|
||||
for name, units in suites.items():
|
||||
print('Processing suite {} (units: {})'.format(name, len(units)))
|
||||
|
||||
def if_failed(unit):
|
||||
if unit['result'] in ['ERROR', 'FAIL', 'UNEXPECTEDPASS', 'TIMEOUT']:
|
||||
return True
|
||||
return False
|
||||
|
||||
def if_succeded(unit):
|
||||
if unit['result'] in ['OK', 'EXPECTEDFAIL', 'SKIP']:
|
||||
return True
|
||||
return False
|
||||
|
||||
successes = list(filter(if_succeded, units))
|
||||
failures = list(filter(if_failed, units))
|
||||
print(' - {}: {} pass, {} fail'.format(name, len(successes), len(failures)))
|
||||
|
||||
testsuite = ET.SubElement(testsuites, 'testsuite')
|
||||
testsuite.set('name', '{}/{}'.format(args.project_name, name))
|
||||
testsuite.set('tests', str(len(units)))
|
||||
testsuite.set('errors', str(len(failures)))
|
||||
testsuite.set('failures', str(len(failures)))
|
||||
|
||||
for unit in successes:
|
||||
testcase = ET.SubElement(testsuite, 'testcase')
|
||||
testcase.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
|
||||
testcase.set('name', '{}/{}'.format(args.backend, unit['name']))
|
||||
testcase.set('time', str(unit['duration']))
|
||||
|
||||
for unit in failures:
|
||||
testcase = ET.SubElement(testsuite, 'testcase')
|
||||
testcase.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
|
||||
testcase.set('name', '{}/{}'.format(args.backend, unit['name']))
|
||||
testcase.set('time', str(unit['duration']))
|
||||
|
||||
failure = ET.SubElement(testcase, 'failure')
|
||||
failure.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
|
||||
testcase.set('name', '{}/{}'.format(args.backend, unit['name']))
|
||||
failure.set('type', 'error')
|
||||
failure.text = unit['stdout']
|
||||
|
||||
output = ET.tostring(testsuites, encoding='unicode')
|
||||
outfile.write(output)
|
||||
+6
-130
@@ -1,135 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
read_arg() {
|
||||
# $1 = arg name
|
||||
# $2 = arg value
|
||||
# $3 = arg parameter
|
||||
local rematch='^[^=]*=(.*)$'
|
||||
if [[ $2 =~ $rematch ]]; then
|
||||
read "$1" <<< "${BASH_REMATCH[1]}"
|
||||
else
|
||||
read "$1" <<< "$3"
|
||||
# There is no way to shift our callers args, so
|
||||
# return 1 to indicate they should do it instead.
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
set -e
|
||||
|
||||
build=0
|
||||
run=0
|
||||
push=0
|
||||
list=0
|
||||
print_help=0
|
||||
no_login=0
|
||||
TAG="registry.gitlab.gnome.org/gnome/gtk/master:v2"
|
||||
|
||||
while (($# > 0)); do
|
||||
case "${1%%=*}" in
|
||||
build) build=1;;
|
||||
run) run=1;;
|
||||
push) push=1;;
|
||||
list) list=1;;
|
||||
help) print_help=1;;
|
||||
--base|-b) read_arg base "$@" || shift;;
|
||||
--base-version) read_arg base_version "$@" || shift;;
|
||||
--no-login) no_login=1;;
|
||||
*) echo -e "\e[1;31mERROR\e[0m: Unknown option '$1'"; exit 1;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ $print_help == 1 ]; then
|
||||
echo "$0 - Build and run Docker images"
|
||||
echo ""
|
||||
echo "Usage: $0 <command> [options] [basename]"
|
||||
echo ""
|
||||
echo "Available commands"
|
||||
echo ""
|
||||
echo " build --base=<BASENAME> - Build Docker image <BASENAME>.Dockerfile"
|
||||
echo " run --base=<BASENAME> - Run Docker image <BASENAME>"
|
||||
echo " push --base=<BASENAME> - Push Docker image <BASENAME> to the registry"
|
||||
echo " list - List available images"
|
||||
echo " help - This help message"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if [ $list == 1 ]; then
|
||||
echo "Available Docker images:"
|
||||
for f in *.Dockerfile; do
|
||||
filename=$( basename -- "$f" )
|
||||
basename="${filename%.*}"
|
||||
|
||||
echo -e " \e[1;39m$basename\e[0m"
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# All commands after this require --base to be set
|
||||
if [ -z $base ]; then
|
||||
echo "Usage: $0 <command>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$base.Dockerfile" ]; then
|
||||
echo -e "\e[1;31mERROR\e[0m: Dockerfile for '$base' not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $base_version ]; then
|
||||
base_version="latest"
|
||||
elif [ $base_version != "latest" ]; then
|
||||
base_version="v$base_version"
|
||||
fi
|
||||
|
||||
if [ ! -x "$(command -v docker)" ] || [ docker --help |& grep -q podman ]; then
|
||||
# Docker is actually implemented by podman, and its OCI output
|
||||
# is incompatible with some of the dockerd instances on GitLab
|
||||
# CI runners.
|
||||
echo "Using: Podman"
|
||||
format="--format docker"
|
||||
CMD="podman"
|
||||
else
|
||||
echo "Using: Docker"
|
||||
format=""
|
||||
CMD="sudo docker"
|
||||
fi
|
||||
|
||||
REGISTRY="registry.gitlab.gnome.org"
|
||||
TAG="${REGISTRY}/gnome/gtk/${base}:${base_version}"
|
||||
|
||||
if [ $build == 1 ]; then
|
||||
echo -e "\e[1;32mBUILDING\e[0m: ${base} as ${TAG}"
|
||||
${CMD} build \
|
||||
${format} \
|
||||
--build-arg HOST_USER_ID="$UID" \
|
||||
--tag "${TAG}" \
|
||||
--file "${base}.Dockerfile" .
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [ $push == 1 ]; then
|
||||
echo -e "\e[1;32mPUSHING\e[0m: ${base} as ${TAG}"
|
||||
|
||||
if [ $no_login == 0 ]; then
|
||||
${CMD} login ${REGISTRY}
|
||||
fi
|
||||
|
||||
${CMD} push ${TAG}
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [ $run == 1 ]; then
|
||||
echo -e "\e[1;32mRUNNING\e[0m: ${base} as ${TAG}"
|
||||
${CMD} run \
|
||||
--rm \
|
||||
--volume "$(pwd)/..:/home/user/app" \
|
||||
--workdir "/home/user/app" \
|
||||
--tty \
|
||||
--interactive "${TAG}" \
|
||||
bash
|
||||
exit $?
|
||||
fi
|
||||
sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \
|
||||
--file "Dockerfile" .
|
||||
sudo docker run --rm --security-opt label=disable \
|
||||
--volume "$(pwd)/..:/home/user/app" --workdir "/home/user/app" \
|
||||
--tty --interactive "${TAG}" bash
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# We need to add a new remote for the upstream master, since this script could
|
||||
# be running in a personal fork of the repository which has out of date branches.
|
||||
git remote add upstream https://gitlab.gnome.org/GNOME/gtk.git
|
||||
git fetch upstream
|
||||
|
||||
# Work out the newest common ancestor between the detached HEAD that this CI job
|
||||
# has checked out, and the upstream target branch (which will typically be
|
||||
# `upstream/master` or `upstream/gtk-3-24`).
|
||||
#
|
||||
# `${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}` is only defined if we’re running in
|
||||
# a merge request pipeline; fall back to `${CI_DEFAULT_BRANCH}` otherwise.
|
||||
newest_common_ancestor_sha=$(diff --old-line-format='' --new-line-format='' <(git rev-list --first-parent "upstream/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-${CI_DEFAULT_BRANCH}}") <(git rev-list --first-parent HEAD) | head -1)
|
||||
git diff -U0 --no-color "${newest_common_ancestor_sha}" | .gitlab-ci/clang-format-diff.py -binary "clang-format" -p1
|
||||
exit_status=$?
|
||||
|
||||
# The style check is not infallible. The clang-format configuration cannot
|
||||
# perfectly describe GTK’s coding style: in particular, it cannot align
|
||||
# function arguments. The documented coding style for GTK takes priority over
|
||||
# clang-format suggestions. Hopefully we can eventually improve clang-format to
|
||||
# be configurable enough for our coding style. That’s why this CI check is OK
|
||||
# to fail: the idea is that people can look through the output and ignore it if
|
||||
# it’s wrong. (That situation can also happen if someone touches pre-existing
|
||||
# badly formatted code and it doesn’t make sense to tidy up the wider coding
|
||||
# style with the changes they’re making.)
|
||||
echo ""
|
||||
echo "Note that clang-format output is advisory and cannot always match the"
|
||||
echo "GTK coding style, documented at:"
|
||||
echo " https://gitlab.gnome.org/GNOME/gtk/blob/master/docs/CODING-STYLE"
|
||||
echo "Warnings from this tool can be ignored in favour of the documented "
|
||||
echo "coding style, or in favour of matching the style of existing"
|
||||
echo "surrounding code."
|
||||
|
||||
exit ${exit_status}
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set +x
|
||||
set +e
|
||||
|
||||
srcdir=$( pwd )
|
||||
builddir=$1
|
||||
backend=$2
|
||||
|
||||
case "${backend}" in
|
||||
x11)
|
||||
xvfb-run -a -s "-screen 0 1024x768x24" \
|
||||
meson test -C ${builddir} \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
--no-suite=gtk:a11y \
|
||||
--no-suite=gsk-compare-broadway
|
||||
|
||||
# Store the exit code for the CI run, but always
|
||||
# generate the reports
|
||||
exit_code=$?
|
||||
;;
|
||||
|
||||
wayland)
|
||||
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
|
||||
|
||||
weston --backend=headless-backend.so --socket=wayland-5 --idle-time=0 &
|
||||
compositor=$!
|
||||
export WAYLAND_DISPLAY=wayland-5
|
||||
|
||||
meson test -C ${builddir} \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
--no-suite=gtk:a11y \
|
||||
--no-suite=gsk-compare-broadway
|
||||
|
||||
exit_code=$?
|
||||
kill ${compositor}
|
||||
;;
|
||||
|
||||
broadway)
|
||||
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
|
||||
|
||||
${builddir}/gdk/broadway/gtk4-broadwayd :5 &
|
||||
server=$!
|
||||
export BROADWAY_DISPLAY=:5
|
||||
|
||||
meson test -C ${builddir} \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
--no-suite=gtk:a11y \
|
||||
--no-suite=gsk-compare-opengl
|
||||
|
||||
# don't let Broadway failures fail the run, for now
|
||||
exit_code=0
|
||||
kill ${server}
|
||||
;;
|
||||
esac
|
||||
|
||||
cd ${builddir}
|
||||
|
||||
$srcdir/.gitlab-ci/meson-junit-report.py \
|
||||
--project-name=gtk \
|
||||
--backend=${backend} \
|
||||
--job-id="${CI_JOB_NAME}" \
|
||||
--output=report-${backend}.xml \
|
||||
meson-logs/testlog-${backend}.json
|
||||
$srcdir/.gitlab-ci/meson-html-report.py \
|
||||
--project-name=gtk \
|
||||
--backend=${backend} \
|
||||
--job-id="${CI_JOB_NAME}" \
|
||||
--reftest-output-dir="testsuite/reftests/output/${backend}" \
|
||||
--output=report-${backend}.html \
|
||||
meson-logs/testlog-${backend}.json
|
||||
|
||||
exit $exit_code
|
||||
@@ -16,9 +16,6 @@ meson \
|
||||
-Dwayland-backend=true \
|
||||
-Dbroadway-backend=true \
|
||||
-Dvulkan=yes \
|
||||
-Dprofiler=true \
|
||||
--werror \
|
||||
${EXTRA_MESON_FLAGS:-} \
|
||||
_build $srcdir
|
||||
unset CCACHE_DISABLE
|
||||
|
||||
@@ -27,30 +24,9 @@ cd _build
|
||||
ninja
|
||||
ccache --show-stats
|
||||
|
||||
set +e
|
||||
|
||||
xvfb-run -a -s "-screen 0 1024x768x24" \
|
||||
meson test \
|
||||
--timeout-multiplier 2 \
|
||||
--print-errorlogs \
|
||||
--suite=gtk \
|
||||
--no-suite=gtk:gsk \
|
||||
--no-suite=gtk:a11y
|
||||
|
||||
# Save the exit code
|
||||
exit_code=$?
|
||||
|
||||
# We always want to run the report generators
|
||||
$srcdir/.gitlab-ci/meson-junit-report.py \
|
||||
--project-name=gtk \
|
||||
--job-id="${CI_JOB_NAME}" \
|
||||
--output=report.xml \
|
||||
meson-logs/testlog.json
|
||||
|
||||
$srcdir/.gitlab-ci/meson-html-report.py \
|
||||
--project-name=GTK \
|
||||
--job-id="${CI_JOB_NAME}" \
|
||||
--reftest-output-dir="testsuite/reftests/output" \
|
||||
--output=report.html \
|
||||
meson-logs/testlog.json
|
||||
|
||||
exit $exit_code
|
||||
|
||||
@@ -33,13 +33,6 @@ pacman --noconfirm -S --needed \
|
||||
mingw-w64-$MSYS2_ARCH-gst-plugins-bad \
|
||||
mingw-w64-$MSYS2_ARCH-shared-mime-info
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/gtk/issues/2243
|
||||
wget "https://gitlab.gnome.org/creiter/gitlab-ci-win32-runner-v2/raw/master/pango/mingw-w64-$MSYS2_ARCH-pango-git-1.44.7.90.ge48ae523-1-any.pkg.tar.zst"
|
||||
pacman --noconfirm -U "mingw-w64-$MSYS2_ARCH-pango-git-1.44.7.90.ge48ae523-1-any.pkg.tar.zst"
|
||||
|
||||
# https://github.com/msys2/MINGW-packages/pull/6465
|
||||
pacman --noconfirm -S --needed mingw-w64-$MSYS2_ARCH-brotli
|
||||
|
||||
mkdir -p _ccache
|
||||
export CCACHE_BASEDIR="$(pwd)"
|
||||
export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache"
|
||||
@@ -48,15 +41,11 @@ export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache"
|
||||
ccache --zero-stats
|
||||
ccache --show-stats
|
||||
export CCACHE_DISABLE=true
|
||||
# FIXME: introspection disabled for now because of
|
||||
# https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/340
|
||||
meson \
|
||||
-Dx11-backend=false \
|
||||
-Dwayland-backend=false \
|
||||
-Dwin32-backend=true \
|
||||
-Denable-x11-backend=false \
|
||||
-Denable-wayland-backend=false \
|
||||
-Denable-win32-backend=true \
|
||||
-Dvulkan=no \
|
||||
-Dintrospection=false \
|
||||
--werror \
|
||||
_build
|
||||
unset CCACHE_DISABLE
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<!--
|
||||
You should try and reproduce with the demos applications available
|
||||
under the `demos` directory, or the test programs in the `tests` directory.
|
||||
Alternatively, please attach a *small and self-contained* example
|
||||
*written in C* that exhibits the issue.
|
||||
Alternatively, please attach a *small and self-contained* example that
|
||||
exhibits the issue.
|
||||
-->
|
||||
|
||||
## Current behavior
|
||||
@@ -23,10 +23,10 @@
|
||||
|
||||
## Version information
|
||||
<!--
|
||||
- Which version of GTK you are using
|
||||
- Which version of GTK+ you are using
|
||||
- What operating system and version
|
||||
- For Linux, which distribution
|
||||
- If you built GTK yourself, the list of options used to configure the build
|
||||
- If you built GTK+ yourself, the list of options used to configure the build
|
||||
-->
|
||||
|
||||
## Additional information
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
|
||||
## Version information
|
||||
<!--
|
||||
- Which version of GTK you are using
|
||||
- Which version of GTK+ you are using
|
||||
- What operating system and version
|
||||
- for Linux, which distribution
|
||||
- If you built GTK yourself, the list of options used to configure the build
|
||||
- If you built GTK+ yourself, the list of options used to configure the build
|
||||
-->
|
||||
|
||||
## Warnings
|
||||
|
||||
+7
-2
@@ -22,7 +22,12 @@ Please, do not use the issue tracker for support questions. If you have
|
||||
questions on how to use GTK effectively, you can use:
|
||||
|
||||
- the `#gtk` IRC channel on irc.gnome.org
|
||||
- the [gtk tag on the GNOME Discourse instance](https://discourse.gnome.org/tag/gtk)
|
||||
- the [gtk](https://mail.gnome.org/mailman/listinfo/gtk-list) mailing list,
|
||||
for general questions on GTK
|
||||
- the [gtk-app-devel](https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list)
|
||||
mailing list, for questions on application development with GTK
|
||||
- the [gtk-devel](https://mail.gnome.org/mailman/listinfo/gtk-devel-list)
|
||||
mailing list, for questions on developing GTK itself
|
||||
|
||||
You can also look at the GTK tag on [Stack
|
||||
Overflow](https://stackoverflow.com/questions/tagged/gtk).
|
||||
@@ -169,7 +174,7 @@ maintainers review your contribution.
|
||||
|
||||
Each contribution is reviewed by the core developers of the GTK project.
|
||||
|
||||
The [CODEOWNERS](./docs/CODEOWNERS) document contains the list of core
|
||||
The [CODE-OWNERS](./docs/CODE-OWNERS) document contains the list of core
|
||||
contributors to GTK and the areas for which they are responsible; you
|
||||
should ensure to receive their review and signoff on your changes.
|
||||
|
||||
|
||||
@@ -1,437 +1,3 @@
|
||||
Overview of Changes in GTK 3.98.4
|
||||
=================================
|
||||
|
||||
* Themes
|
||||
- Refine menu styling
|
||||
- Tweak visible focus behavior
|
||||
- HighConstrast: Add public colors
|
||||
- HighContrast: Fix scale borders
|
||||
|
||||
* CSS:
|
||||
- Drop the nonstandard -gtk-icon-theme property
|
||||
- Add a system_setting_changed vfunc to propagate global changes
|
||||
|
||||
* Untangle titlebars from windows:
|
||||
- Add a GtkWindowControls widget
|
||||
- Add a GtkWindowHandle widget
|
||||
- Add actions for window menu items
|
||||
- Remove app menu fallback from GtkHeaderBar
|
||||
- Remove title and subtitle properties from GtkHeaderBar,
|
||||
rename custom-title to title-widget
|
||||
|
||||
* GtkWidget
|
||||
- Add a focusable property
|
||||
|
||||
* GtkPopover:
|
||||
- Fix (re-)positioning issues
|
||||
|
||||
* GtkStack:
|
||||
- Drop the homogeneous property
|
||||
- Add a use-underline property to stack pages
|
||||
|
||||
* GtkScale:
|
||||
- Make area around the trough clickable
|
||||
|
||||
* GtkScrolledWindow:
|
||||
- Fix kinetic scrolling
|
||||
|
||||
* GtkTreeView:
|
||||
- Break reference cycles in unroot
|
||||
|
||||
* Drop GtkBin and GtkContainer. All existing GtkBin subclasses
|
||||
have grown a child property with setter and getter. All
|
||||
existing GtkContainer subclasses have grown widget-specific
|
||||
remove (and in some cases, add) functions. <child> in ui
|
||||
files continues to work as before
|
||||
|
||||
* Replace gtk_widget_destroy by gtk_window_destroy
|
||||
|
||||
* Drop the ::size-allocate signal. Use a GtkWidgetPaintable
|
||||
if you need to be informed about changes to a widgets
|
||||
content or size
|
||||
|
||||
* Remove gtk_dialog_run
|
||||
|
||||
* GDK:
|
||||
- Wayland: Provide a builtin cursor of last resort
|
||||
- Change the monitor api to use a GListModel
|
||||
|
||||
* GSK:
|
||||
- Don't include renderer-specific headers automatically
|
||||
- GL: Fix nested rounded clips
|
||||
|
||||
* Introspection:
|
||||
- Assorted annotation fixes
|
||||
|
||||
* Inspector:
|
||||
- Preview media resources
|
||||
- Show media backend information
|
||||
|
||||
* gtk4-widget-factory:
|
||||
- Add GtkVideo
|
||||
- Add text styles
|
||||
- Add a print dialog
|
||||
- Add a password entry
|
||||
- Improve toolbar styling
|
||||
- Revamp transition effects
|
||||
|
||||
* gtk4-demo:
|
||||
- Replace some demos
|
||||
|
||||
* Translation updates:
|
||||
Chinese (Taiwan)
|
||||
Esperanto
|
||||
Japanese
|
||||
Romanian
|
||||
Spanish
|
||||
Ukrainian
|
||||
|
||||
|
||||
Overview of Changes in GTK 3.98.3
|
||||
=================================
|
||||
|
||||
* GtkEntry:
|
||||
- Support setting attributes in ui files
|
||||
|
||||
* GtkScaleButton:
|
||||
- Don't derive from GtkButton
|
||||
|
||||
* GtkAboutDialog:
|
||||
- Support more common licenses
|
||||
|
||||
* GtkEmojiChooser:
|
||||
- Improve keyboard navigation
|
||||
|
||||
* GtkLabel:
|
||||
- Remove pattern API
|
||||
|
||||
* GtkAspectFrame:
|
||||
- Modernize and simplify
|
||||
|
||||
* Chooser buttons:
|
||||
- Make dialogs modal by default
|
||||
|
||||
* Various widgets:
|
||||
- Replace shadow-type and relief properties by
|
||||
a simpler has-frame
|
||||
|
||||
* CSS:
|
||||
- Use :focus-visible instead of :focus(visible)
|
||||
- Add support for :focus-within
|
||||
|
||||
* Focus handling
|
||||
- Fix crossing event generation
|
||||
- Fix focus handling in various widgets
|
||||
- Change :can-focus to be recursive
|
||||
- Fix GtkWindow:is-active setting
|
||||
|
||||
* Scrolling
|
||||
- gtk_container_set_focus_[hv]adjustment has been removed
|
||||
- gtk_viewport_set_scroll_to_focus has been added
|
||||
|
||||
* Accessibility:
|
||||
- Add a cursor-aspect-ratio setting
|
||||
- Set focus-related states properly
|
||||
|
||||
* Themes:
|
||||
- Use blue focus outlines more
|
||||
- Numerous minor improvements
|
||||
|
||||
* Wayland:
|
||||
- Fix .Compose file loading
|
||||
- Support popup repositioning
|
||||
- Fix problems with autohide popovers
|
||||
|
||||
* GDK:
|
||||
- Remove GdkKeymap from public API, replaced by
|
||||
GdkDevice properties
|
||||
- Add full keyboard translation state to key events
|
||||
- Simplify modifier support, drop GdkModifierIntent
|
||||
- Move key event matching to GDK
|
||||
- Add GdkSurface::enter/leave-monitor signals
|
||||
- Turn GskEvent into a derivable type, and make
|
||||
it introspectable
|
||||
|
||||
* GSK:
|
||||
- Turn GskRenderNode into a derivable type, and make
|
||||
it introspectable
|
||||
- Fall back to cairo if compiling shaders fails
|
||||
|
||||
* Translation updates:
|
||||
- Japanese
|
||||
- Lithuanian
|
||||
- Turkish
|
||||
|
||||
|
||||
Overview of Changes in GTK 3.98.2
|
||||
=================================
|
||||
|
||||
* Introduce GtkShortcutController, and replace key bindings,
|
||||
mnemonics and accelerators by GtkShortcut
|
||||
|
||||
* Derive the HighContrast theme from Adwaita
|
||||
|
||||
* GtkMenuButton: Add a use-underline property
|
||||
|
||||
* GtkTreeView: Fix cell editing
|
||||
|
||||
* Add gdk_toplevel_inhibit_system_shortcuts
|
||||
|
||||
* gtk-demo: Fix issues in multiple demos
|
||||
|
||||
* Translation updates:
|
||||
Polish
|
||||
|
||||
|
||||
Overview of Changes in GTK 3.98.1
|
||||
=================================
|
||||
|
||||
* GtkFileChooser:
|
||||
- Remove filename/uri api
|
||||
- Drop extra-widget
|
||||
- Remove overwrite confirmation
|
||||
- Remove show-hidden property
|
||||
- Remove local-only property
|
||||
- Remove GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
|
||||
- The portal file chooser supports selecting folders
|
||||
|
||||
* GtkSpinner:
|
||||
- Rename active property to spinning
|
||||
|
||||
* GtkRevealer:
|
||||
- Fix size allocation at small scales
|
||||
|
||||
* GtkPopover:
|
||||
- Drop :relative-to, it is always the :parent now
|
||||
|
||||
* GtkWindow:
|
||||
- Drop window-type, it is always a regular toplevel
|
||||
|
||||
* GtkWidget:
|
||||
- Drop expand property
|
||||
- Drop margin property
|
||||
- Drop gtk_grab_add, gtk_device_grab_add
|
||||
|
||||
* GtkTextView:
|
||||
- Support overlines in GtkTextTag
|
||||
- Support visible spaces in GtkTextTag
|
||||
- Support hyphenation control in GtkTextTag
|
||||
|
||||
* Split GtkEventControllerFocus from GtkEventControllerKey
|
||||
|
||||
* DND:
|
||||
- Fix local DND to avoid serialization
|
||||
- Add new content provider constructors
|
||||
- Split GtkDropTargetAsync and GtkDropTarget
|
||||
- Group DND events into event sequences
|
||||
- Propagate DND events like motion events
|
||||
- Introduce GtkDropControllerMotion
|
||||
- Remove GtkSelectionData
|
||||
|
||||
* Performance:
|
||||
- Clean up profiler marks
|
||||
- Share GL programs between renderers
|
||||
|
||||
* GDK:
|
||||
- Drop gdk_surface_new_temp
|
||||
- Make GdkEvent an immutable boxed type, not an object
|
||||
- Remove GdkAtom and property- and selection-related apis
|
||||
- Introduce GdkPopup and GdkToplevel interfaces
|
||||
- Implement them in backend-specific surface subtypes
|
||||
- Rename gdk_surface_input_shape_combine_region to
|
||||
gdk_surface_set_input_region
|
||||
- Drop X11-only concepts such as sticky or keep-below
|
||||
|
||||
* OS X: Fix OpenGL extension detection
|
||||
|
||||
* Broadway: implement scaling
|
||||
|
||||
* Translation updates:
|
||||
Dutch
|
||||
Japanese
|
||||
Persian
|
||||
|
||||
|
||||
Overview of Changes in GTK 3.98.0
|
||||
=================================
|
||||
|
||||
While this release gets significantly closer to what we aim for in GTK 4,
|
||||
there are still a few big items outstanding that we are currently working
|
||||
on:
|
||||
|
||||
- Event controllers for keyboard shortcuts
|
||||
- Movable popovers
|
||||
- Row-recycling list and grid views
|
||||
- Revamped accessibility infrastructure
|
||||
- Animation API
|
||||
|
||||
We will do further 3.98.x snapshots as these land.
|
||||
|
||||
*****************
|
||||
|
||||
* The DND refactoring has been completed. The GTK API for DND has been turned
|
||||
into event controllers: GtkDragSource and GtkDropTarget. Support for file
|
||||
transfers via file transfer portal has been added for both DND and the clipboard.
|
||||
|
||||
* Child surfaces have been removed. GDK only supports toplevel and popup surfaces
|
||||
now. The client-side window implementation has been removed too. On the GTK side,
|
||||
the GtkNative interface has been introduced for widgets that have their own
|
||||
surface. This cleanup is not 100% complete yet.
|
||||
|
||||
* Global positions and related apis such as gdk_surface_move are no longer available.
|
||||
|
||||
* A constraint-based layout manager has been added.
|
||||
|
||||
* Many classes have been made explicitly non-subclassable, and the widget hierarchy
|
||||
has been simplified, by making widgets derive directly from GtkWidget instead of
|
||||
a container.
|
||||
|
||||
* Menu-related changes:
|
||||
- GtkMenu, GtkMenuBar and related classes have been removed. They are being replaced
|
||||
by GMenu and popover-based variants. Popover menus can now do traditional, nested
|
||||
menus, and model buttons show accelerators.
|
||||
- Context menus are no longer created with ::populate-popup signals, but use menu
|
||||
models and actions.
|
||||
- Widget actions can be created in class_init, with gtk_widget_class_install_action.
|
||||
- GtkToolbar has been removed as well.
|
||||
|
||||
* Text-related changed:
|
||||
- Text cursor blinking has been made smooth.
|
||||
- GtkTextView is caching rendernodes for the visible text range now, improving the
|
||||
scrolling performance of text.
|
||||
- Add a simple undo stack for text edits has been added.
|
||||
|
||||
* The native Win32 filechooser backend supports choices.
|
||||
|
||||
* GtkTreeView renders tree and grid lines with textures.
|
||||
|
||||
* GtkEmojiChooser has been made public.
|
||||
|
||||
* GtkGestureMultiPress has been renamed to GtkGestureClick.
|
||||
|
||||
* GtkWidget has api to handle style classes: gtk_widget_add_style_class.
|
||||
This is the first step towards moving away from GtkStyleContext.
|
||||
|
||||
* X11-specific changes:
|
||||
- XI2 is now mandatory
|
||||
- The xim input method has been removed
|
||||
|
||||
* Wayland-specific changes:
|
||||
- The loading of cursor themes has been improved to load cursors on demand,
|
||||
and no longer relies on libwayland-cursor.
|
||||
|
||||
* The GL renderer is now sharing icon and glyph caches for all surfaces,
|
||||
and has better support for blurring and shadow rendering.
|
||||
|
||||
* Performance-related changes:
|
||||
- GTK provides profiling information for Sysprof when launched with GTK_TRACE=1.
|
||||
- Css computation has been optimized
|
||||
- Css lookups are using a Bloom filter
|
||||
- Icon loading IO has been moved to a thread
|
||||
|
||||
|
||||
Overview of Changes in GTK+ 3.96.0
|
||||
==================================
|
||||
|
||||
* DND has been refactored. There are now separate GdkDrag and GdkDrop
|
||||
objects. This work is still incomplete
|
||||
|
||||
* The GDK_SURFACE_SUBSURFACE surface type has been removed.
|
||||
|
||||
* Use of child surfaces has been greatly reduced. This work is still
|
||||
incomplete
|
||||
|
||||
* The use of global coordinates in GDK apis has been reduced. This
|
||||
work is still incomplete
|
||||
|
||||
* Events have been simplified and are used just for input
|
||||
- expose events have been replaced by a GdkSurface::render signal
|
||||
- configure events have been replaced by a GdkSurface::size-changed signal
|
||||
- map events have been replaced by a GdkSurface::mapped property
|
||||
- gdk_event_handler_set has been replaced by a GdkSurface::event signal
|
||||
- key events no longer contain a string
|
||||
- events on unmapped widgets are ignored
|
||||
|
||||
* Warping the pointer is no longer supported
|
||||
|
||||
* The Wayland backend now uses the Settings portal for GtkSettings
|
||||
|
||||
* The Wayland input module uses the text-input-unstable-v3 protocol
|
||||
|
||||
* The Broadway backend has been rewritten to work well with GSK
|
||||
|
||||
* The color chooser has a color picker
|
||||
|
||||
* GtkApplication tracks screensaver state and has a ::query-end signal
|
||||
|
||||
* The file chooser portal backend supports file filters
|
||||
|
||||
* A number of list models have been introduced, for internal use
|
||||
and as public api:
|
||||
- GtkMapListModel
|
||||
- GtkSliceListModel
|
||||
- GtkSortListModel
|
||||
- GtkSelectionModel
|
||||
- GtkSingleSelection
|
||||
|
||||
* Support for tabular menus and combo boxes has been dropped
|
||||
|
||||
* Key themes are no longer supported
|
||||
|
||||
* GtkInvisible has been dropped
|
||||
|
||||
* A GtkRoot interface has been added that is currently implemented
|
||||
just by GtkWindow. This work is incomplete
|
||||
|
||||
* GtkWidgets can transform their children using projective linear
|
||||
transformations. This functionality is available in CSS and
|
||||
as GskTransform argument to gtk_widget_allocate. GtkFixed is
|
||||
a container that exposes this functionality. For examples of this,
|
||||
see the swing transition of GtkRevealer, the rotate transitions
|
||||
of GtkStack or the Fixed Layout example in gtk-demo.
|
||||
|
||||
* GtkEntry functionality has been moved into a new GtkText widget,
|
||||
the GtkEditable interface has been expanded, and new a new
|
||||
GtkPasswordEntry widget has been introduced.
|
||||
|
||||
* Focus handling has been rewritten, and focus-change event
|
||||
generation has been unified with crossing events.
|
||||
|
||||
* All demos and settings schemas have been renamed to avoid collisions
|
||||
with GTK3.
|
||||
|
||||
* GtkWidget can now use a GtkLayoutManager for size allocation.
|
||||
Layout managers can optionally use layout children holding layout
|
||||
properties. A number of layout managers are available:
|
||||
- GtkBinLayout
|
||||
- GtkBoxLayout
|
||||
- GtkGridLayout
|
||||
- GtkFixedLayout
|
||||
- GtkCustomLayout
|
||||
More layout manager implementations will appear in the future.
|
||||
|
||||
* GtkAssistant, GtkStack and GtkNotebook now have publicly
|
||||
accessible page objects for their children. The page objects
|
||||
are also exposed via a list model.
|
||||
|
||||
* GtkContainer no longer supports child properties. All existing
|
||||
child properties have been removed, converted to regular properties,
|
||||
moved to layout properties or moved to child meta objects.
|
||||
|
||||
* GtkListBox has gained a ::show-separators property that gets
|
||||
translated into a CSS style class.
|
||||
|
||||
* A number of X11-specific GtkWindow and GdkSurface apis have been
|
||||
removed or changed to backend APIs.
|
||||
|
||||
* GtkBuilder can specify object-valued properties inline.
|
||||
|
||||
* The gtk4-builder-tool simplify command has gained a --3to4 option
|
||||
to convert GTK3 ui files to GTK4.
|
||||
|
||||
* The inspector can show child meta objects and layout properties.
|
||||
|
||||
|
||||
Overview of Changes in GTK+ 3.94.0
|
||||
==================================
|
||||
|
||||
@@ -692,7 +258,7 @@ Overview of Changes in GTK+ 3.92.1, 重庆市
|
||||
The bulk of the preparation for this release was done during
|
||||
and after the fantastic GNOME.Asia Summit 2017 in Chongqing, China.
|
||||
|
||||
* Drop autotools support. Meson 0.42.1 is now required
|
||||
* Drop autotools support. Meson 0.42.1 is now required
|
||||
|
||||
* Implement most of CSS3 font-variant
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@ The official developers blog
|
||||
|
||||
- https://blog.gtk.org
|
||||
|
||||
Discussion forum
|
||||
Information about mailing lists can be found at
|
||||
|
||||
- https://discourse.gnome.org/c/platform/core/
|
||||
- http://www.gtk.org/mailing-lists.php
|
||||
|
||||
Nightly documentation can be found at
|
||||
- Gtk: https://gnome.pages.gitlab.gnome.org/gtk/gtk/
|
||||
@@ -140,12 +140,6 @@ In the bug report please include:
|
||||
* Further information such as stack traces may be useful, but
|
||||
is not necessary.
|
||||
|
||||
Contributing to GTK
|
||||
-------------------
|
||||
|
||||
Please, follow the [contribution guide](./CONTRIBUTING.md) to know how to
|
||||
start contributing to GTK.
|
||||
|
||||
Release notes
|
||||
-------------
|
||||
|
||||
@@ -162,4 +156,4 @@ GTK is released under the terms of the GNU Lesser General Public License,
|
||||
version 2.1 or, at your option, any later version, as published by the Free
|
||||
Software Foundation.
|
||||
|
||||
Please, see the [`COPYING`](./COPYING) file for further information.
|
||||
Please, see the `COPYING` file for further information.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"app-id": "org.gtk.Demo4",
|
||||
"app-id": "org.gtk.Demo",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "master",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
@@ -9,9 +9,10 @@
|
||||
"finish-args": [
|
||||
"--device=dri",
|
||||
"--share=ipc",
|
||||
"--socket=fallback-x11",
|
||||
"--socket=x11",
|
||||
"--socket=wayland",
|
||||
"--talk-name=org.gtk.vfs", "--talk-name=org.gtk.vfs.*"
|
||||
"--talk-name=org.gtk.vfs", "--talk-name=org.gtk.vfs.*",
|
||||
"--talk-name=ca.desrt.conf", "--env=DCONF_USER_CONFIG_DIR=.config/dconf"
|
||||
],
|
||||
"cleanup": [
|
||||
"/include",
|
||||
@@ -54,36 +55,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "libsass",
|
||||
"buildsystem" : "meson",
|
||||
"builddir" : true,
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://github.com/lazka/libsass.git",
|
||||
"branch" : "meson"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "sassc",
|
||||
"buildsystem" : "meson",
|
||||
"builddir" : true,
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://github.com/lazka/sassc.git",
|
||||
"branch" : "meson"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "gtk",
|
||||
"buildsystem": "meson",
|
||||
@@ -1,102 +0,0 @@
|
||||
{
|
||||
"app-id": "org.gtk.IconBrowser4",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "master",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"command": "gtk4-icon-browser",
|
||||
"tags": ["devel", "development", "nightly"],
|
||||
"desktop-file-name-prefix": "(Development) ",
|
||||
"finish-args": [
|
||||
"--device=dri",
|
||||
"--share=ipc",
|
||||
"--socket=fallback-x11",
|
||||
"--socket=wayland",
|
||||
"--talk-name=org.gtk.vfs", "--talk-name=org.gtk.vfs.*"
|
||||
],
|
||||
"cleanup": [
|
||||
"/include",
|
||||
"/lib/pkgconfig", "/share/pkgconfig",
|
||||
"/share/aclocal",
|
||||
"/man", "/share/man", "/share/gtk-doc",
|
||||
"*.la", ".a",
|
||||
"/lib/girepository-1.0",
|
||||
"/share/gir-1.0",
|
||||
"/share/doc"
|
||||
],
|
||||
"modules": [
|
||||
{
|
||||
"name" : "wayland",
|
||||
"buildsystem" : "autotools",
|
||||
"builddir" : true,
|
||||
"config-opts" : [
|
||||
"--disable-documentation"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://github.com/wayland-project/wayland.git"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "graphene",
|
||||
"buildsystem": "meson",
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib",
|
||||
"-Dtests=false",
|
||||
"-Dbenchmarks=false"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/ebassi/graphene.git"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "libsass",
|
||||
"buildsystem" : "meson",
|
||||
"builddir" : true,
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://github.com/lazka/libsass.git",
|
||||
"branch" : "meson"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "sassc",
|
||||
"buildsystem" : "meson",
|
||||
"builddir" : true,
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://github.com/lazka/sassc.git",
|
||||
"branch" : "meson"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "gtk",
|
||||
"buildsystem": "meson",
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.gnome.org/GNOME/gtk.git"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+4
-33
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"app-id": "org.gtk.WidgetFactory4",
|
||||
"app-id": "org.gtk.WidgetFactory",
|
||||
"runtime": "org.gnome.Platform",
|
||||
"runtime-version": "master",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
@@ -9,9 +9,10 @@
|
||||
"finish-args": [
|
||||
"--device=dri",
|
||||
"--share=ipc",
|
||||
"--socket=fallback-x11",
|
||||
"--socket=x11",
|
||||
"--socket=wayland",
|
||||
"--talk-name=org.gtk.vfs", "--talk-name=org.gtk.vfs.*"
|
||||
"--talk-name=org.gtk.vfs", "--talk-name=org.gtk.vfs.*",
|
||||
"--talk-name=ca.desrt.conf", "--env=DCONF_USER_CONFIG_DIR=.config/dconf"
|
||||
],
|
||||
"cleanup": [
|
||||
"/include",
|
||||
@@ -54,36 +55,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "libsass",
|
||||
"buildsystem" : "meson",
|
||||
"builddir" : true,
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://github.com/lazka/libsass.git",
|
||||
"branch" : "meson"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "sassc",
|
||||
"buildsystem" : "meson",
|
||||
"builddir" : true,
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://github.com/lazka/sassc.git",
|
||||
"branch" : "meson"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "gtk",
|
||||
"buildsystem": "meson",
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -7,8 +7,8 @@ import subprocess
|
||||
if 'DESTDIR' not in os.environ:
|
||||
gtk_api_version = sys.argv[1]
|
||||
gtk_abi_version = sys.argv[2]
|
||||
gtk_libdir = sys.argv[3]
|
||||
gtk_datadir = sys.argv[4]
|
||||
gtk_libdir = sys.argv[3].replace('/', os.sep)
|
||||
gtk_datadir = sys.argv[4].replace('/', os.sep)
|
||||
|
||||
gtk_moduledir = os.path.join(gtk_libdir, 'gtk-' + gtk_api_version, gtk_abi_version)
|
||||
gtk_printmodule_dir = os.path.join(gtk_moduledir, 'printbackends')
|
||||
@@ -19,13 +19,15 @@ if 'DESTDIR' not in os.environ:
|
||||
os.path.join(gtk_datadir, 'glib-2.0', 'schemas')])
|
||||
|
||||
print('Updating icon cache...')
|
||||
subprocess.call(['gtk4-update-icon-cache', '-q', '-t' ,'-f',
|
||||
subprocess.call(['gtk-update-icon-cache', '-q', '-t' ,'-f',
|
||||
os.path.join(gtk_datadir, 'icons', 'hicolor')])
|
||||
|
||||
print('Updating module cache for print backends...')
|
||||
os.makedirs(gtk_printmodule_dir, exist_ok=True)
|
||||
if not os.path.isdir(gtk_printmodule_dir):
|
||||
os.mkdir(gtk_printmodule_dir)
|
||||
subprocess.call(['gio-querymodules', gtk_printmodule_dir])
|
||||
|
||||
print('Updating module cache for input methods...')
|
||||
os.makedirs(gtk_immodule_dir, exist_ok=True)
|
||||
if not os.path.isdir(gtk_immodule_dir):
|
||||
os.mkdir(gtk_immodule_dir)
|
||||
subprocess.call(['gio-querymodules', gtk_immodule_dir])
|
||||
|
||||
+27
-11
@@ -24,6 +24,9 @@
|
||||
/* Define to 1 if you have the <crt_externs.h> header file. */
|
||||
#mesondefine HAVE_CRT_EXTERNS_H
|
||||
|
||||
/* Define to 1 if CUPS 1.6 API is available */
|
||||
#mesondefine HAVE_CUPS_API_1_6
|
||||
|
||||
/* Define to 1 if you have the `dcgettext' function. */
|
||||
#mesondefine HAVE_DCGETTEXT
|
||||
|
||||
@@ -35,10 +38,6 @@
|
||||
*/
|
||||
#mesondefine HAVE_DECL_ISNAN
|
||||
|
||||
/* Define to 1 if you have the declaration of `isnanf', and to 0 if you don't.
|
||||
*/
|
||||
#mesondefine HAVE_DECL_ISNANF
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#mesondefine HAVE_DLFCN_H
|
||||
|
||||
@@ -60,6 +59,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
|
||||
|
||||
@@ -129,9 +134,6 @@
|
||||
/* Define to 1 if you have the <sys/param.h> header file. */
|
||||
#mesondefine HAVE_SYS_PARAM_H
|
||||
|
||||
/* Have the sysprof-capture library */
|
||||
#mesondefine HAVE_SYSPROF_CAPTURE
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#mesondefine HAVE_SYS_STAT_H
|
||||
|
||||
@@ -150,6 +152,9 @@
|
||||
/* Have the Xcursor library */
|
||||
#mesondefine HAVE_XCURSOR
|
||||
|
||||
/* Have the XDAMAGE X extension */
|
||||
#mesondefine HAVE_XDAMAGE
|
||||
|
||||
/* Have the XFIXES X extension */
|
||||
#mesondefine HAVE_XFIXES
|
||||
|
||||
@@ -186,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
|
||||
|
||||
@@ -236,6 +244,9 @@
|
||||
#endif
|
||||
|
||||
|
||||
/* Define to 1 if XInput 2.0 is available */
|
||||
#mesondefine XINPUT_2
|
||||
|
||||
/* Define to 1 if XInput 2.2 is available */
|
||||
#mesondefine XINPUT_2_2
|
||||
|
||||
@@ -289,13 +300,18 @@
|
||||
|
||||
#mesondefine GTK_PRINT_BACKENDS
|
||||
|
||||
#mesondefine HAVE_CAIRO_SCRIPT_INTERPRETER
|
||||
|
||||
#mesondefine HAVE_HARFBUZZ
|
||||
|
||||
#mesondefine HAVE_PANGOFT
|
||||
|
||||
#mesondefine ISO_CODES_PREFIX
|
||||
|
||||
/* Define if tracker3 is available */
|
||||
#mesondefine HAVE_TRACKER3
|
||||
#mesondefine MALLOC_IS_ALIGNED16
|
||||
|
||||
#mesondefine HAVE_POSIX_MEMALIGN
|
||||
|
||||
#mesondefine HAVE_MEMALIGN
|
||||
|
||||
#mesondefine HAVE_ALIGNED_ALLOC
|
||||
|
||||
#mesondefine HAVE__ALIGNED_MALLOC
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -1,654 +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);
|
||||
|
||||
GFile *cwd = g_file_new_for_path (".");
|
||||
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), cwd, NULL);
|
||||
g_object_unref (cwd);
|
||||
|
||||
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;
|
||||
GFile *file;
|
||||
char *text;
|
||||
GError *error = NULL;
|
||||
|
||||
model = constraint_view_get_model (CONSTRAINT_VIEW (self->view));
|
||||
text = serialize_model (model);
|
||||
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
||||
g_file_replace_contents (file, text, -1,
|
||||
NULL, FALSE,
|
||||
G_FILE_CREATE_NONE,
|
||||
NULL,
|
||||
NULL,
|
||||
&error);
|
||||
if (error != NULL)
|
||||
{
|
||||
GtkWidget *message_dialog;
|
||||
|
||||
message_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 (message_dialog),
|
||||
"%s", error->message);
|
||||
g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
|
||||
gtk_widget_show (message_dialog);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_free (text);
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
GFile *cwd = g_file_new_for_path (".");
|
||||
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), cwd, NULL);
|
||||
g_object_unref (cwd);
|
||||
|
||||
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_window_destroy (GTK_WINDOW (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_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_window_set_child (GTK_WINDOW (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_window_destroy (GTK_WINDOW (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_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_window_set_child (GTK_WINDOW (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);
|
||||
|
||||
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);
|
||||
gtk_widget_set_margin_start (label, 10);
|
||||
gtk_widget_set_margin_end (label, 10);
|
||||
gtk_widget_set_margin_top (label, 10);
|
||||
gtk_widget_set_margin_bottom (label, 10);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
|
||||
gtk_box_append (GTK_BOX (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_has_frame (GTK_BUTTON (button), FALSE);
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (row_edit), win);
|
||||
g_object_set_data (G_OBJECT (row), "edit", button);
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
|
||||
gtk_button_set_has_frame (GTK_BUTTON (button), FALSE);
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
}
|
||||
else if (GTK_IS_WIDGET (item))
|
||||
{
|
||||
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
|
||||
gtk_button_set_has_frame (GTK_BUTTON (button), FALSE);
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
|
||||
gtk_box_append (GTK_BOX (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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -1,81 +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="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>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
constraintview {
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
constraintview .child {
|
||||
background: red;
|
||||
}
|
||||
|
||||
constraintview .guide {
|
||||
background: blue;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
@@ -1,166 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="ConstraintEditor" parent="GtkWidget">
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid">
|
||||
<property name="margin-start">20</property>
|
||||
<property name="margin-end">20</property>
|
||||
<property name="margin-top">20</property>
|
||||
<property name="margin-bottom">20</property>
|
||||
<property name="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>
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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", (char *)"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", (char *)"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_widget_add_css_class (frame, "child");
|
||||
gtk_widget_set_name (frame, name);
|
||||
gtk_frame_set_child (GTK_FRAME (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_widget_add_css_class (frame, "guide");
|
||||
g_object_set_data (G_OBJECT (frame), "internal", (char *)"yes");
|
||||
gtk_frame_set_child (GTK_FRAME (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", (char *)"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;
|
||||
}
|
||||
@@ -1,45 +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_MODULE_EXPORT
|
||||
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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -1,191 +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-start">20</property>
|
||||
<property name="margin-end">20</property>
|
||||
<property name="margin-top">20</property>
|
||||
<property name="margin-bottom">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>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,21 +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,
|
||||
c_args: common_cflags,
|
||||
dependencies: libgtk_dep,
|
||||
include_directories: confinc,
|
||||
gui_app: true,
|
||||
link_args: extra_demo_ldflags,
|
||||
install: false)
|
||||
@@ -6,7 +6,6 @@
|
||||
typedef GtkApplication DemoApplication;
|
||||
typedef GtkApplicationClass DemoApplicationClass;
|
||||
|
||||
static GType demo_application_get_type (void);
|
||||
G_DEFINE_TYPE (DemoApplication, demo_application, GTK_TYPE_APPLICATION)
|
||||
|
||||
typedef struct {
|
||||
@@ -15,7 +14,7 @@ typedef struct {
|
||||
GtkWidget *message;
|
||||
GtkWidget *infobar;
|
||||
GtkWidget *status;
|
||||
GtkWidget *menubutton;
|
||||
GtkWidget *menutool;
|
||||
GMenuModel *toolmenu;
|
||||
GtkTextBuffer *buffer;
|
||||
|
||||
@@ -26,7 +25,6 @@ typedef struct {
|
||||
} DemoApplicationWindow;
|
||||
typedef GtkApplicationWindowClass DemoApplicationWindowClass;
|
||||
|
||||
static GType demo_application_window_get_type (void);
|
||||
G_DEFINE_TYPE (DemoApplicationWindow, demo_application_window, GTK_TYPE_APPLICATION_WINDOW)
|
||||
|
||||
static void create_window (GApplication *app, const char *contents);
|
||||
@@ -47,7 +45,7 @@ show_action_dialog (GSimpleAction *action)
|
||||
name);
|
||||
|
||||
g_signal_connect (dialog, "response",
|
||||
G_CALLBACK (gtk_window_destroy), NULL);
|
||||
G_CALLBACK (gtk_widget_destroy), NULL);
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
}
|
||||
@@ -120,7 +118,7 @@ open_response_cb (GtkNativeDialog *dialog,
|
||||
"Error loading file: \"%s\"",
|
||||
error->message);
|
||||
g_signal_connect (message_dialog, "response",
|
||||
G_CALLBACK (gtk_window_destroy), NULL);
|
||||
G_CALLBACK (gtk_widget_destroy), NULL);
|
||||
gtk_widget_show (message_dialog);
|
||||
g_error_free (error);
|
||||
}
|
||||
@@ -214,7 +212,7 @@ activate_about (GSimpleAction *action,
|
||||
"comments", "Program to demonstrate GTK functions.",
|
||||
"authors", authors,
|
||||
"documenters", documentors,
|
||||
"logo-icon-name", "org.gtk.Demo4",
|
||||
"logo-icon-name", "org.gtk.Demo",
|
||||
"title", "About GTK Code Demos",
|
||||
NULL);
|
||||
}
|
||||
@@ -234,7 +232,7 @@ activate_quit (GSimpleAction *action,
|
||||
win = list->data;
|
||||
next = list->next;
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
gtk_widget_destroy (GTK_WIDGET (win));
|
||||
|
||||
list = next;
|
||||
}
|
||||
@@ -328,14 +326,19 @@ static void
|
||||
startup (GApplication *app)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
GMenuModel *appmenu;
|
||||
GMenuModel *menubar;
|
||||
|
||||
G_APPLICATION_CLASS (demo_application_parent_class)->startup (app);
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
gtk_builder_add_from_resource (builder, "/application_demo/menus.ui", NULL);
|
||||
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app),
|
||||
G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")));
|
||||
appmenu = (GMenuModel *)gtk_builder_get_object (builder, "appmenu");
|
||||
menubar = (GMenuModel *)gtk_builder_get_object (builder, "menubar");
|
||||
|
||||
gtk_application_set_app_menu (GTK_APPLICATION (app), appmenu);
|
||||
gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
|
||||
|
||||
g_object_unref (builder);
|
||||
}
|
||||
@@ -348,7 +351,6 @@ create_window (GApplication *app,
|
||||
|
||||
window = (DemoApplicationWindow *)g_object_new (demo_application_window_get_type (),
|
||||
"application", app,
|
||||
"show-menubar", TRUE,
|
||||
NULL);
|
||||
if (content)
|
||||
gtk_text_buffer_set_text (window->buffer, content, -1);
|
||||
@@ -368,7 +370,7 @@ demo_application_init (DemoApplication *app)
|
||||
GSettings *settings;
|
||||
GAction *action;
|
||||
|
||||
settings = g_settings_new ("org.gtk.Demo4");
|
||||
settings = g_settings_new ("org.gtk.Demo");
|
||||
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
||||
app_entries, G_N_ELEMENTS (app_entries),
|
||||
@@ -395,7 +397,7 @@ demo_application_window_store_state (DemoApplicationWindow *win)
|
||||
{
|
||||
GSettings *settings;
|
||||
|
||||
settings = g_settings_new ("org.gtk.Demo4");
|
||||
settings = g_settings_new ("org.gtk.Demo");
|
||||
g_settings_set (settings, "window-size", "(ii)", win->width, win->height);
|
||||
g_settings_set_boolean (settings, "maximized", win->maximized);
|
||||
g_settings_set_boolean (settings, "fullscreen", win->fullscreen);
|
||||
@@ -407,7 +409,7 @@ demo_application_window_load_state (DemoApplicationWindow *win)
|
||||
{
|
||||
GSettings *settings;
|
||||
|
||||
settings = g_settings_new ("org.gtk.Demo4");
|
||||
settings = g_settings_new ("org.gtk.Demo");
|
||||
g_settings_get (settings, "window-size", "(ii)", &win->width, &win->height);
|
||||
win->maximized = g_settings_get_boolean (settings, "maximized");
|
||||
win->fullscreen = g_settings_get_boolean (settings, "fullscreen");
|
||||
@@ -417,7 +419,7 @@ demo_application_window_load_state (DemoApplicationWindow *win)
|
||||
static void
|
||||
demo_application_window_init (DemoApplicationWindow *window)
|
||||
{
|
||||
GtkWidget *popover;
|
||||
GtkWidget *menu;
|
||||
|
||||
window->width = -1;
|
||||
window->height = -1;
|
||||
@@ -426,8 +428,8 @@ demo_application_window_init (DemoApplicationWindow *window)
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (window));
|
||||
|
||||
popover = gtk_popover_menu_new_from_model (window->toolmenu);
|
||||
gtk_menu_button_set_popover (GTK_MENU_BUTTON (window->menubutton), popover);
|
||||
menu = gtk_menu_new_from_model (window->toolmenu);
|
||||
gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (window->menutool), menu);
|
||||
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (window),
|
||||
win_entries, G_N_ELEMENTS (win_entries),
|
||||
@@ -475,7 +477,7 @@ surface_state_changed (GtkWidget *widget)
|
||||
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
|
||||
GdkSurfaceState new_state;
|
||||
|
||||
new_state = gdk_toplevel_get_state (GDK_TOPLEVEL (gtk_native_get_surface (GTK_NATIVE (widget))));
|
||||
new_state = gdk_surface_get_state (gtk_widget_get_surface (widget));
|
||||
window->maximized = (new_state & GDK_SURFACE_STATE_MAXIMIZED) != 0;
|
||||
window->fullscreen = (new_state & GDK_SURFACE_STATE_FULLSCREEN) != 0;
|
||||
}
|
||||
@@ -485,27 +487,27 @@ demo_application_window_realize (GtkWidget *widget)
|
||||
{
|
||||
GTK_WIDGET_CLASS (demo_application_window_parent_class)->realize (widget);
|
||||
|
||||
g_signal_connect_swapped (gtk_native_get_surface (GTK_NATIVE (widget)), "notify::state",
|
||||
g_signal_connect_swapped (gtk_widget_get_surface (widget), "notify::state",
|
||||
G_CALLBACK (surface_state_changed), widget);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_application_window_unrealize (GtkWidget *widget)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (gtk_native_get_surface (GTK_NATIVE (widget)),
|
||||
g_signal_handlers_disconnect_by_func (gtk_widget_get_surface (widget),
|
||||
surface_state_changed, widget);
|
||||
|
||||
GTK_WIDGET_CLASS (demo_application_window_parent_class)->unrealize (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_application_window_dispose (GObject *object)
|
||||
demo_application_window_destroy (GtkWidget *widget)
|
||||
{
|
||||
DemoApplicationWindow *window = (DemoApplicationWindow *)object;
|
||||
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
|
||||
|
||||
demo_application_window_store_state (window);
|
||||
|
||||
G_OBJECT_CLASS (demo_application_window_parent_class)->dispose (object);
|
||||
GTK_WIDGET_CLASS (demo_application_window_parent_class)->destroy (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -515,18 +517,18 @@ demo_application_window_class_init (DemoApplicationWindowClass *class)
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->constructed = demo_application_window_constructed;
|
||||
object_class->dispose = demo_application_window_dispose;
|
||||
|
||||
widget_class->size_allocate = demo_application_window_size_allocate;
|
||||
widget_class->realize = demo_application_window_realize;
|
||||
widget_class->unrealize = demo_application_window_unrealize;
|
||||
widget_class->destroy = demo_application_window_destroy;
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/application_demo/application.ui");
|
||||
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, message);
|
||||
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, infobar);
|
||||
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, status);
|
||||
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, buffer);
|
||||
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, menubutton);
|
||||
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, menutool);
|
||||
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, toolmenu);
|
||||
gtk_widget_class_bind_template_callback (widget_class, clicked_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, update_statusbar);
|
||||
@@ -539,7 +541,7 @@ main (int argc, char *argv[])
|
||||
GtkApplication *app;
|
||||
|
||||
app = GTK_APPLICATION (g_object_new (demo_application_get_type (),
|
||||
"application-id", "org.gtk.Demo4.App",
|
||||
"application-id", "org.gtk.Demo2",
|
||||
"flags", G_APPLICATION_HANDLES_OPEN,
|
||||
NULL));
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="DemoApplicationWindow" parent="GtkApplicationWindow">
|
||||
<property name="title" translatable="yes">Application Class</property>
|
||||
@@ -8,60 +7,71 @@
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<object class="GtkToolbar">
|
||||
<property name="hexpand">1</property>
|
||||
<style>
|
||||
<class name="primary-toolbar"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="menubutton">
|
||||
<object class="GtkMenuToolButton" id="menutool">
|
||||
<property name="icon-name">document-open</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkToolButton">
|
||||
<property name="icon-name">application-exit</property>
|
||||
<property name="action-name">app.quit</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator"/>
|
||||
<object class="GtkSeparatorToolItem"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkToolButton">
|
||||
<property name="icon-name">applications-other</property>
|
||||
<property name="action-name">win.logo</property>
|
||||
</object>
|
||||
</child>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkInfoBar" id="infobar">
|
||||
<property name="visible">0</property>
|
||||
<property name="hexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="message">
|
||||
<property name="hexpand">1</property>
|
||||
<child internal-child="content_area">
|
||||
<object class="GtkBox" id="content_area">
|
||||
<child>
|
||||
<object class="GtkLabel" id="message">
|
||||
<property name="hexpand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="action">
|
||||
<object class="GtkButton">
|
||||
<property name="valign">center</property>
|
||||
<property name="label" translatable="yes">_OK</property>
|
||||
<property name="use-underline">1</property>
|
||||
<signal name="clicked" handler="clicked_cb"/>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="valign">center</property>
|
||||
<property name="label" translatable="yes">_OK</property>
|
||||
<property name="use-underline">1</property>
|
||||
<signal name="clicked" handler="clicked_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="has-frame">1</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTextView">
|
||||
<property name="hexpand">1</property>
|
||||
@@ -69,20 +79,20 @@
|
||||
<property name="buffer">buffer</property>
|
||||
</object>
|
||||
</child>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStatusbar" id="status">
|
||||
<property name="hexpand">1</property>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
@@ -31,7 +31,12 @@ on_name_vanished (GDBusConnection *connection,
|
||||
if (!name_seen)
|
||||
return;
|
||||
|
||||
g_clear_object (&placeholder);
|
||||
if (placeholder)
|
||||
{
|
||||
gtk_widget_destroy (placeholder);
|
||||
g_object_unref (placeholder);
|
||||
placeholder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
@@ -47,7 +52,7 @@ do_application_demo (GtkWidget *toplevel)
|
||||
|
||||
if (watch == 0)
|
||||
watch = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.Demo4.App",
|
||||
"org.gtk.Demo2",
|
||||
0,
|
||||
on_name_appeared,
|
||||
on_name_vanished,
|
||||
@@ -75,8 +80,8 @@ do_application_demo (GtkWidget *toplevel)
|
||||
else
|
||||
{
|
||||
g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL),
|
||||
"org.gtk.Demo4.App",
|
||||
"/org/gtk/Demo4/App",
|
||||
"org.gtk.Demo2",
|
||||
"/org/gtk/Demo2",
|
||||
"org.gtk.Actions",
|
||||
"Activate",
|
||||
g_variant_new ("(sava{sv})", "quit", NULL, NULL),
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<interface>
|
||||
<menu id="appmenu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">About</attribute>
|
||||
<attribute name="action">app.about</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Quit</attribute>
|
||||
<attribute name="action">app.quit</attribute>
|
||||
<attribute name="accel"><Primary>q</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
</interface>
|
||||
+19
-23
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static GtkWidget *assistant = NULL;
|
||||
static GtkWidget *progress_bar = NULL;
|
||||
|
||||
static gboolean
|
||||
@@ -26,7 +27,8 @@ apply_changes_gradually (gpointer data)
|
||||
else
|
||||
{
|
||||
/* Close automatically once changes are fully applied. */
|
||||
gtk_window_destroy (GTK_WINDOW (data));
|
||||
gtk_widget_destroy (assistant);
|
||||
assistant = NULL;
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
}
|
||||
@@ -35,13 +37,16 @@ static void
|
||||
on_assistant_apply (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
/* Start a timer to simulate changes taking a few seconds to apply. */
|
||||
g_timeout_add (100, apply_changes_gradually, widget);
|
||||
g_timeout_add (100, apply_changes_gradually, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
on_assistant_close_cancel (GtkWidget *widget, gpointer data)
|
||||
{
|
||||
gtk_window_destroy (GTK_WINDOW (widget));
|
||||
GtkWidget **assistant = (GtkWidget **) data;
|
||||
|
||||
gtk_widget_destroy (*assistant);
|
||||
*assistant = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -75,7 +80,7 @@ on_entry_changed (GtkWidget *widget, gpointer data)
|
||||
|
||||
page_number = gtk_assistant_get_current_page (assistant);
|
||||
current_page = gtk_assistant_get_nth_page (assistant, page_number);
|
||||
text = gtk_editable_get_text (GTK_EDITABLE (widget));
|
||||
text = gtk_entry_get_text (GTK_ENTRY (widget));
|
||||
|
||||
if (text && *text)
|
||||
gtk_assistant_set_page_complete (assistant, current_page, TRUE);
|
||||
@@ -89,18 +94,14 @@ create_page1 (GtkWidget *assistant)
|
||||
GtkWidget *box, *label, *entry;
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
|
||||
gtk_widget_set_margin_start (box, 12);
|
||||
gtk_widget_set_margin_end (box, 12);
|
||||
gtk_widget_set_margin_top (box, 12);
|
||||
gtk_widget_set_margin_bottom (box, 12);
|
||||
|
||||
label = gtk_label_new ("You must fill out this entry to continue:");
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
gtk_container_add (GTK_CONTAINER (box), label);
|
||||
|
||||
entry = gtk_entry_new ();
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
|
||||
gtk_widget_set_valign (entry, GTK_ALIGN_CENTER);
|
||||
gtk_box_append (GTK_BOX (box), entry);
|
||||
gtk_container_add (GTK_CONTAINER (box), entry);
|
||||
g_signal_connect (G_OBJECT (entry), "changed",
|
||||
G_CALLBACK (on_entry_changed), assistant);
|
||||
|
||||
@@ -114,16 +115,11 @@ create_page2 (GtkWidget *assistant)
|
||||
{
|
||||
GtkWidget *box, *checkbutton;
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
|
||||
gtk_widget_set_margin_start (box, 12);
|
||||
gtk_widget_set_margin_end (box, 12);
|
||||
gtk_widget_set_margin_top (box, 12);
|
||||
gtk_widget_set_margin_bottom (box, 12);
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||
|
||||
checkbutton = gtk_check_button_new_with_label ("This is optional data, you may continue "
|
||||
"even if you do not check this");
|
||||
gtk_widget_set_valign (checkbutton, GTK_ALIGN_CENTER);
|
||||
gtk_box_append (GTK_BOX (box), checkbutton);
|
||||
gtk_container_add (GTK_CONTAINER (box), checkbutton);
|
||||
|
||||
gtk_assistant_append_page (GTK_ASSISTANT (assistant), box);
|
||||
gtk_assistant_set_page_complete (GTK_ASSISTANT (assistant), box, TRUE);
|
||||
@@ -168,8 +164,6 @@ create_page4 (GtkWidget *assistant)
|
||||
GtkWidget*
|
||||
do_assistant (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *assistant;
|
||||
|
||||
if (!assistant)
|
||||
{
|
||||
assistant = gtk_assistant_new ();
|
||||
@@ -178,7 +172,6 @@ do_assistant (GtkWidget *do_widget)
|
||||
|
||||
gtk_window_set_display (GTK_WINDOW (assistant),
|
||||
gtk_widget_get_display (do_widget));
|
||||
g_object_add_weak_pointer (G_OBJECT (assistant), (gpointer *)&assistant);
|
||||
|
||||
create_page1 (assistant);
|
||||
create_page2 (assistant);
|
||||
@@ -186,9 +179,9 @@ do_assistant (GtkWidget *do_widget)
|
||||
create_page4 (assistant);
|
||||
|
||||
g_signal_connect (G_OBJECT (assistant), "cancel",
|
||||
G_CALLBACK (on_assistant_close_cancel), NULL);
|
||||
G_CALLBACK (on_assistant_close_cancel), &assistant);
|
||||
g_signal_connect (G_OBJECT (assistant), "close",
|
||||
G_CALLBACK (on_assistant_close_cancel), NULL);
|
||||
G_CALLBACK (on_assistant_close_cancel), &assistant);
|
||||
g_signal_connect (G_OBJECT (assistant), "apply",
|
||||
G_CALLBACK (on_assistant_apply), NULL);
|
||||
g_signal_connect (G_OBJECT (assistant), "prepare",
|
||||
@@ -198,7 +191,10 @@ do_assistant (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (assistant))
|
||||
gtk_widget_show (assistant);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (assistant));
|
||||
{
|
||||
gtk_widget_destroy (assistant);
|
||||
assistant = NULL;
|
||||
}
|
||||
|
||||
return assistant;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -1,48 +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_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_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_window_set_child (GTK_WINDOW (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_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
+102
-102
@@ -1,4 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkWindow" id="window">
|
||||
@@ -17,33 +16,34 @@
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow">
|
||||
<property name="can-focus">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<property name="has-frame">1</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<property name="min-content-width">150</property>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackSwitcher">
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="stack">stack</property>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
@@ -66,53 +66,53 @@
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Duck</property>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Background</property>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<style>
|
||||
<class name="duck"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<style>
|
||||
<class name="gradient"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">
|
||||
Blended picture</property>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -120,12 +120,12 @@ Blended picture</property>
|
||||
<style>
|
||||
<class name="blend0"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
@@ -145,53 +145,53 @@ Blended picture</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Red</property>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Blue</property>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<style>
|
||||
<class name="red"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<style>
|
||||
<class name="blue"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">
|
||||
Blended picture</property>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -199,12 +199,12 @@ Blended picture</property>
|
||||
<style>
|
||||
<class name="blend1"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
@@ -227,33 +227,33 @@ Blended picture</property>
|
||||
<style>
|
||||
<class name="cyan"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<style>
|
||||
<class name="magenta"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<style>
|
||||
<class name="yellow"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -261,11 +261,11 @@ Blended picture</property>
|
||||
<style>
|
||||
<class name="blend2"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
@@ -274,11 +274,11 @@ Blended picture</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
@@ -287,11 +287,11 @@ Blended picture</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
@@ -300,11 +300,11 @@ Blended picture</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
@@ -313,21 +313,21 @@ Blended picture</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"></attribute>
|
||||
</attributes>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
@@ -39,7 +39,7 @@ enum {
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
static GQuark child_data_quark = 0;
|
||||
|
||||
G_DEFINE_TYPE (BlurOverlay, blur_overlay, GTK_TYPE_WIDGET)
|
||||
G_DEFINE_TYPE (BlurOverlay, blur_overlay, GTK_TYPE_BIN)
|
||||
|
||||
static void
|
||||
blur_overlay_set_overlay_child (GtkWidget *widget,
|
||||
@@ -131,11 +131,13 @@ blur_overlay_child_update_style_classes (BlurOverlay *overlay,
|
||||
GtkAlign valign, halign;
|
||||
gboolean is_left, is_right, is_top, is_bottom;
|
||||
gboolean has_left, has_right, has_top, has_bottom;
|
||||
GtkStyleContext *context;
|
||||
|
||||
has_left = gtk_widget_has_css_class (child, GTK_STYLE_CLASS_LEFT);
|
||||
has_right = gtk_widget_has_css_class (child, GTK_STYLE_CLASS_RIGHT);
|
||||
has_top = gtk_widget_has_css_class (child, GTK_STYLE_CLASS_TOP);
|
||||
has_bottom = gtk_widget_has_css_class (child, GTK_STYLE_CLASS_BOTTOM);
|
||||
context = gtk_widget_get_style_context (child);
|
||||
has_left = gtk_style_context_has_class (context, GTK_STYLE_CLASS_LEFT);
|
||||
has_right = gtk_style_context_has_class (context, GTK_STYLE_CLASS_RIGHT);
|
||||
has_top = gtk_style_context_has_class (context, GTK_STYLE_CLASS_TOP);
|
||||
has_bottom = gtk_style_context_has_class (context, GTK_STYLE_CLASS_BOTTOM);
|
||||
|
||||
is_left = is_right = is_top = is_bottom = FALSE;
|
||||
|
||||
@@ -158,24 +160,24 @@ blur_overlay_child_update_style_classes (BlurOverlay *overlay,
|
||||
is_bottom = (child_allocation->y + child_allocation->height == height);
|
||||
|
||||
if (has_left && !is_left)
|
||||
gtk_widget_remove_css_class (child, GTK_STYLE_CLASS_LEFT);
|
||||
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_LEFT);
|
||||
else if (!has_left && is_left)
|
||||
gtk_widget_add_css_class (child, GTK_STYLE_CLASS_LEFT);
|
||||
gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT);
|
||||
|
||||
if (has_right && !is_right)
|
||||
gtk_widget_remove_css_class (child, GTK_STYLE_CLASS_RIGHT);
|
||||
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_RIGHT);
|
||||
else if (!has_right && is_right)
|
||||
gtk_widget_add_css_class (child, GTK_STYLE_CLASS_RIGHT);
|
||||
gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT);
|
||||
|
||||
if (has_top && !is_top)
|
||||
gtk_widget_remove_css_class (child, GTK_STYLE_CLASS_TOP);
|
||||
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_TOP);
|
||||
else if (!has_top && is_top)
|
||||
gtk_widget_add_css_class (child, GTK_STYLE_CLASS_TOP);
|
||||
gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP);
|
||||
|
||||
if (has_bottom && !is_bottom)
|
||||
gtk_widget_remove_css_class (child, GTK_STYLE_CLASS_BOTTOM);
|
||||
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BOTTOM);
|
||||
else if (!has_bottom && is_bottom)
|
||||
gtk_widget_add_css_class (child, GTK_STYLE_CLASS_BOTTOM);
|
||||
gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -204,7 +206,7 @@ blur_overlay_size_allocate (GtkWidget *widget,
|
||||
GtkWidget *child;
|
||||
GtkWidget *main_widget;
|
||||
|
||||
main_widget = overlay->main_widget;
|
||||
main_widget = gtk_bin_get_child (GTK_BIN (overlay));
|
||||
if (main_widget && gtk_widget_get_visible (main_widget))
|
||||
gtk_widget_size_allocate (main_widget,
|
||||
&(GtkAllocation) {
|
||||
@@ -290,6 +292,43 @@ blur_overlay_get_child_position (BlurOverlay *overlay,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
blur_overlay_add (GtkContainer *container,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
BlurOverlay *overlay = BLUR_OVERLAY (container);
|
||||
gtk_widget_insert_after (widget, GTK_WIDGET (container), NULL);
|
||||
overlay->main_widget = widget;
|
||||
}
|
||||
|
||||
static void
|
||||
blur_overlay_remove (GtkContainer *container,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
BlurOverlay *overlay = BLUR_OVERLAY (container);
|
||||
gtk_widget_unparent (widget);
|
||||
if (overlay->main_widget == widget)
|
||||
overlay->main_widget = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
blur_overlay_forall (GtkContainer *overlay,
|
||||
GtkCallback callback,
|
||||
gpointer callback_data)
|
||||
{
|
||||
GtkWidget *child;
|
||||
|
||||
child = gtk_widget_get_first_child (GTK_WIDGET (overlay));
|
||||
while (child != NULL)
|
||||
{
|
||||
GtkWidget *next = gtk_widget_get_next_sibling (child);
|
||||
|
||||
(* callback) (child, callback_data);
|
||||
|
||||
child = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
blur_overlay_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
@@ -383,32 +422,21 @@ blur_overlay_snapshot (GtkWidget *widget,
|
||||
gsk_render_node_unref (main_widget_node);
|
||||
}
|
||||
|
||||
static void
|
||||
blur_overlay_dispose (GObject *object)
|
||||
{
|
||||
BlurOverlay *overlay = BLUR_OVERLAY (object);
|
||||
GtkWidget *child;
|
||||
|
||||
g_clear_pointer (&overlay->main_widget, gtk_widget_unparent);
|
||||
|
||||
while ((child = gtk_widget_get_first_child (GTK_WIDGET (overlay))))
|
||||
gtk_widget_unparent (child);
|
||||
|
||||
G_OBJECT_CLASS (blur_overlay_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
blur_overlay_class_init (BlurOverlayClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = blur_overlay_dispose;
|
||||
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
|
||||
|
||||
widget_class->measure = blur_overlay_measure;
|
||||
widget_class->size_allocate = blur_overlay_size_allocate;
|
||||
widget_class->snapshot = blur_overlay_snapshot;
|
||||
|
||||
container_class->add = blur_overlay_add;
|
||||
container_class->remove = blur_overlay_remove;
|
||||
container_class->forall = blur_overlay_forall;
|
||||
|
||||
klass->get_child_position = blur_overlay_get_child_position;
|
||||
|
||||
signals[GET_CHILD_POSITION] =
|
||||
@@ -430,6 +458,7 @@ blur_overlay_class_init (BlurOverlayClass *klass)
|
||||
static void
|
||||
blur_overlay_init (BlurOverlay *overlay)
|
||||
{
|
||||
gtk_widget_set_has_surface (GTK_WIDGET (overlay), FALSE);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
@@ -451,11 +480,3 @@ blur_overlay_add_overlay (BlurOverlay *overlay,
|
||||
|
||||
blur_overlay_set_overlay_child (widget, child);
|
||||
}
|
||||
|
||||
void
|
||||
blur_overlay_set_child (BlurOverlay *overlay,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
gtk_widget_insert_after (widget, GTK_WIDGET (overlay), NULL);
|
||||
overlay->main_widget = widget;
|
||||
}
|
||||
|
||||
@@ -37,14 +37,14 @@ typedef struct _BlurOverlayClass BlurOverlayClass;
|
||||
|
||||
struct _BlurOverlay
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
GtkBin parent_instance;
|
||||
|
||||
GtkWidget *main_widget;
|
||||
};
|
||||
|
||||
struct _BlurOverlayClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
GtkBinClass parent_class;
|
||||
|
||||
gboolean (*get_child_position) (BlurOverlay *overlay,
|
||||
GtkWidget *widget,
|
||||
@@ -59,9 +59,6 @@ GDK_AVAILABLE_IN_ALL
|
||||
void blur_overlay_add_overlay (BlurOverlay *overlay,
|
||||
GtkWidget *widget,
|
||||
double blur);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void blur_overlay_set_child (BlurOverlay *overlay,
|
||||
GtkWidget *widget);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
+52
-23
@@ -12,7 +12,7 @@ quit_activate (GSimpleAction *action,
|
||||
{
|
||||
GtkWidget *window = user_data;
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -26,10 +26,8 @@ about_activate (GSimpleAction *action,
|
||||
|
||||
builder = g_object_get_data (G_OBJECT (window), "builder");
|
||||
about_dlg = GTK_WIDGET (gtk_builder_get_object (builder, "aboutdialog1"));
|
||||
gtk_window_set_transient_for (GTK_WINDOW (about_dlg), GTK_WINDOW (window));
|
||||
gtk_window_set_hide_on_close (GTK_WINDOW (about_dlg), TRUE);
|
||||
g_signal_connect (about_dlg, "response", G_CALLBACK (gtk_widget_hide), NULL);
|
||||
gtk_widget_show (about_dlg);
|
||||
gtk_dialog_run (GTK_DIALOG (about_dlg));
|
||||
gtk_widget_hide (about_dlg);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -40,22 +38,7 @@ help_activate (GSimpleAction *action,
|
||||
g_print ("Help not available\n");
|
||||
}
|
||||
|
||||
static void
|
||||
not_implemented (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("Action “%s” not implemented\n", g_action_get_name (G_ACTION (action)));
|
||||
}
|
||||
|
||||
static GActionEntry win_entries[] = {
|
||||
{ "new", not_implemented, NULL, NULL, NULL },
|
||||
{ "open", not_implemented, NULL, NULL, NULL },
|
||||
{ "save", not_implemented, NULL, NULL, NULL },
|
||||
{ "save-as", not_implemented, NULL, NULL, NULL },
|
||||
{ "copy", not_implemented, NULL, NULL, NULL },
|
||||
{ "cut", not_implemented, NULL, NULL, NULL },
|
||||
{ "paste", not_implemented, NULL, NULL, NULL },
|
||||
{ "quit", quit_activate, NULL, NULL, NULL },
|
||||
{ "about", about_activate, NULL, NULL, NULL },
|
||||
{ "help", help_activate, NULL, NULL, NULL }
|
||||
@@ -65,7 +48,10 @@ GtkWidget *
|
||||
do_builder (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
GtkWidget *toolbar;
|
||||
GActionGroup *actions;
|
||||
GtkAccelGroup *accel_group;
|
||||
GtkWidget *item;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
@@ -73,23 +59,66 @@ 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));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
toolbar = GTK_WIDGET (gtk_builder_get_object (builder, "toolbar1"));
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (toolbar),
|
||||
"primary-toolbar");
|
||||
actions = (GActionGroup*)g_simple_action_group_new ();
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (actions),
|
||||
win_entries, G_N_ELEMENTS (win_entries),
|
||||
window);
|
||||
gtk_widget_insert_action_group (window, "win", actions);
|
||||
accel_group = gtk_accel_group_new ();
|
||||
gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
|
||||
|
||||
g_object_unref (builder);
|
||||
item = (GtkWidget*)gtk_builder_get_object (builder, "new_item");
|
||||
gtk_widget_add_accelerator (item, "activate", accel_group,
|
||||
GDK_KEY_n, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
|
||||
|
||||
item = (GtkWidget*)gtk_builder_get_object (builder, "open_item");
|
||||
gtk_widget_add_accelerator (item, "activate", accel_group,
|
||||
GDK_KEY_o, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
|
||||
|
||||
item = (GtkWidget*)gtk_builder_get_object (builder, "save_item");
|
||||
gtk_widget_add_accelerator (item, "activate", accel_group,
|
||||
GDK_KEY_s, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
|
||||
|
||||
item = (GtkWidget*)gtk_builder_get_object (builder, "quit_item");
|
||||
gtk_widget_add_accelerator (item, "activate", accel_group,
|
||||
GDK_KEY_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
|
||||
|
||||
item = (GtkWidget*)gtk_builder_get_object (builder, "copy_item");
|
||||
gtk_widget_add_accelerator (item, "activate", accel_group,
|
||||
GDK_KEY_c, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
|
||||
|
||||
item = (GtkWidget*)gtk_builder_get_object (builder, "cut_item");
|
||||
gtk_widget_add_accelerator (item, "activate", accel_group,
|
||||
GDK_KEY_x, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
|
||||
|
||||
item = (GtkWidget*)gtk_builder_get_object (builder, "paste_item");
|
||||
gtk_widget_add_accelerator (item, "activate", accel_group,
|
||||
GDK_KEY_v, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
|
||||
|
||||
item = (GtkWidget*)gtk_builder_get_object (builder, "help_item");
|
||||
gtk_widget_add_accelerator (item, "activate", accel_group,
|
||||
GDK_KEY_F1, 0, GTK_ACCEL_VISIBLE);
|
||||
|
||||
item = (GtkWidget*)gtk_builder_get_object (builder, "about_item");
|
||||
gtk_widget_add_accelerator (item, "activate", accel_group,
|
||||
GDK_KEY_F7, 0, GTK_ACCEL_VISIBLE);
|
||||
|
||||
g_object_set_data_full (G_OBJECT(window), "builder", builder, g_object_unref);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,560 @@
|
||||
/* Change Display
|
||||
*
|
||||
* Demonstrates migrating a window between different displays.
|
||||
* A display is a mouse and keyboard with some number of
|
||||
* associated monitors. The neat thing about having multiple
|
||||
* displays is that they can be on a completely separate
|
||||
* computers, as long as there is a network connection to the
|
||||
* computer where the application is running.
|
||||
*
|
||||
* Only some of the windowing systems where GTK runs have the
|
||||
* concept of multiple displays. (The X Window System is the
|
||||
* main example.) Other windowing systems can only handle one
|
||||
* keyboard and mouse, and combine all monitors into
|
||||
* a single display.
|
||||
*
|
||||
* This is a moderately complex example, and demonstrates:
|
||||
*
|
||||
* - Tracking the currently open displays
|
||||
*
|
||||
* - Changing the display for a window
|
||||
*
|
||||
* - Letting the user choose a window by clicking on it
|
||||
*
|
||||
* - Using GtkListStore and GtkTreeView
|
||||
*
|
||||
* - Using GtkDialog
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
/* The ChangeDisplayInfo structure corresponds to a toplevel window and
|
||||
* holds pointers to widgets inside the toplevel window along with other
|
||||
* information about the contents of the window.
|
||||
* This is a common organizational structure in real applications.
|
||||
*/
|
||||
typedef struct _ChangeDisplayInfo ChangeDisplayInfo;
|
||||
|
||||
struct _ChangeDisplayInfo
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkSizeGroup *size_group;
|
||||
|
||||
GtkTreeModel *display_model;
|
||||
|
||||
GdkDisplay *current_display;
|
||||
};
|
||||
|
||||
/* These enumerations provide symbolic names for the columns
|
||||
* in the two GtkListStore models.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
DISPLAY_COLUMN_NAME,
|
||||
DISPLAY_COLUMN_DISPLAY,
|
||||
DISPLAY_NUM_COLUMNS
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SCREEN_COLUMN_NUMBER,
|
||||
SCREEN_COLUMN_SCREEN,
|
||||
SCREEN_NUM_COLUMNS
|
||||
};
|
||||
|
||||
/* Finds the toplevel window under the mouse pointer, if any.
|
||||
*/
|
||||
static GtkWidget *
|
||||
find_toplevel_at_pointer (GdkDisplay *display)
|
||||
{
|
||||
GdkSurface *pointer_window;
|
||||
GtkWidget *widget = NULL;
|
||||
|
||||
pointer_window = gdk_device_get_surface_at_position (gtk_get_current_event_device (),
|
||||
NULL, NULL);
|
||||
|
||||
/* The user data field of a GdkSurface is used to store a pointer
|
||||
* to the widget that created it.
|
||||
*/
|
||||
if (pointer_window)
|
||||
{
|
||||
gpointer widget_ptr;
|
||||
gdk_surface_get_user_data (pointer_window, &widget_ptr);
|
||||
widget = widget_ptr;
|
||||
}
|
||||
|
||||
return widget ? gtk_widget_get_toplevel (widget) : NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
released_cb (GtkGestureMultiPress *gesture,
|
||||
guint n_press,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gboolean *clicked)
|
||||
{
|
||||
*clicked = TRUE;
|
||||
}
|
||||
|
||||
/* Asks the user to click on a window, then waits for them click
|
||||
* the mouse. When the mouse is released, returns the toplevel
|
||||
* window under the pointer, or NULL, if there is none.
|
||||
*/
|
||||
static GtkWidget *
|
||||
query_for_toplevel (GdkDisplay *display,
|
||||
const char *prompt)
|
||||
{
|
||||
GtkWidget *popup, *label, *frame;
|
||||
GdkCursor *cursor;
|
||||
GtkWidget *toplevel = NULL;
|
||||
GdkDevice *device;
|
||||
|
||||
popup = gtk_window_new (GTK_WINDOW_POPUP);
|
||||
gtk_window_set_display (GTK_WINDOW (popup), display);
|
||||
gtk_window_set_modal (GTK_WINDOW (popup), TRUE);
|
||||
gtk_window_set_position (GTK_WINDOW (popup), GTK_WIN_POS_CENTER);
|
||||
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
|
||||
gtk_container_add (GTK_CONTAINER (popup), frame);
|
||||
|
||||
label = gtk_label_new (prompt);
|
||||
g_object_set (label, "margin", 10, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (frame), label);
|
||||
|
||||
gtk_widget_show (popup);
|
||||
cursor = gdk_cursor_new_from_name ("crosshair", NULL);
|
||||
device = gtk_get_current_event_device ();
|
||||
|
||||
if (gdk_seat_grab (gdk_device_get_seat (device),
|
||||
gtk_widget_get_surface (popup),
|
||||
GDK_SEAT_CAPABILITY_ALL_POINTING,
|
||||
FALSE, cursor, NULL, NULL, NULL) == GDK_GRAB_SUCCESS)
|
||||
{
|
||||
GtkGesture *gesture = gtk_gesture_multi_press_new ();
|
||||
gboolean clicked = FALSE;
|
||||
|
||||
g_signal_connect (gesture, "released",
|
||||
G_CALLBACK (released_cb), &clicked);
|
||||
gtk_widget_add_controller (popup, GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
/* Process events until clicked is set by our button release event handler.
|
||||
* We pass in may_block=TRUE since we want to wait if there
|
||||
* are no events currently.
|
||||
*/
|
||||
while (!clicked)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
gdk_seat_ungrab (gdk_device_get_seat (device));
|
||||
|
||||
toplevel = find_toplevel_at_pointer (display);
|
||||
if (toplevel == popup)
|
||||
toplevel = NULL;
|
||||
}
|
||||
|
||||
g_object_unref (cursor);
|
||||
gtk_widget_destroy (popup);
|
||||
|
||||
return toplevel;
|
||||
}
|
||||
|
||||
/* Prompts the user for a toplevel window to move, and then moves
|
||||
* that window to the currently selected display
|
||||
*/
|
||||
static void
|
||||
query_change_display (ChangeDisplayInfo *info)
|
||||
{
|
||||
GdkDisplay *display = gtk_widget_get_display (info->window);
|
||||
GtkWidget *toplevel;
|
||||
|
||||
toplevel = query_for_toplevel (display,
|
||||
"Please select the toplevel\n"
|
||||
"to move to the new display");
|
||||
|
||||
if (toplevel)
|
||||
gtk_window_set_display (GTK_WINDOW (toplevel), info->current_display);
|
||||
else
|
||||
gdk_display_beep (display);
|
||||
}
|
||||
|
||||
/* Called when the user clicks on a button in our dialog or
|
||||
* closes the dialog through the window manager. Unless the
|
||||
* "Change" button was clicked, we destroy the dialog.
|
||||
*/
|
||||
static void
|
||||
response_cb (GtkDialog *dialog,
|
||||
gint response_id,
|
||||
ChangeDisplayInfo *info)
|
||||
{
|
||||
if (response_id == GTK_RESPONSE_OK)
|
||||
query_change_display (info);
|
||||
else
|
||||
gtk_widget_destroy (GTK_WIDGET (dialog));
|
||||
}
|
||||
|
||||
/* Called when the user clicks on "Open..." in the display
|
||||
* frame. Prompts for a new display, and then opens a connection
|
||||
* to that display.
|
||||
*/
|
||||
static void
|
||||
open_display_cb (GtkWidget *button,
|
||||
ChangeDisplayInfo *info)
|
||||
{
|
||||
GtkWidget *content_area;
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *display_entry;
|
||||
GtkWidget *dialog_label;
|
||||
gchar *new_screen_name = NULL;
|
||||
GdkDisplay *result = NULL;
|
||||
|
||||
dialog = gtk_dialog_new_with_buttons ("Open Display",
|
||||
GTK_WINDOW (info->window),
|
||||
GTK_DIALOG_MODAL,
|
||||
_("_Cancel"), GTK_RESPONSE_CANCEL,
|
||||
_("_OK"), GTK_RESPONSE_OK,
|
||||
NULL);
|
||||
|
||||
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
|
||||
display_entry = gtk_entry_new ();
|
||||
gtk_entry_set_activates_default (GTK_ENTRY (display_entry), TRUE);
|
||||
dialog_label =
|
||||
gtk_label_new ("Please enter the name of\nthe new display\n");
|
||||
|
||||
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (content_area), dialog_label);
|
||||
gtk_container_add (GTK_CONTAINER (content_area), display_entry);
|
||||
|
||||
gtk_widget_grab_focus (display_entry);
|
||||
|
||||
while (!result)
|
||||
{
|
||||
gint response_id = gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
if (response_id != GTK_RESPONSE_OK)
|
||||
break;
|
||||
|
||||
new_screen_name = gtk_editable_get_chars (GTK_EDITABLE (display_entry),
|
||||
0, -1);
|
||||
|
||||
if (strcmp (new_screen_name, "") != 0)
|
||||
{
|
||||
result = gdk_display_open (new_screen_name);
|
||||
if (!result)
|
||||
{
|
||||
gchar *error_msg =
|
||||
g_strdup_printf ("Can't open display:\n\t%s\nplease try another one\n",
|
||||
new_screen_name);
|
||||
gtk_label_set_text (GTK_LABEL (dialog_label), error_msg);
|
||||
g_free (error_msg);
|
||||
}
|
||||
|
||||
g_free (new_screen_name);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
/* Called when the user clicks on the "Close" button in the
|
||||
* "Display" frame. Closes the selected display.
|
||||
*/
|
||||
static void
|
||||
close_display_cb (GtkWidget *button,
|
||||
ChangeDisplayInfo *info)
|
||||
{
|
||||
if (info->current_display)
|
||||
gdk_display_close (info->current_display);
|
||||
}
|
||||
|
||||
/* Called when the selected row in the display list changes.
|
||||
* Updates info->current_display, then refills the list of
|
||||
* screens.
|
||||
*/
|
||||
static void
|
||||
display_changed_cb (GtkTreeSelection *selection,
|
||||
ChangeDisplayInfo *info)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
|
||||
if (info->current_display)
|
||||
g_object_unref (info->current_display);
|
||||
if (gtk_tree_selection_get_selected (selection, &model, &iter))
|
||||
gtk_tree_model_get (model, &iter,
|
||||
DISPLAY_COLUMN_DISPLAY, &info->current_display,
|
||||
-1);
|
||||
else
|
||||
info->current_display = NULL;
|
||||
}
|
||||
|
||||
/* This function is used both for creating the "Display" and
|
||||
* "Screen" frames, since they have a similar structure. The
|
||||
* caller hooks up the right context for the value returned
|
||||
* in tree_view, and packs any relevant buttons into button_vbox.
|
||||
*/
|
||||
static void
|
||||
create_frame (ChangeDisplayInfo *info,
|
||||
const char *title,
|
||||
GtkWidget **frame,
|
||||
GtkWidget **tree_view,
|
||||
GtkWidget **button_vbox)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
GtkWidget *scrollwin;
|
||||
GtkWidget *hbox;
|
||||
|
||||
*frame = gtk_frame_new (title);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
|
||||
g_object_set (hbox, "margin", 8, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (*frame), hbox);
|
||||
|
||||
scrollwin = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin),
|
||||
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin),
|
||||
GTK_SHADOW_IN);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), scrollwin);
|
||||
|
||||
*tree_view = gtk_tree_view_new ();
|
||||
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (*tree_view), FALSE);
|
||||
gtk_container_add (GTK_CONTAINER (scrollwin), *tree_view);
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*tree_view));
|
||||
gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
|
||||
|
||||
*button_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), *button_vbox);
|
||||
|
||||
if (!info->size_group)
|
||||
info->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
|
||||
|
||||
gtk_size_group_add_widget (GTK_SIZE_GROUP (info->size_group), *button_vbox);
|
||||
}
|
||||
|
||||
/* If we have a stack of buttons, it often looks better if their contents
|
||||
* are left-aligned, rather than centered. This function creates a button
|
||||
* and left-aligns it contents.
|
||||
*/
|
||||
GtkWidget *
|
||||
left_align_button_new (const char *label)
|
||||
{
|
||||
GtkWidget *button = gtk_button_new_with_mnemonic (label);
|
||||
GtkWidget *child = gtk_bin_get_child (GTK_BIN (button));
|
||||
|
||||
gtk_widget_set_halign (child, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (child, GTK_ALIGN_CENTER);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
/* Creates the "Display" frame in the main window.
|
||||
*/
|
||||
GtkWidget *
|
||||
create_display_frame (ChangeDisplayInfo *info)
|
||||
{
|
||||
GtkWidget *frame;
|
||||
GtkWidget *tree_view;
|
||||
GtkWidget *button_vbox;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkTreeSelection *selection;
|
||||
GtkWidget *button;
|
||||
|
||||
create_frame (info, "Display", &frame, &tree_view, &button_vbox);
|
||||
|
||||
button = left_align_button_new ("_Open...");
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (open_display_cb), info);
|
||||
gtk_container_add (GTK_CONTAINER (button_vbox), button);
|
||||
|
||||
button = left_align_button_new ("_Close");
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (close_display_cb), info);
|
||||
gtk_container_add (GTK_CONTAINER (button_vbox), button);
|
||||
|
||||
info->display_model = (GtkTreeModel *)gtk_list_store_new (DISPLAY_NUM_COLUMNS,
|
||||
G_TYPE_STRING,
|
||||
GDK_TYPE_DISPLAY);
|
||||
|
||||
gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), info->display_model);
|
||||
|
||||
column = gtk_tree_view_column_new_with_attributes ("Name",
|
||||
gtk_cell_renderer_text_new (),
|
||||
"text", DISPLAY_COLUMN_NAME,
|
||||
NULL);
|
||||
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
|
||||
g_signal_connect (selection, "changed",
|
||||
G_CALLBACK (display_changed_cb), info);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
/* Called when one of the currently open displays is closed.
|
||||
* Remove it from our list of displays.
|
||||
*/
|
||||
static void
|
||||
display_closed_cb (GdkDisplay *display,
|
||||
gboolean is_error,
|
||||
ChangeDisplayInfo *info)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
gboolean valid;
|
||||
|
||||
for (valid = gtk_tree_model_get_iter_first (info->display_model, &iter);
|
||||
valid;
|
||||
valid = gtk_tree_model_iter_next (info->display_model, &iter))
|
||||
{
|
||||
GdkDisplay *tmp_display;
|
||||
|
||||
gtk_tree_model_get (info->display_model, &iter,
|
||||
DISPLAY_COLUMN_DISPLAY, &tmp_display,
|
||||
-1);
|
||||
if (tmp_display == display)
|
||||
{
|
||||
gtk_list_store_remove (GTK_LIST_STORE (info->display_model), &iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Adds a new display to our list of displays, and connects
|
||||
* to the "closed" signal so that we can remove it from the
|
||||
* list of displays again.
|
||||
*/
|
||||
static void
|
||||
add_display (ChangeDisplayInfo *info,
|
||||
GdkDisplay *display)
|
||||
{
|
||||
const gchar *name = gdk_display_get_name (display);
|
||||
GtkTreeIter iter;
|
||||
|
||||
gtk_list_store_append (GTK_LIST_STORE (info->display_model), &iter);
|
||||
gtk_list_store_set (GTK_LIST_STORE (info->display_model), &iter,
|
||||
DISPLAY_COLUMN_NAME, name,
|
||||
DISPLAY_COLUMN_DISPLAY, display,
|
||||
-1);
|
||||
|
||||
g_signal_connect (display, "closed",
|
||||
G_CALLBACK (display_closed_cb), info);
|
||||
}
|
||||
|
||||
/* Called when a new display is opened
|
||||
*/
|
||||
static void
|
||||
display_opened_cb (GdkDisplayManager *manager,
|
||||
GdkDisplay *display,
|
||||
ChangeDisplayInfo *info)
|
||||
{
|
||||
add_display (info, display);
|
||||
}
|
||||
|
||||
/* Adds all currently open displays to our list of displays,
|
||||
* and set up a signal connection so that we'll be notified
|
||||
* when displays are opened in the future as well.
|
||||
*/
|
||||
static void
|
||||
initialize_displays (ChangeDisplayInfo *info)
|
||||
{
|
||||
GdkDisplayManager *manager = gdk_display_manager_get ();
|
||||
GSList *displays = gdk_display_manager_list_displays (manager);
|
||||
GSList *tmp_list;
|
||||
|
||||
for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
|
||||
add_display (info, tmp_list->data);
|
||||
|
||||
g_slist_free (tmp_list);
|
||||
|
||||
g_signal_connect (manager, "display-opened",
|
||||
G_CALLBACK (display_opened_cb), info);
|
||||
}
|
||||
|
||||
/* Cleans up when the toplevel is destroyed; we remove the
|
||||
* connections we use to track currently open displays, then
|
||||
* free the ChangeDisplayInfo structure.
|
||||
*/
|
||||
static void
|
||||
destroy_info (ChangeDisplayInfo *info)
|
||||
{
|
||||
GdkDisplayManager *manager = gdk_display_manager_get ();
|
||||
GSList *displays = gdk_display_manager_list_displays (manager);
|
||||
GSList *tmp_list;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (manager,
|
||||
display_opened_cb,
|
||||
info);
|
||||
|
||||
for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
|
||||
g_signal_handlers_disconnect_by_func (tmp_list->data,
|
||||
display_closed_cb,
|
||||
info);
|
||||
|
||||
g_slist_free (tmp_list);
|
||||
|
||||
g_object_unref (info->size_group);
|
||||
g_object_unref (info->display_model);
|
||||
|
||||
if (info->current_display)
|
||||
g_object_unref (info->current_display);
|
||||
|
||||
g_free (info);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_cb (GObject *object,
|
||||
ChangeDisplayInfo **info)
|
||||
{
|
||||
destroy_info (*info);
|
||||
*info = NULL;
|
||||
}
|
||||
|
||||
/* Main entry point. If the dialog for this demo doesn't yet exist, creates
|
||||
* it. Otherwise, destroys it.
|
||||
*/
|
||||
GtkWidget *
|
||||
do_changedisplay (GtkWidget *do_widget)
|
||||
{
|
||||
static ChangeDisplayInfo *info = NULL;
|
||||
|
||||
if (!info)
|
||||
{
|
||||
GtkWidget *content_area;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *frame;
|
||||
|
||||
info = g_new0 (ChangeDisplayInfo, 1);
|
||||
|
||||
info->window = gtk_dialog_new_with_buttons ("Change Display",
|
||||
GTK_WINDOW (do_widget),
|
||||
0,
|
||||
"Close", GTK_RESPONSE_CLOSE,
|
||||
"Change", GTK_RESPONSE_OK,
|
||||
NULL);
|
||||
|
||||
gtk_window_set_default_size (GTK_WINDOW (info->window), 300, 400);
|
||||
|
||||
g_signal_connect (info->window, "response",
|
||||
G_CALLBACK (response_cb), info);
|
||||
g_signal_connect (info->window, "destroy",
|
||||
G_CALLBACK (destroy_cb), &info);
|
||||
|
||||
content_area = gtk_dialog_get_content_area (GTK_DIALOG (info->window));
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
||||
g_object_set (vbox, "margin", 8, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (content_area), vbox);
|
||||
|
||||
frame = create_display_frame (info);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), frame);
|
||||
|
||||
initialize_displays (info);
|
||||
|
||||
gtk_widget_show (info->window);
|
||||
return info->window;
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_destroy (info->window);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
+212
-44
@@ -12,11 +12,10 @@
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <string.h>
|
||||
#include "demoimage.h"
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
static void
|
||||
void
|
||||
copy_button_clicked (GtkWidget *button,
|
||||
gpointer user_data)
|
||||
{
|
||||
@@ -29,10 +28,10 @@ copy_button_clicked (GtkWidget *button,
|
||||
clipboard = gtk_widget_get_clipboard (entry);
|
||||
|
||||
/* Set clipboard text */
|
||||
gdk_clipboard_set_text (clipboard, gtk_editable_get_text (GTK_EDITABLE (entry)));
|
||||
gdk_clipboard_set_text (clipboard, gtk_entry_get_text (GTK_ENTRY (entry)));
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
paste_received (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
@@ -51,7 +50,7 @@ paste_received (GObject *source_object,
|
||||
if (text)
|
||||
{
|
||||
/* Set the entry text */
|
||||
gtk_editable_set_text (GTK_EDITABLE (entry), text);
|
||||
gtk_entry_set_text (GTK_ENTRY (entry), text);
|
||||
g_free (text);
|
||||
}
|
||||
else
|
||||
@@ -69,14 +68,14 @@ paste_received (GObject *source_object,
|
||||
"Could not paste text: %s",
|
||||
error->message);
|
||||
g_signal_connect (dialog, "response",
|
||||
G_CALLBACK (gtk_window_destroy), NULL);
|
||||
G_CALLBACK (gtk_widget_destroy), NULL);
|
||||
gtk_widget_show (dialog);
|
||||
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
paste_button_clicked (GtkWidget *button,
|
||||
gpointer user_data)
|
||||
{
|
||||
@@ -94,6 +93,146 @@ paste_button_clicked (GtkWidget *button,
|
||||
gdk_clipboard_read_text_async (clipboard, NULL, paste_received, entry);
|
||||
}
|
||||
|
||||
static GdkPaintable *
|
||||
get_image_paintable (GtkImage *image)
|
||||
{
|
||||
const gchar *icon_name;
|
||||
GtkIconTheme *icon_theme;
|
||||
GtkIconInfo *icon_info;
|
||||
|
||||
switch (gtk_image_get_storage_type (image))
|
||||
{
|
||||
case GTK_IMAGE_PAINTABLE:
|
||||
return g_object_ref (gtk_image_get_paintable (image));
|
||||
case GTK_IMAGE_ICON_NAME:
|
||||
icon_name = gtk_image_get_icon_name (image);
|
||||
icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (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 GDK_PAINTABLE (gtk_icon_info_load_texture (icon_info));
|
||||
default:
|
||||
g_warning ("Image storage type %d not handled",
|
||||
gtk_image_get_storage_type (image));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
{
|
||||
GdkPaintable *paintable;
|
||||
|
||||
paintable = get_image_paintable (GTK_IMAGE (widget));
|
||||
if (paintable)
|
||||
{
|
||||
gtk_drag_set_icon_paintable (drag, paintable, -2, -2);
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
drag_data_get (GtkWidget *widget,
|
||||
GdkDrag *drag,
|
||||
GtkSelectionData *selection_data,
|
||||
guint info,
|
||||
gpointer data)
|
||||
{
|
||||
GdkPaintable *paintable;
|
||||
|
||||
paintable = get_image_paintable (GTK_IMAGE (widget));
|
||||
if (GDK_IS_TEXTURE (paintable))
|
||||
gtk_selection_data_set_texture (selection_data, GDK_TEXTURE (paintable));
|
||||
}
|
||||
|
||||
static void
|
||||
drag_data_received (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
GtkSelectionData *selection_data,
|
||||
gpointer data)
|
||||
{
|
||||
if (gtk_selection_data_get_length (selection_data) > 0)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
|
||||
texture = gtk_selection_data_get_texture (selection_data);
|
||||
gtk_image_set_from_paintable (GTK_IMAGE (data), GDK_PAINTABLE (texture));
|
||||
g_object_unref (texture);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
copy_image (GtkMenuItem *item,
|
||||
gpointer data)
|
||||
{
|
||||
GdkClipboard *clipboard;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
|
||||
paintable = get_image_paintable (GTK_IMAGE (data));
|
||||
|
||||
if (GDK_IS_TEXTURE (paintable))
|
||||
gdk_clipboard_set_texture (clipboard, GDK_TEXTURE (paintable));
|
||||
|
||||
if (paintable)
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
|
||||
static void
|
||||
paste_image_received (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
|
||||
texture = gdk_clipboard_read_texture_finish (GDK_CLIPBOARD (source), result, NULL);
|
||||
if (texture == NULL)
|
||||
return;
|
||||
|
||||
gtk_image_set_from_paintable (GTK_IMAGE (data), GDK_PAINTABLE (texture));
|
||||
g_object_unref (texture);
|
||||
}
|
||||
|
||||
static void
|
||||
paste_image (GtkMenuItem *item,
|
||||
gpointer data)
|
||||
{
|
||||
GdkClipboard *clipboard;
|
||||
|
||||
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
|
||||
gdk_clipboard_read_texture_async (clipboard,
|
||||
NULL,
|
||||
paste_image_received,
|
||||
data);
|
||||
}
|
||||
|
||||
static void
|
||||
pressed_cb (GtkGesture *gesture,
|
||||
int n_press,
|
||||
double x,
|
||||
double y,
|
||||
GtkWidget *image)
|
||||
{
|
||||
GtkWidget *menu;
|
||||
GtkWidget *item;
|
||||
|
||||
menu = gtk_menu_new ();
|
||||
|
||||
item = gtk_menu_item_new_with_mnemonic (_("_Copy"));
|
||||
g_signal_connect (item, "activate", G_CALLBACK (copy_image), image);
|
||||
gtk_widget_show (item);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
|
||||
item = gtk_menu_item_new_with_mnemonic (_("_Paste"));
|
||||
g_signal_connect (item, "activate", G_CALLBACK (paste_image), image);
|
||||
gtk_widget_show (item);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
|
||||
gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_clipboard (GtkWidget *do_widget)
|
||||
{
|
||||
@@ -103,89 +242,118 @@ do_clipboard (GtkWidget *do_widget)
|
||||
GtkWidget *label;
|
||||
GtkWidget *entry, *button;
|
||||
GtkWidget *image;
|
||||
GtkGesture *gesture;
|
||||
|
||||
window = gtk_window_new ();
|
||||
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), "Clipboard");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_margin_start (vbox, 8);
|
||||
gtk_widget_set_margin_end (vbox, 8);
|
||||
gtk_widget_set_margin_top (vbox, 8);
|
||||
gtk_widget_set_margin_bottom (vbox, 8);
|
||||
g_object_set (vbox, "margin", 8, NULL);
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
|
||||
label = gtk_label_new ("\"Copy\" will copy the text\nin the entry to the clipboard");
|
||||
|
||||
gtk_box_append (GTK_BOX (vbox), label);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), label);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
gtk_widget_set_margin_start (hbox, 8);
|
||||
gtk_widget_set_margin_end (hbox, 8);
|
||||
gtk_widget_set_margin_top (hbox, 8);
|
||||
gtk_widget_set_margin_bottom (hbox, 8);
|
||||
gtk_box_append (GTK_BOX (vbox), hbox);
|
||||
g_object_set (hbox, "margin", 8, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
||||
|
||||
/* Create the first entry */
|
||||
entry = gtk_entry_new ();
|
||||
gtk_box_append (GTK_BOX (hbox), entry);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), entry);
|
||||
|
||||
/* Create the button */
|
||||
button = gtk_button_new_with_mnemonic (_("_Copy"));
|
||||
gtk_box_append (GTK_BOX (hbox), button);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), button);
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (copy_button_clicked), entry);
|
||||
|
||||
label = gtk_label_new ("\"Paste\" will paste the text from the clipboard to the entry");
|
||||
gtk_box_append (GTK_BOX (vbox), label);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), label);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
gtk_widget_set_margin_start (hbox, 8);
|
||||
gtk_widget_set_margin_end (hbox, 8);
|
||||
gtk_widget_set_margin_top (hbox, 8);
|
||||
gtk_widget_set_margin_bottom (hbox, 8);
|
||||
gtk_box_append (GTK_BOX (vbox), hbox);
|
||||
g_object_set (hbox, "margin", 8, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
||||
|
||||
/* Create the second entry */
|
||||
entry = gtk_entry_new ();
|
||||
gtk_box_append (GTK_BOX (hbox), entry);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), entry);
|
||||
|
||||
/* Create the button */
|
||||
button = gtk_button_new_with_mnemonic (_("_Paste"));
|
||||
gtk_box_append (GTK_BOX (hbox), button);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), button);
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (paste_button_clicked), entry);
|
||||
|
||||
label = gtk_label_new ("Images can be transferred via the clipboard, too");
|
||||
gtk_box_append (GTK_BOX (vbox), label);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), label);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
gtk_widget_set_margin_start (hbox, 8);
|
||||
gtk_widget_set_margin_end (hbox, 8);
|
||||
gtk_widget_set_margin_top (hbox, 8);
|
||||
gtk_widget_set_margin_bottom (hbox, 8);
|
||||
gtk_box_append (GTK_BOX (vbox), hbox);
|
||||
g_object_set (hbox, "margin", 8, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
||||
|
||||
/* Create the first image */
|
||||
image = demo_image_new ("dialog-warning");
|
||||
gtk_box_append (GTK_BOX (hbox), image);
|
||||
image = gtk_image_new_from_icon_name ("dialog-warning");
|
||||
gtk_container_add (GTK_CONTAINER (hbox), image);
|
||||
|
||||
/* make image a drag source */
|
||||
gtk_drag_source_set (image, GDK_BUTTON1_MASK, NULL, GDK_ACTION_COPY);
|
||||
gtk_drag_source_add_image_targets (image);
|
||||
g_signal_connect (image, "drag-begin",
|
||||
G_CALLBACK (drag_begin), image);
|
||||
g_signal_connect (image, "drag-data-get",
|
||||
G_CALLBACK (drag_data_get), image);
|
||||
|
||||
/* accept drops on image */
|
||||
gtk_drag_dest_set (image, GTK_DEST_DEFAULT_ALL,
|
||||
NULL, GDK_ACTION_COPY);
|
||||
gtk_drag_dest_add_image_targets (image);
|
||||
g_signal_connect (image, "drag-data-received",
|
||||
G_CALLBACK (drag_data_received), image);
|
||||
|
||||
/* context menu on image */
|
||||
gesture = gtk_gesture_multi_press_new ();
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
|
||||
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), image);
|
||||
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
/* Create the second image */
|
||||
image = demo_image_new ("process-stop");
|
||||
gtk_box_append (GTK_BOX (hbox), image);
|
||||
image = gtk_image_new_from_icon_name ("process-stop");
|
||||
gtk_container_add (GTK_CONTAINER (hbox), image);
|
||||
|
||||
/* Create the third image */
|
||||
image = demo_image_new ("weather-clear");
|
||||
gtk_box_append (GTK_BOX (hbox), image);
|
||||
/* make image a drag source */
|
||||
gtk_drag_source_set (image, GDK_BUTTON1_MASK, NULL, GDK_ACTION_COPY);
|
||||
gtk_drag_source_add_image_targets (image);
|
||||
g_signal_connect (image, "drag-begin",
|
||||
G_CALLBACK (drag_begin), image);
|
||||
g_signal_connect (image, "drag-data-get",
|
||||
G_CALLBACK (drag_data_get), image);
|
||||
|
||||
/* accept drops on image */
|
||||
gtk_drag_dest_set (image, GTK_DEST_DEFAULT_ALL,
|
||||
NULL, GDK_ACTION_COPY);
|
||||
gtk_drag_dest_add_image_targets (image);
|
||||
g_signal_connect (image, "drag-data-received",
|
||||
G_CALLBACK (drag_data_received), image);
|
||||
|
||||
/* context menu on image */
|
||||
gesture = gtk_gesture_multi_press_new ();
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
|
||||
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), image);
|
||||
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (gesture));
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,116 @@
|
||||
/* Color Chooser
|
||||
*
|
||||
* A GtkColorChooser lets the user choose a color. There are several
|
||||
* implementations of the GtkColorChooser interface in GTK. The
|
||||
* GtkColorChooserDialog is a prebuilt dialog containing a
|
||||
* GtkColorChooserWidget.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
static GtkWidget *da;
|
||||
static GdkRGBA color;
|
||||
static GtkWidget *frame;
|
||||
|
||||
/* draw callback for the drawing area
|
||||
*/
|
||||
static void
|
||||
draw_function (GtkDrawingArea *da,
|
||||
cairo_t *cr,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
gdk_cairo_set_source_rgba (cr, &color);
|
||||
cairo_paint (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
response_cb (GtkDialog *dialog,
|
||||
gint response_id,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (response_id == GTK_RESPONSE_OK)
|
||||
{
|
||||
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog), &color);
|
||||
gtk_widget_queue_draw (da);
|
||||
}
|
||||
|
||||
gtk_widget_destroy (GTK_WIDGET (dialog));
|
||||
}
|
||||
|
||||
static void
|
||||
change_color_callback (GtkWidget *button,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
dialog = gtk_color_chooser_dialog_new ("Changing color", GTK_WINDOW (window));
|
||||
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (dialog), &color);
|
||||
|
||||
g_signal_connect (dialog, "response",
|
||||
G_CALLBACK (response_cb), NULL);
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_colorsel (GtkWidget *do_widget)
|
||||
{
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *button;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
color.red = 0;
|
||||
color.blue = 1;
|
||||
color.green = 0;
|
||||
color.alpha = 1;
|
||||
|
||||
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), "Color Chooser");
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
|
||||
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
||||
g_object_set (vbox, "margin", 12, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
|
||||
/*
|
||||
* Create the color swatch area
|
||||
*/
|
||||
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), frame);
|
||||
|
||||
da = gtk_drawing_area_new ();
|
||||
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 200);
|
||||
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 200);
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_function, NULL, NULL);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (frame), da);
|
||||
|
||||
button = gtk_button_new_with_mnemonic ("_Change the above color");
|
||||
gtk_widget_set_halign (button, GTK_ALIGN_END);
|
||||
gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (vbox), button);
|
||||
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (change_color_callback), NULL);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
+32
-45
@@ -19,7 +19,7 @@ enum
|
||||
static GtkTreeModel *
|
||||
create_icon_store (void)
|
||||
{
|
||||
const char *icon_names[6] = {
|
||||
const gchar *icon_names[6] = {
|
||||
"dialog-warning",
|
||||
"process-stop",
|
||||
"document-new",
|
||||
@@ -27,7 +27,7 @@ create_icon_store (void)
|
||||
NULL,
|
||||
"document-open"
|
||||
};
|
||||
const char *labels[6] = {
|
||||
const gchar *labels[6] = {
|
||||
N_("Warning"),
|
||||
N_("Stop"),
|
||||
N_("New"),
|
||||
@@ -111,8 +111,8 @@ static GtkTreeModel *
|
||||
create_capital_store (void)
|
||||
{
|
||||
struct {
|
||||
const char *group;
|
||||
const char *capital;
|
||||
gchar *group;
|
||||
gchar *capital;
|
||||
} capitals[] = {
|
||||
{ "A - B", NULL },
|
||||
{ NULL, "Albany" },
|
||||
@@ -234,7 +234,7 @@ typedef struct _MaskEntry MaskEntry;
|
||||
struct _MaskEntry
|
||||
{
|
||||
GtkEntry entry;
|
||||
const char *mask;
|
||||
gchar *mask;
|
||||
};
|
||||
|
||||
typedef struct _MaskEntryClass MaskEntryClass;
|
||||
@@ -246,7 +246,6 @@ struct _MaskEntryClass
|
||||
|
||||
static void mask_entry_editable_init (GtkEditableInterface *iface);
|
||||
|
||||
static GType mask_entry_get_type (void);
|
||||
G_DEFINE_TYPE_WITH_CODE (MaskEntry, mask_entry, GTK_TYPE_ENTRY,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
|
||||
mask_entry_editable_init));
|
||||
@@ -257,7 +256,7 @@ mask_entry_set_background (MaskEntry *entry)
|
||||
{
|
||||
if (entry->mask)
|
||||
{
|
||||
if (!g_regex_match_simple (entry->mask, gtk_editable_get_text (GTK_EDITABLE (entry)), 0, 0))
|
||||
if (!g_regex_match_simple (entry->mask, gtk_entry_get_text (GTK_ENTRY (entry)), 0, 0))
|
||||
{
|
||||
PangoAttrList *attrs;
|
||||
|
||||
@@ -311,36 +310,32 @@ do_combobox (GtkWidget *do_widget)
|
||||
|
||||
if (!window)
|
||||
{
|
||||
window = gtk_window_new ();
|
||||
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), "Combo Boxes");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
|
||||
gtk_widget_set_margin_start (vbox, 10);
|
||||
gtk_widget_set_margin_end (vbox, 10);
|
||||
gtk_widget_set_margin_top (vbox, 10);
|
||||
gtk_widget_set_margin_bottom (vbox, 10);
|
||||
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
||||
g_object_set (vbox, "margin", 10, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
|
||||
/* A combobox demonstrating cell renderers, separators and
|
||||
* insensitive rows
|
||||
*/
|
||||
frame = gtk_frame_new ("Items with icons");
|
||||
gtk_box_append (GTK_BOX (vbox), frame);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), frame);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_margin_start (box, 5);
|
||||
gtk_widget_set_margin_end (box, 5);
|
||||
gtk_widget_set_margin_top (box, 5);
|
||||
gtk_widget_set_margin_bottom (box, 5);
|
||||
gtk_frame_set_child (GTK_FRAME (frame), box);
|
||||
g_object_set (box, "margin", 5, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (frame), box);
|
||||
|
||||
model = create_icon_store ();
|
||||
combo = gtk_combo_box_new_with_model (model);
|
||||
g_object_unref (model);
|
||||
gtk_box_append (GTK_BOX (box), combo);
|
||||
gtk_container_add (GTK_CONTAINER (box), combo);
|
||||
|
||||
renderer = gtk_cell_renderer_pixbuf_new ();
|
||||
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
|
||||
@@ -372,19 +367,16 @@ do_combobox (GtkWidget *do_widget)
|
||||
/* A combobox demonstrating trees.
|
||||
*/
|
||||
frame = gtk_frame_new ("Where are we ?");
|
||||
gtk_box_append (GTK_BOX (vbox), frame);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), frame);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_margin_start (box, 5);
|
||||
gtk_widget_set_margin_end (box, 5);
|
||||
gtk_widget_set_margin_top (box, 5);
|
||||
gtk_widget_set_margin_bottom (box, 5);
|
||||
gtk_frame_set_child (GTK_FRAME (frame), box);
|
||||
g_object_set (box, "margin", 5, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (frame), box);
|
||||
|
||||
model = create_capital_store ();
|
||||
combo = gtk_combo_box_new_with_model (model);
|
||||
g_object_unref (model);
|
||||
gtk_box_append (GTK_BOX (box), combo);
|
||||
gtk_container_add (GTK_CONTAINER (box), combo);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
|
||||
@@ -403,52 +395,47 @@ do_combobox (GtkWidget *do_widget)
|
||||
|
||||
/* A GtkComboBoxEntry with validation */
|
||||
frame = gtk_frame_new ("Editable");
|
||||
gtk_box_append (GTK_BOX (vbox), frame);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), frame);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_margin_start (box, 5);
|
||||
gtk_widget_set_margin_end (box, 5);
|
||||
gtk_widget_set_margin_top (box, 5);
|
||||
gtk_widget_set_margin_bottom (box, 5);
|
||||
gtk_frame_set_child (GTK_FRAME (frame), box);
|
||||
g_object_set (box, "margin", 5, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (frame), box);
|
||||
|
||||
combo = gtk_combo_box_text_new_with_entry ();
|
||||
fill_combo_entry (combo);
|
||||
gtk_box_append (GTK_BOX (box), combo);
|
||||
gtk_container_add (GTK_CONTAINER (box), combo);
|
||||
|
||||
entry = g_object_new (TYPE_MASK_ENTRY, NULL);
|
||||
MASK_ENTRY (entry)->mask = "^([0-9]*|One|Two|2\302\275|Three)$";
|
||||
|
||||
gtk_combo_box_set_child (GTK_COMBO_BOX (combo), entry);
|
||||
gtk_container_remove (GTK_CONTAINER (combo), gtk_bin_get_child (GTK_BIN (combo)));
|
||||
gtk_container_add (GTK_CONTAINER (combo), entry);
|
||||
|
||||
/* A combobox with string IDs */
|
||||
frame = gtk_frame_new ("String IDs");
|
||||
gtk_box_append (GTK_BOX (vbox), frame);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), frame);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_margin_start (box, 5);
|
||||
gtk_widget_set_margin_end (box, 5);
|
||||
gtk_widget_set_margin_top (box, 5);
|
||||
gtk_widget_set_margin_bottom (box, 5);
|
||||
gtk_frame_set_child (GTK_FRAME (frame), box);
|
||||
g_object_set (box, "margin", 5, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (frame), box);
|
||||
|
||||
combo = gtk_combo_box_text_new ();
|
||||
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "never", "Not visible");
|
||||
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "when-active", "Visible when active");
|
||||
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "always", "Always visible");
|
||||
gtk_box_append (GTK_BOX (box), combo);
|
||||
gtk_container_add (GTK_CONTAINER (box), combo);
|
||||
|
||||
entry = gtk_entry_new ();
|
||||
g_object_bind_property (combo, "active-id",
|
||||
entry, "text",
|
||||
G_BINDING_BIDIRECTIONAL);
|
||||
gtk_box_append (GTK_BOX (box), entry);
|
||||
gtk_container_add (GTK_CONTAINER (box), entry);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -1,289 +0,0 @@
|
||||
/* Constraints/Simple
|
||||
*
|
||||
* GtkConstraintLayout provides a layout manager that uses relations
|
||||
* between widgets (also known as "constraints") to compute the position
|
||||
* and size of each child.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SimpleGrid, simple_grid, SIMPLE, GRID, GtkWidget)
|
||||
|
||||
struct _SimpleGrid
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *button1, *button2;
|
||||
GtkWidget *button3;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SimpleGrid, simple_grid, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
simple_grid_dispose (GObject *object)
|
||||
{
|
||||
SimpleGrid *self = SIMPLE_GRID (object);
|
||||
|
||||
g_clear_pointer (&self->button1, gtk_widget_unparent);
|
||||
g_clear_pointer (&self->button2, gtk_widget_unparent);
|
||||
g_clear_pointer (&self->button3, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (simple_grid_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
simple_grid_class_init (SimpleGridClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = simple_grid_dispose;
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
|
||||
}
|
||||
|
||||
/* Layout:
|
||||
*
|
||||
* +-------------------------------------+
|
||||
* | +-----------++-------++-----------+ |
|
||||
* | | Child 1 || Space || Child 2 | |
|
||||
* | +-----------++-------++-----------+ |
|
||||
* | +---------------------------------+ |
|
||||
* | | Child 3 | |
|
||||
* | +---------------------------------+ |
|
||||
* +-------------------------------------+
|
||||
*
|
||||
* Constraints:
|
||||
*
|
||||
* super.start = child1.start - 8
|
||||
* child1.width = child2.width
|
||||
* child1.end = space.start
|
||||
* space.end = child2.start
|
||||
* 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
|
||||
*
|
||||
* To add some flexibility, we make the space
|
||||
* stretchable:
|
||||
*
|
||||
* space.width >= 10
|
||||
* space.width = 100
|
||||
* space.width <= 200
|
||||
*/
|
||||
static void
|
||||
build_constraints (SimpleGrid *self,
|
||||
GtkConstraintLayout *manager)
|
||||
{
|
||||
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);
|
||||
gtk_constraint_layout_add_guide (manager, guide);
|
||||
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->button1),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
|
||||
GTK_CONSTRAINT_RELATION_LE,
|
||||
200.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
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_ATTRIBUTE_WIDTH,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
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_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
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_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
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_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
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_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
self->button1,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
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_ATTRIBUTE_BOTTOM,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
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_ATTRIBUTE_BOTTOM,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
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_ATTRIBUTE_HEIGHT,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
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_ATTRIBUTE_HEIGHT,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
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_ATTRIBUTE_BOTTOM,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
}
|
||||
|
||||
static void
|
||||
simple_grid_init (SimpleGrid *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_constraints (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *header, *box, *grid, *button;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Constraints");
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
|
||||
grid = g_object_new (simple_grid_get_type (), NULL);
|
||||
gtk_widget_set_hexpand (grid, TRUE);
|
||||
gtk_widget_set_vexpand (grid, TRUE);
|
||||
gtk_box_append (GTK_BOX (box), grid);
|
||||
|
||||
button = gtk_button_new_with_label ("Close");
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
gtk_widget_set_hexpand (grid, TRUE);
|
||||
g_signal_connect_swapped (button, "clicked",
|
||||
G_CALLBACK (gtk_window_destroy), window);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
/* Constraints/Interactive
|
||||
*
|
||||
* Demonstrate how constraints can be updates during
|
||||
* user interaction.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_DECLARE_FINAL_TYPE (InteractiveGrid, interactive_grid, INTERACTIVE, GRID, GtkWidget)
|
||||
|
||||
struct _InteractiveGrid
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *button1, *button2;
|
||||
GtkWidget *button3;
|
||||
GtkConstraintGuide *guide;
|
||||
GtkConstraint *constraint;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (InteractiveGrid, interactive_grid, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
interactive_grid_dispose (GObject *object)
|
||||
{
|
||||
InteractiveGrid *self = INTERACTIVE_GRID (object);
|
||||
|
||||
g_clear_pointer (&self->button1, gtk_widget_unparent);
|
||||
g_clear_pointer (&self->button2, gtk_widget_unparent);
|
||||
g_clear_pointer (&self->button3, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (interactive_grid_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
interactive_grid_class_init (InteractiveGridClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = interactive_grid_dispose;
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
|
||||
}
|
||||
|
||||
static void
|
||||
build_constraints (InteractiveGrid *self,
|
||||
GtkConstraintLayout *manager)
|
||||
{
|
||||
self->guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL);
|
||||
gtk_constraint_layout_add_guide (manager, self->guide);
|
||||
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->guide),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
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 (GTK_CONSTRAINT_TARGET (self->button1),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->guide),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->guide),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
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 (GTK_CONSTRAINT_TARGET (self->button3),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->guide),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->button1),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->button1),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->button2),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
}
|
||||
|
||||
static void
|
||||
drag_cb (GtkGestureDrag *drag,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
InteractiveGrid *self)
|
||||
{
|
||||
GtkConstraintLayout *layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (self)));
|
||||
double x, y;
|
||||
|
||||
if (self->constraint)
|
||||
{
|
||||
gtk_constraint_layout_remove_constraint (layout, self->constraint);
|
||||
g_clear_object (&self->constraint);
|
||||
}
|
||||
|
||||
gtk_gesture_drag_get_start_point (drag, &x, &y);
|
||||
self->constraint = gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->guide),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_LEFT,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
x + offset_x,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED);
|
||||
gtk_constraint_layout_add_constraint (layout, g_object_ref (self->constraint));
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
interactive_grid_init (InteractiveGrid *self)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (self);
|
||||
GtkGesture *drag;
|
||||
|
||||
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));
|
||||
|
||||
drag = gtk_gesture_drag_new ();
|
||||
g_signal_connect (drag, "drag-update", G_CALLBACK (drag_cb), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (drag));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_constraints2 (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *header, *box, *grid, *button;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Constraints");
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
|
||||
grid = g_object_new (interactive_grid_get_type (), NULL);
|
||||
gtk_widget_set_hexpand (grid, TRUE);
|
||||
gtk_widget_set_vexpand (grid, TRUE);
|
||||
gtk_box_append (GTK_BOX (box), grid);
|
||||
|
||||
button = gtk_button_new_with_label ("Close");
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
gtk_widget_set_hexpand (grid, TRUE);
|
||||
g_signal_connect_swapped (button, "clicked",
|
||||
G_CALLBACK (gtk_window_destroy), window);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -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_dispose (GObject *object)
|
||||
{
|
||||
VflGrid *self = VFL_GRID (object);
|
||||
|
||||
g_clear_pointer (&self->button1, gtk_widget_unparent);
|
||||
g_clear_pointer (&self->button2, gtk_widget_unparent);
|
||||
g_clear_pointer (&self->button3, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (vfl_grid_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
vfl_grid_class_init (VflGridClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = vfl_grid_dispose;
|
||||
|
||||
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_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Constraints");
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
|
||||
grid = g_object_new (vfl_grid_get_type (), NULL);
|
||||
gtk_widget_set_hexpand (grid, TRUE);
|
||||
gtk_widget_set_vexpand (grid, TRUE);
|
||||
gtk_box_append (GTK_BOX (box), grid);
|
||||
|
||||
button = gtk_button_new_with_label ("Close");
|
||||
gtk_box_append (GTK_BOX (box), button);
|
||||
gtk_widget_set_hexpand (grid, TRUE);
|
||||
g_signal_connect_swapped (button, "clicked",
|
||||
G_CALLBACK (gtk_window_destroy), window);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -9,13 +9,9 @@
|
||||
static void
|
||||
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
|
||||
{
|
||||
GtkWidget *child;
|
||||
|
||||
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
|
||||
for (child = gtk_widget_get_first_child (widget);
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
apply_css (child, provider);
|
||||
if (GTK_IS_CONTAINER (widget))
|
||||
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
@@ -28,34 +24,35 @@ do_css_accordion (GtkWidget *do_widget)
|
||||
GtkWidget *container, *child;
|
||||
GtkStyleProvider *provider;
|
||||
|
||||
window = gtk_window_new ();
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "CSS Accordion");
|
||||
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 600, 300);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_widget_set_halign (container, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (container, GTK_ALIGN_CENTER);
|
||||
gtk_window_set_child (GTK_WINDOW (window), container);
|
||||
gtk_container_add (GTK_CONTAINER (window), container);
|
||||
|
||||
child = gtk_button_new_with_label ("This");
|
||||
gtk_box_append (GTK_BOX (container), child);
|
||||
gtk_container_add (GTK_CONTAINER (container), child);
|
||||
|
||||
child = gtk_button_new_with_label ("Is");
|
||||
gtk_box_append (GTK_BOX (container), child);
|
||||
gtk_container_add (GTK_CONTAINER (container), child);
|
||||
|
||||
child = gtk_button_new_with_label ("A");
|
||||
gtk_box_append (GTK_BOX (container), child);
|
||||
gtk_container_add (GTK_CONTAINER (container), child);
|
||||
|
||||
child = gtk_button_new_with_label ("CSS");
|
||||
gtk_box_append (GTK_BOX (container), child);
|
||||
gtk_container_add (GTK_CONTAINER (container), child);
|
||||
|
||||
child = gtk_button_new_with_label ("Accordion");
|
||||
gtk_box_append (GTK_BOX (container), child);
|
||||
gtk_container_add (GTK_CONTAINER (container), child);
|
||||
|
||||
child = gtk_button_new_with_label (":-)");
|
||||
gtk_box_append (GTK_BOX (container), child);
|
||||
gtk_container_add (GTK_CONTAINER (container), child);
|
||||
|
||||
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
|
||||
gtk_css_provider_load_from_resource (GTK_CSS_PROVIDER (provider), "/css_accordion/css_accordion.css");
|
||||
@@ -66,7 +63,7 @@ do_css_accordion (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
+13
-19
@@ -13,22 +13,19 @@ show_parsing_error (GtkCssProvider *provider,
|
||||
const GError *error,
|
||||
GtkTextBuffer *buffer)
|
||||
{
|
||||
const GtkCssLocation *start_location, *end_location;
|
||||
GtkTextIter start, end;
|
||||
const char *tag_name;
|
||||
|
||||
start_location = gtk_css_section_get_start_location (section);
|
||||
gtk_text_buffer_get_iter_at_line_index (buffer,
|
||||
&start,
|
||||
start_location->lines,
|
||||
start_location->line_bytes);
|
||||
end_location = gtk_css_section_get_end_location (section);
|
||||
gtk_css_section_get_start_line (section),
|
||||
gtk_css_section_get_start_position (section));
|
||||
gtk_text_buffer_get_iter_at_line_index (buffer,
|
||||
&end,
|
||||
end_location->lines,
|
||||
end_location->line_bytes);
|
||||
gtk_css_section_get_end_line (section),
|
||||
gtk_css_section_get_end_position (section));
|
||||
|
||||
if (error->domain == GTK_CSS_PARSER_WARNING)
|
||||
if (g_error_matches (error, GTK_CSS_PROVIDER_ERROR, GTK_CSS_PROVIDER_ERROR_DEPRECATED))
|
||||
tag_name = "warning";
|
||||
else
|
||||
tag_name = "error";
|
||||
@@ -55,13 +52,9 @@ css_text_changed (GtkTextBuffer *buffer,
|
||||
static void
|
||||
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
|
||||
{
|
||||
GtkWidget *child;
|
||||
|
||||
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
|
||||
for (child = gtk_widget_get_first_child (widget);
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
apply_css (child, provider);
|
||||
if (GTK_IS_CONTAINER (widget))
|
||||
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
@@ -76,11 +69,12 @@ do_css_basics (GtkWidget *do_widget)
|
||||
GtkTextBuffer *text;
|
||||
GBytes *bytes;
|
||||
|
||||
window = gtk_window_new ();
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "CSS Basics");
|
||||
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
text = gtk_text_buffer_new (NULL);
|
||||
gtk_text_buffer_create_tag (text,
|
||||
@@ -95,9 +89,9 @@ do_css_basics (GtkWidget *do_widget)
|
||||
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
|
||||
|
||||
container = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_window_set_child (GTK_WINDOW (window), container);
|
||||
gtk_container_add (GTK_CONTAINER (window), container);
|
||||
child = gtk_text_view_new_with_buffer (text);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (container), child);
|
||||
gtk_container_add (GTK_CONTAINER (container), child);
|
||||
g_signal_connect (text, "changed",
|
||||
G_CALLBACK (css_text_changed), provider);
|
||||
|
||||
@@ -116,7 +110,7 @@ do_css_basics (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
* These are the available blend modes.
|
||||
*/
|
||||
struct {
|
||||
const char *name;
|
||||
const char *id;
|
||||
gchar *name;
|
||||
gchar *id;
|
||||
} blend_modes[] =
|
||||
{
|
||||
{ "Color", "color" },
|
||||
@@ -79,7 +79,7 @@ setup_listbox (GtkBuilder *builder,
|
||||
|
||||
normal_row = NULL;
|
||||
listbox = gtk_list_box_new ();
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (WID ("scrolledwindow")), listbox);
|
||||
gtk_container_add (GTK_CONTAINER (WID ("scrolledwindow")), listbox);
|
||||
|
||||
g_signal_connect (listbox, "row-activated", G_CALLBACK (row_activated), provider);
|
||||
|
||||
@@ -95,8 +95,9 @@ setup_listbox (GtkBuilder *builder,
|
||||
"xalign", 0.0,
|
||||
NULL);
|
||||
|
||||
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), label);
|
||||
gtk_list_box_insert (GTK_LIST_BOX (listbox), row, -1);
|
||||
gtk_container_add (GTK_CONTAINER (row), label);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (listbox), row);
|
||||
|
||||
/* The first selected row is "normal" */
|
||||
if (g_strcmp0 (blend_modes[i].id, "normal") == 0)
|
||||
@@ -124,7 +125,7 @@ do_css_blendmodes (GtkWidget *do_widget)
|
||||
|
||||
window = WID ("window");
|
||||
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
/* Setup the CSS provider for window */
|
||||
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
|
||||
@@ -134,14 +135,12 @@ do_css_blendmodes (GtkWidget *do_widget)
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
|
||||
setup_listbox (builder, provider);
|
||||
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -13,23 +13,19 @@ show_parsing_error (GtkCssProvider *provider,
|
||||
const GError *error,
|
||||
GtkTextBuffer *buffer)
|
||||
{
|
||||
const GtkCssLocation *start_location, *end_location;
|
||||
GtkTextIter start, end;
|
||||
const char *tag_name;
|
||||
|
||||
start_location = gtk_css_section_get_start_location (section);
|
||||
gtk_text_buffer_get_iter_at_line_index (buffer,
|
||||
&start,
|
||||
start_location->lines,
|
||||
start_location->line_bytes);
|
||||
end_location = gtk_css_section_get_end_location (section);
|
||||
gtk_css_section_get_start_line (section),
|
||||
gtk_css_section_get_start_position (section));
|
||||
gtk_text_buffer_get_iter_at_line_index (buffer,
|
||||
&end,
|
||||
end_location->lines,
|
||||
end_location->line_bytes);
|
||||
gtk_css_section_get_end_line (section),
|
||||
gtk_css_section_get_end_position (section));
|
||||
|
||||
|
||||
if (error->domain == GTK_CSS_PARSER_WARNING)
|
||||
if (g_error_matches (error, GTK_CSS_PROVIDER_ERROR, GTK_CSS_PROVIDER_ERROR_DEPRECATED))
|
||||
tag_name = "warning";
|
||||
else
|
||||
tag_name = "error";
|
||||
@@ -69,13 +65,9 @@ drawing_area_draw (GtkDrawingArea *da,
|
||||
static void
|
||||
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
|
||||
{
|
||||
GtkWidget *child;
|
||||
|
||||
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
|
||||
for (child = gtk_widget_get_first_child (widget);
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
apply_css (child, provider);
|
||||
if (GTK_IS_CONTAINER (widget))
|
||||
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
@@ -85,40 +77,41 @@ do_css_multiplebgs (GtkWidget *do_widget)
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *paned, *overlay, *child, *sw;
|
||||
GtkWidget *paned, *container, *child;
|
||||
GtkStyleProvider *provider;
|
||||
GtkTextBuffer *text;
|
||||
GBytes *bytes;
|
||||
|
||||
window = gtk_window_new ();
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Multiple Backgrounds");
|
||||
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
overlay = gtk_overlay_new ();
|
||||
gtk_window_set_child (GTK_WINDOW (window), overlay);
|
||||
container = gtk_overlay_new ();
|
||||
gtk_container_add (GTK_CONTAINER (window), container);
|
||||
|
||||
child = gtk_drawing_area_new ();
|
||||
gtk_widget_set_name (child, "canvas");
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (child),
|
||||
drawing_area_draw,
|
||||
NULL, NULL);
|
||||
gtk_overlay_set_child (GTK_OVERLAY (overlay), child);
|
||||
gtk_container_add (GTK_CONTAINER (container), child);
|
||||
|
||||
child = gtk_button_new ();
|
||||
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), child);
|
||||
gtk_overlay_add_overlay (GTK_OVERLAY (container), child);
|
||||
gtk_widget_set_name (child, "bricks-button");
|
||||
gtk_widget_set_halign (child, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (child, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_size_request (child, 250, 84);
|
||||
|
||||
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
|
||||
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), paned);
|
||||
gtk_overlay_add_overlay (GTK_OVERLAY (container), paned);
|
||||
|
||||
/* Need a filler so we get a handle */
|
||||
child = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_paned_set_start_child (GTK_PANED (paned), child);
|
||||
gtk_container_add (GTK_CONTAINER (paned), child);
|
||||
|
||||
text = gtk_text_buffer_new (NULL);
|
||||
gtk_text_buffer_create_tag (text,
|
||||
@@ -132,10 +125,10 @@ do_css_multiplebgs (GtkWidget *do_widget)
|
||||
|
||||
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
|
||||
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_paned_set_end_child (GTK_PANED (paned), sw);
|
||||
container = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (paned), container);
|
||||
child = gtk_text_view_new_with_buffer (text);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child);
|
||||
gtk_container_add (GTK_CONTAINER (container), child);
|
||||
g_signal_connect (text,
|
||||
"changed",
|
||||
G_CALLBACK (css_text_changed),
|
||||
@@ -156,7 +149,7 @@ do_css_multiplebgs (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -12,23 +12,19 @@ show_parsing_error (GtkCssProvider *provider,
|
||||
const GError *error,
|
||||
GtkTextBuffer *buffer)
|
||||
{
|
||||
const GtkCssLocation *start_location, *end_location;
|
||||
GtkTextIter start, end;
|
||||
const char *tag_name;
|
||||
|
||||
start_location = gtk_css_section_get_start_location (section);
|
||||
gtk_text_buffer_get_iter_at_line_index (buffer,
|
||||
&start,
|
||||
start_location->lines,
|
||||
start_location->line_bytes);
|
||||
end_location = gtk_css_section_get_end_location (section);
|
||||
gtk_css_section_get_start_line (section),
|
||||
gtk_css_section_get_start_position (section));
|
||||
gtk_text_buffer_get_iter_at_line_index (buffer,
|
||||
&end,
|
||||
end_location->lines,
|
||||
end_location->line_bytes);
|
||||
gtk_css_section_get_end_line (section),
|
||||
gtk_css_section_get_end_position (section));
|
||||
|
||||
|
||||
if (error->domain == GTK_CSS_PARSER_WARNING)
|
||||
if (g_error_matches (error, GTK_CSS_PROVIDER_ERROR, GTK_CSS_PROVIDER_ERROR_DEPRECATED))
|
||||
tag_name = "warning";
|
||||
else
|
||||
tag_name = "error";
|
||||
@@ -55,13 +51,9 @@ css_text_changed (GtkTextBuffer *buffer,
|
||||
static void
|
||||
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
|
||||
{
|
||||
GtkWidget *child;
|
||||
|
||||
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
|
||||
for (child = gtk_widget_get_first_child (widget);
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
apply_css (child, provider);
|
||||
if (GTK_IS_CONTAINER (widget))
|
||||
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
@@ -76,18 +68,19 @@ do_css_pixbufs (GtkWidget *do_widget)
|
||||
GtkTextBuffer *text;
|
||||
GBytes *bytes;
|
||||
|
||||
window = gtk_window_new ();
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Animated Backgrounds");
|
||||
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
|
||||
gtk_window_set_child (GTK_WINDOW (window), paned);
|
||||
gtk_container_add (GTK_CONTAINER (window), paned);
|
||||
|
||||
/* Need a filler so we get a handle */
|
||||
child = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_paned_set_start_child (GTK_PANED (paned), child);
|
||||
gtk_container_add (GTK_CONTAINER (paned), child);
|
||||
|
||||
text = gtk_text_buffer_new (NULL);
|
||||
gtk_text_buffer_create_tag (text,
|
||||
@@ -102,9 +95,9 @@ do_css_pixbufs (GtkWidget *do_widget)
|
||||
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
|
||||
|
||||
container = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_paned_set_end_child (GTK_PANED (paned), container);
|
||||
gtk_container_add (GTK_CONTAINER (paned), container);
|
||||
child = gtk_text_view_new_with_buffer (text);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (container), child);
|
||||
gtk_container_add (GTK_CONTAINER (container), child);
|
||||
g_signal_connect (text, "changed",
|
||||
G_CALLBACK (css_text_changed), provider);
|
||||
|
||||
@@ -123,7 +116,7 @@ do_css_pixbufs (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -11,22 +11,19 @@ show_parsing_error (GtkCssProvider *provider,
|
||||
const GError *error,
|
||||
GtkTextBuffer *buffer)
|
||||
{
|
||||
const GtkCssLocation *start_location, *end_location;
|
||||
GtkTextIter start, end;
|
||||
const char *tag_name;
|
||||
|
||||
start_location = gtk_css_section_get_start_location (section);
|
||||
gtk_text_buffer_get_iter_at_line_index (buffer,
|
||||
&start,
|
||||
start_location->lines,
|
||||
start_location->line_bytes);
|
||||
end_location = gtk_css_section_get_end_location (section);
|
||||
gtk_css_section_get_start_line (section),
|
||||
gtk_css_section_get_start_position (section));
|
||||
gtk_text_buffer_get_iter_at_line_index (buffer,
|
||||
&end,
|
||||
end_location->lines,
|
||||
end_location->line_bytes);
|
||||
gtk_css_section_get_end_line (section),
|
||||
gtk_css_section_get_end_position (section));
|
||||
|
||||
if (error->domain == GTK_CSS_PARSER_WARNING)
|
||||
if (g_error_matches (error, GTK_CSS_PROVIDER_ERROR, GTK_CSS_PROVIDER_ERROR_DEPRECATED))
|
||||
tag_name = "warning";
|
||||
else
|
||||
tag_name = "error";
|
||||
@@ -53,32 +50,31 @@ css_text_changed (GtkTextBuffer *buffer,
|
||||
static void
|
||||
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
|
||||
{
|
||||
GtkWidget *child;
|
||||
|
||||
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
|
||||
for (child = gtk_widget_get_first_child (widget);
|
||||
child != NULL;
|
||||
child = gtk_widget_get_next_sibling (child))
|
||||
apply_css (child, provider);
|
||||
if (GTK_IS_CONTAINER (widget))
|
||||
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
GtkWidget *
|
||||
create_toolbar (void)
|
||||
{
|
||||
GtkWidget *toolbar;
|
||||
GtkWidget *item;
|
||||
GtkToolItem *item;
|
||||
|
||||
toolbar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
toolbar = gtk_toolbar_new ();
|
||||
gtk_widget_set_valign (toolbar, GTK_ALIGN_CENTER);
|
||||
|
||||
item = gtk_button_new_from_icon_name ("go-next");
|
||||
gtk_box_append (GTK_BOX (toolbar), item);
|
||||
item = gtk_tool_button_new (NULL, NULL);
|
||||
gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "go-next");
|
||||
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
|
||||
|
||||
item = gtk_button_new_from_icon_name ("go-previous");
|
||||
gtk_box_append (GTK_BOX (toolbar), item);
|
||||
item = gtk_tool_button_new (NULL, NULL);
|
||||
gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "go-previous");
|
||||
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
|
||||
|
||||
item = gtk_button_new_with_label ("Hello World");
|
||||
gtk_box_append (GTK_BOX (toolbar), item);
|
||||
item = gtk_tool_button_new (NULL, "Hello World");
|
||||
gtk_tool_item_set_is_important (item, TRUE);
|
||||
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
|
||||
|
||||
return toolbar;
|
||||
}
|
||||
@@ -95,17 +91,18 @@ do_css_shadows (GtkWidget *do_widget)
|
||||
GtkTextBuffer *text;
|
||||
GBytes *bytes;
|
||||
|
||||
window = gtk_window_new ();
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Shadows");
|
||||
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
|
||||
gtk_window_set_child (GTK_WINDOW (window), paned);
|
||||
gtk_container_add (GTK_CONTAINER (window), paned);
|
||||
|
||||
child = create_toolbar ();
|
||||
gtk_paned_set_start_child (GTK_PANED (paned), child);
|
||||
gtk_container_add (GTK_CONTAINER (paned), child);
|
||||
|
||||
text = gtk_text_buffer_new (NULL);
|
||||
gtk_text_buffer_create_tag (text,
|
||||
@@ -120,9 +117,9 @@ do_css_shadows (GtkWidget *do_widget)
|
||||
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
|
||||
|
||||
container = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_paned_set_end_child (GTK_PANED (paned), container);
|
||||
gtk_container_add (GTK_CONTAINER (paned), container);
|
||||
child = gtk_text_view_new_with_buffer (text);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (container), child);
|
||||
gtk_container_add (GTK_CONTAINER (container), child);
|
||||
g_signal_connect (text, "changed",
|
||||
G_CALLBACK (css_text_changed), provider);
|
||||
|
||||
@@ -141,7 +138,7 @@ do_css_shadows (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -24,19 +24,20 @@ 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));
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (on_destroy), NULL);
|
||||
g_object_unref (builder);
|
||||
g_object_set_data_full (G_OBJECT (window), "builder", builder, g_object_unref);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
{
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
}
|
||||
|
||||
return window;
|
||||
|
||||
+37
-149
@@ -1,4 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GdkCursor" id="default_cursor">
|
||||
<property name="name">default</property>
|
||||
@@ -656,10 +655,7 @@
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="margin-start">60</property>
|
||||
<property name="margin-end">60</property>
|
||||
<property name="margin-top">60</property>
|
||||
<property name="margin-bottom">60</property>
|
||||
<property name="margin">60</property>
|
||||
<property name="spacing">10</property>
|
||||
<property name="halign">center</property>
|
||||
<child>
|
||||
@@ -675,10 +671,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -735,10 +728,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -795,10 +785,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -868,10 +855,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -928,10 +912,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -988,10 +969,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1048,10 +1026,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1108,10 +1083,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1181,10 +1153,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1241,10 +1210,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1301,10 +1267,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1361,10 +1324,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1434,10 +1394,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1494,10 +1451,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1554,10 +1508,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1614,10 +1565,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1674,10 +1622,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1734,10 +1679,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1794,10 +1736,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1867,10 +1806,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1927,10 +1863,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -1987,10 +1920,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2047,10 +1977,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2107,10 +2034,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2167,10 +2091,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2227,10 +2148,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2287,10 +2205,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2347,10 +2262,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2407,10 +2319,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2467,10 +2376,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2527,10 +2433,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2587,10 +2490,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2647,10 +2547,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2707,10 +2604,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2780,10 +2674,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
@@ -2840,10 +2731,7 @@
|
||||
<property name="activatable">0</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
|
||||
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
+1
-1
@@ -10,7 +10,7 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
sodipodi:docname="org.gtk.Demo4-symbolic.svg"
|
||||
sodipodi:docname="org.gtk.Demo-symbolic.svg"
|
||||
height="16.03125"
|
||||
id="svg7384"
|
||||
inkscape:version="0.92.4 5da689c313, 2019-01-14"
|
||||
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
@@ -1,27 +1,17 @@
|
||||
<?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">
|
||||
<file>application.c</file>
|
||||
<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>
|
||||
<gresource prefix="/clipboard">
|
||||
<file>demoimage.c</file>
|
||||
<file>demoimage.h</file>
|
||||
</gresource>
|
||||
<gresource prefix="/css_accordion">
|
||||
<file>css_accordion.css</file>
|
||||
<file>reset.css</file>
|
||||
@@ -47,9 +37,6 @@
|
||||
<gresource prefix="/theming_style_classes">
|
||||
<file>theming.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/themes">
|
||||
<file>themes.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/css_pixbufs">
|
||||
<file alias="gtk.css">css_pixbufs.css</file>
|
||||
<file>cssview.css</file>
|
||||
@@ -114,33 +101,10 @@
|
||||
<file>gtkfishbowl.c</file>
|
||||
<file>gtkfishbowl.h</file>
|
||||
</gresource>
|
||||
<gresource prefix="/gears">
|
||||
<file>gtkgears.c</file>
|
||||
<file>gtkgears.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="/listview_colors">
|
||||
<file compressed="true">color.names.txt</file>
|
||||
</gresource>
|
||||
<gresource prefix="/shortcuts">
|
||||
<file>shortcuts.ui</file>
|
||||
<file>shortcuts-builder.ui</file>
|
||||
@@ -177,14 +141,12 @@
|
||||
</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>
|
||||
<file>clipboard.c</file>
|
||||
<file>colorsel.c</file>
|
||||
<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>
|
||||
@@ -196,37 +158,28 @@
|
||||
<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>
|
||||
<file>fixed.c</file>
|
||||
<file>flowbox.c</file>
|
||||
<file>foreigndrawing.c</file>
|
||||
<file>font_features.c</file>
|
||||
<file>fontplane.c</file>
|
||||
<file>fontrendering.c</file>
|
||||
<file>gears.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_colors.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>
|
||||
<file>modelbutton.c</file>
|
||||
<file>overlay.c</file>
|
||||
<file>overlay2.c</file>
|
||||
@@ -236,10 +189,9 @@
|
||||
<file>paintable_animated.c</file>
|
||||
<file>paintable_mediastream.c</file>
|
||||
<file>panes.c</file>
|
||||
<file>password_entry.c</file>
|
||||
<file>peg_solitaire.c</file>
|
||||
<file>pickers.c</file>
|
||||
<file>pixbufs.c</file>
|
||||
<file>popover.c</file>
|
||||
<file>printing.c</file>
|
||||
<file>revealer.c</file>
|
||||
<file>rotated_text.c</file>
|
||||
@@ -247,7 +199,6 @@
|
||||
<file>search_entry.c</file>
|
||||
<file>search_entry2.c</file>
|
||||
<file>shortcuts.c</file>
|
||||
<file>shortcut_triggers.c</file>
|
||||
<file>sizegroup.c</file>
|
||||
<file>sidebar.c</file>
|
||||
<file>sliding_puzzle.c</file>
|
||||
@@ -255,12 +206,9 @@
|
||||
<file>spinbutton.c</file>
|
||||
<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>
|
||||
<file>themes.c</file>
|
||||
<file>transparent.c</file>
|
||||
<file>tree_store.c</file>
|
||||
<file>textmask.c</file>
|
||||
@@ -269,14 +217,14 @@
|
||||
<gresource prefix="/textview">
|
||||
<file>floppybuddy.gif</file>
|
||||
</gresource>
|
||||
<gresource prefix="/tagged_entry">
|
||||
<file>tagstyle.css</file>
|
||||
</gresource>
|
||||
<gresource prefix="/listbox">
|
||||
<file>listbox.ui</file>
|
||||
<file>messages.txt</file>
|
||||
<file>apple-red.png</file>
|
||||
</gresource>
|
||||
<gresource prefix="/popover">
|
||||
<file>popover.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/glarea">
|
||||
<file>glarea-gl.fs.glsl</file>
|
||||
<file>glarea-gl.vs.glsl</file>
|
||||
@@ -310,17 +258,10 @@
|
||||
<gresource prefix="/modelbutton">
|
||||
<file>modelbutton.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/tagged_entry">
|
||||
<file>demotaggedentry.c</file>
|
||||
<file>demotaggedentry.h</file>
|
||||
<gresource prefix="/dnd">
|
||||
<file>dnd.css</file>
|
||||
</gresource>
|
||||
<gresource prefix="/fixed">
|
||||
<file>fixed.css</file>
|
||||
</gresource>
|
||||
<gresource prefix="/fontrendering">
|
||||
<file>fontrendering.ui</file>
|
||||
</gresource>
|
||||
<gresource prefix="/org/gtk/Demo4">
|
||||
<gresource prefix="/org/gtk/Demo">
|
||||
<file>icons/16x16/actions/application-exit.png</file>
|
||||
<file>icons/16x16/actions/document-new.png</file>
|
||||
<file>icons/16x16/actions/document-open.png</file>
|
||||
@@ -339,7 +280,4 @@
|
||||
<file>icons/16x16/status/battery-caution-charging-symbolic.symbolic.png</file>
|
||||
<file>icons/16x16/categories/applications-other.png</file>
|
||||
</gresource>
|
||||
<gresource prefix="/org/gtk/Demo4/gtk">
|
||||
<file preprocess="xml-stripblanks">help-overlay.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
||||
+114
-84
@@ -1,4 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkListStore" id="liststore1">
|
||||
<columns>
|
||||
@@ -22,79 +21,9 @@
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<menu id="menubar">
|
||||
<submenu>
|
||||
<attribute name="label" translatable="yes">_File</attribute>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_New</attribute>
|
||||
<attribute name="action">win.new</attribute>
|
||||
<attribute name="accel"><Control>n</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Open</attribute>
|
||||
<attribute name="action">win.open</attribute>
|
||||
<attribute name="accel"><Control>o</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Save</attribute>
|
||||
<attribute name="action">win.save</attribute>
|
||||
<attribute name="accel"><Control>s</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Save _As</attribute>
|
||||
<attribute name="action">win.save-as</attribute>
|
||||
<attribute name="accel"><Control>q</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Quit</attribute>
|
||||
<attribute name="action">win.quit</attribute>
|
||||
<attribute name="accel"><Control><Shift>s</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</submenu>
|
||||
<submenu>
|
||||
<attribute name="label" translatable="yes">_Edit</attribute>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Copy</attribute>
|
||||
<attribute name="action">win.copy</attribute>
|
||||
<attribute name="accel"><Control>c</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Cut</attribute>
|
||||
<attribute name="action">win.cut</attribute>
|
||||
<attribute name="accel"><Control>x</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Paste</attribute>
|
||||
<attribute name="action">win.paste</attribute>
|
||||
<attribute name="accel"><Control>v</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</submenu>
|
||||
<submenu>
|
||||
<attribute name="label" translatable="yes">_Help</attribute>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Help</attribute>
|
||||
<attribute name="action">win.help</attribute>
|
||||
<attribute name="accel">F1</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_About</attribute>
|
||||
<attribute name="action">win.about</attribute>
|
||||
<attribute name="accel">F7</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</submenu>
|
||||
</menu>
|
||||
<object class="GtkAboutDialog" id="aboutdialog1">
|
||||
<property name="program-name" translatable="yes">Builder demo</property>
|
||||
<property name="logo-icon-name" translatable="yes">gtk3-demo</property>
|
||||
<property name="modal">True</property>
|
||||
<accessibility>
|
||||
<relation target="window1" type="subwindow-of"/>
|
||||
</accessibility>
|
||||
@@ -107,57 +36,159 @@
|
||||
<object class="GtkBox" id="vbox1">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkPopoverMenuBar" id="menubar1">
|
||||
<property name="menu-model">menubar</property>
|
||||
<object class="GtkMenuBar" id="menubar1">
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="a11y-menubar">
|
||||
<property name="AtkObject::accessible-name">The menubar</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem">
|
||||
<property name="label" translatable="yes">_File</property>
|
||||
<property name="use-underline">1</property>
|
||||
<child type="submenu">
|
||||
<object class="GtkMenu">
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="new_item">
|
||||
<property name="label" translatable="yes">_New</property>
|
||||
<property name="use-underline">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="open_item">
|
||||
<property name="label" translatable="yes">_Open</property>
|
||||
<property name="use-underline">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="save_item">
|
||||
<property name="label" translatable="yes">_Save</property>
|
||||
<property name="use-underline">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="save_as_item">
|
||||
<property name="label" translatable="yes">Save _As</property>
|
||||
<property name="use-underline">1</property>
|
||||
<accelerator key="s" modifiers="primary | shift-mask" signal="activate"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="quit_item">
|
||||
<property name="label" translatable="yes">_Quit</property>
|
||||
<property name="use-underline">1</property>
|
||||
<property name="action-name">win.quit</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem">
|
||||
<property name="label" translatable="yes">_Edit</property>
|
||||
<property name="use-underline">1</property>
|
||||
<child type="submenu">
|
||||
<object class="GtkMenu">
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="copy_item">
|
||||
<property name="label" translatable="yes">_Copy</property>
|
||||
<property name="use-underline">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="cut_item">
|
||||
<property name="label" translatable="yes">_Cut</property>
|
||||
<property name="use-underline">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="paste_item">
|
||||
<property name="label" translatable="yes">_Paste</property>
|
||||
<property name="use-underline">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem">
|
||||
<property name="label" translatable="yes">_Help</property>
|
||||
<property name="use-underline">1</property>
|
||||
<child type="submenu">
|
||||
<object class="GtkMenu">
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="help_item">
|
||||
<property name="label" translatable="yes">_Help</property>
|
||||
<property name="use-underline">1</property>
|
||||
<property name="action-name">win.help</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="about_item">
|
||||
<property name="label" translatable="yes">_About</property>
|
||||
<property name="use-underline">1</property>
|
||||
<property name="action-name">win.about</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="toolbar1">
|
||||
<object class="GtkToolbar" id="toolbar1">
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="a11y-toolbar">
|
||||
<property name="AtkObject::accessible-name">The toolbar</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkToolButton">
|
||||
<property name="label" translatable="yes">New</property>
|
||||
<property name="tooltip-text" translatable="yes">Create a new file</property>
|
||||
<property name="icon-name">document-new</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkToolButton">
|
||||
<property name="label" translatable="yes">Open</property>
|
||||
<property name="tooltip-text" translatable="yes">Open a file</property>
|
||||
<property name="icon-name">document-open</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkToolButton">
|
||||
<property name="label" translatable="yes">Save</property>
|
||||
<property name="tooltip-text" translatable="yes">Save a file</property>
|
||||
<property name="icon-name">document-save</property>
|
||||
<property name="is-important">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator"/>
|
||||
<object class="GtkSeparatorToolItem"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkToolButton">
|
||||
<property name="label" translatable="yes">Copy</property>
|
||||
<property name="tooltip-text" translatable="yes">Copy selected object into the clipboard</property>
|
||||
<property name="icon-name">edit-copy</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkToolButton">
|
||||
<property name="label" translatable="yes">Cut</property>
|
||||
<property name="tooltip-text" translatable="yes">Cut selected object into the clipboard</property>
|
||||
<property name="icon-name">edit-cut</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkToolButton">
|
||||
<property name="label" translatable="yes">Paste</property>
|
||||
<property name="tooltip-text" translatable="yes">Paste object from the clipboard</property>
|
||||
<property name="icon-name">edit-paste</property>
|
||||
@@ -167,9 +198,8 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow1">
|
||||
<property name="has-frame">1</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<property name="expand">1</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="treeview1">
|
||||
<property name="model">liststore1</property>
|
||||
|
||||
@@ -1,259 +0,0 @@
|
||||
#include "demoimage.h"
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
struct _DemoImage {
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *image;
|
||||
GtkWidget *popover;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_ICON_NAME = 1
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(DemoImage, demo_image, GTK_TYPE_WIDGET)
|
||||
|
||||
static GdkPaintable *
|
||||
get_image_paintable (GtkImage *image)
|
||||
{
|
||||
const gchar *icon_name;
|
||||
GtkIconTheme *icon_theme;
|
||||
GtkIconPaintable *icon;
|
||||
|
||||
switch (gtk_image_get_storage_type (image))
|
||||
{
|
||||
case GTK_IMAGE_PAINTABLE:
|
||||
return g_object_ref (gtk_image_get_paintable (image));
|
||||
case GTK_IMAGE_ICON_NAME:
|
||||
icon_name = gtk_image_get_icon_name (image);
|
||||
icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (image)));
|
||||
icon = gtk_icon_theme_lookup_icon (icon_theme,
|
||||
icon_name,
|
||||
NULL,
|
||||
48, 1,
|
||||
gtk_widget_get_direction (GTK_WIDGET (image)),
|
||||
0);
|
||||
if (icon == NULL)
|
||||
return NULL;
|
||||
return GDK_PAINTABLE (icon);
|
||||
|
||||
case GTK_IMAGE_EMPTY:
|
||||
case GTK_IMAGE_GICON:
|
||||
default:
|
||||
g_warning ("Image storage type %d not handled",
|
||||
gtk_image_get_storage_type (image));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin (GtkDragSource *source,
|
||||
GdkDrag *drag,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
|
||||
DemoImage *demo = DEMO_IMAGE (widget);
|
||||
GdkPaintable *paintable;
|
||||
|
||||
paintable = get_image_paintable (GTK_IMAGE (demo->image));
|
||||
if (paintable)
|
||||
{
|
||||
gtk_drag_icon_set_from_paintable (drag, paintable, -2, -2);
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
}
|
||||
|
||||
static GdkContentProvider *
|
||||
prepare_drag (GtkDragSource *source,
|
||||
double x,
|
||||
double y,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
|
||||
DemoImage *demo = DEMO_IMAGE (widget);
|
||||
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image));
|
||||
|
||||
return gdk_content_provider_new_typed (GDK_TYPE_PAINTABLE, paintable);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drag_drop (GtkDropTarget *dest,
|
||||
const GValue *value,
|
||||
double x,
|
||||
double y,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
|
||||
DemoImage *demo = DEMO_IMAGE (widget);
|
||||
GdkPaintable *paintable = g_value_get_object (value);
|
||||
|
||||
gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
copy_image (GtkWidget *widget,
|
||||
const char *action_name,
|
||||
GVariant *parameter)
|
||||
{
|
||||
GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
|
||||
DemoImage *demo = DEMO_IMAGE (widget);
|
||||
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image));
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
g_value_init (&value, GDK_TYPE_PAINTABLE);
|
||||
g_value_set_object (&value, paintable);
|
||||
gdk_clipboard_set_value (clipboard, &value);
|
||||
g_value_unset (&value);
|
||||
|
||||
if (paintable)
|
||||
g_object_unref (paintable);
|
||||
}
|
||||
|
||||
static void
|
||||
paste_image (GtkWidget *widget,
|
||||
const char *action_name,
|
||||
GVariant *parameter)
|
||||
{
|
||||
GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
|
||||
DemoImage *demo = DEMO_IMAGE (widget);
|
||||
GdkContentProvider *content = gdk_clipboard_get_content (clipboard);
|
||||
GValue value = G_VALUE_INIT;
|
||||
GdkPaintable *paintable;
|
||||
|
||||
g_value_init (&value, GDK_TYPE_PAINTABLE);
|
||||
if (!gdk_content_provider_get_value (content, &value, NULL))
|
||||
return;
|
||||
|
||||
paintable = GDK_PAINTABLE (g_value_get_object (&value));
|
||||
gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable);
|
||||
g_value_unset (&value);
|
||||
}
|
||||
|
||||
static void
|
||||
pressed_cb (GtkGesture *gesture,
|
||||
int n_press,
|
||||
double x,
|
||||
double y,
|
||||
gpointer data)
|
||||
{
|
||||
DemoImage *demo = DEMO_IMAGE (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
|
||||
|
||||
gtk_popover_popup (GTK_POPOVER (demo->popover));
|
||||
}
|
||||
|
||||
static void
|
||||
demo_image_init (DemoImage *demo)
|
||||
{
|
||||
GMenu *menu;
|
||||
GMenuItem *item;
|
||||
GtkDragSource *source;
|
||||
GtkDropTarget *dest;
|
||||
GtkGesture *gesture;
|
||||
|
||||
demo->image = gtk_image_new ();
|
||||
gtk_image_set_pixel_size (GTK_IMAGE (demo->image), 48);
|
||||
gtk_widget_set_parent (demo->image, GTK_WIDGET (demo));
|
||||
|
||||
menu = g_menu_new ();
|
||||
item = g_menu_item_new (_("_Copy"), "clipboard.copy");
|
||||
g_menu_append_item (menu, item);
|
||||
|
||||
item = g_menu_item_new (_("_Paste"), "clipboard.paste");
|
||||
g_menu_append_item (menu, item);
|
||||
|
||||
demo->popover = gtk_popover_menu_new_from_model (G_MENU_MODEL (menu));
|
||||
gtk_widget_set_parent (demo->popover, GTK_WIDGET (demo));
|
||||
|
||||
source = gtk_drag_source_new ();
|
||||
g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL);
|
||||
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL);
|
||||
gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (source));
|
||||
|
||||
dest = gtk_drop_target_new (GDK_TYPE_PAINTABLE, GDK_ACTION_COPY);
|
||||
g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), NULL);
|
||||
gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
|
||||
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), NULL);
|
||||
gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (gesture));
|
||||
}
|
||||
|
||||
static void
|
||||
demo_image_dispose (GObject *object)
|
||||
{
|
||||
DemoImage *demo = DEMO_IMAGE (object);
|
||||
|
||||
g_clear_pointer (&demo->image, gtk_widget_unparent);
|
||||
g_clear_pointer (&demo->popover, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (demo_image_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_image_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
DemoImage *demo = DEMO_IMAGE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ICON_NAME:
|
||||
g_value_set_string (value, gtk_image_get_icon_name (GTK_IMAGE (demo->image)));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
demo_image_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
DemoImage *demo = DEMO_IMAGE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ICON_NAME:
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (demo->image),
|
||||
g_value_get_string (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
demo_image_class_init (DemoImageClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->dispose = demo_image_dispose;
|
||||
object_class->get_property = demo_image_get_property;
|
||||
object_class->set_property = demo_image_set_property;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ICON_NAME,
|
||||
g_param_spec_string ("icon-name", "Icon name", "Icon name",
|
||||
NULL, G_PARAM_READWRITE));
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
|
||||
gtk_widget_class_install_action (widget_class, "clipboard.copy", NULL, copy_image);
|
||||
gtk_widget_class_install_action (widget_class, "clipboard.paste", NULL, paste_image);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
demo_image_new (const char *icon_name)
|
||||
{
|
||||
return g_object_new (DEMO_TYPE_IMAGE, "icon-name", icon_name, NULL);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define DEMO_TYPE_IMAGE (demo_image_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE(DemoImage, demo_image, DEMO, IMAGE, GtkWidget)
|
||||
|
||||
GtkWidget * demo_image_new (const char *icon_name);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -1,489 +0,0 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2019 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* - Matthias Clasen <mclasen@redhat.com>
|
||||
*
|
||||
* 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 "config.h"
|
||||
|
||||
#include "demotaggedentry.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gtk/gtk-a11y.h>
|
||||
|
||||
typedef struct {
|
||||
GtkWidget *box;
|
||||
GtkWidget *entry;
|
||||
} DemoTaggedEntryPrivate;
|
||||
|
||||
static void demo_tagged_entry_editable_init (GtkEditableInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (DemoTaggedEntry, demo_tagged_entry, GTK_TYPE_WIDGET,
|
||||
G_ADD_PRIVATE (DemoTaggedEntry)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, demo_tagged_entry_editable_init))
|
||||
|
||||
static void
|
||||
demo_tagged_entry_init (DemoTaggedEntry *entry)
|
||||
{
|
||||
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
|
||||
|
||||
priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_widget_set_parent (priv->box, GTK_WIDGET (entry));
|
||||
|
||||
priv->entry = gtk_text_new ();
|
||||
gtk_widget_set_hexpand (priv->entry, TRUE);
|
||||
gtk_widget_set_vexpand (priv->entry, TRUE);
|
||||
gtk_widget_set_hexpand (priv->box, FALSE);
|
||||
gtk_widget_set_vexpand (priv->box, FALSE);
|
||||
gtk_box_append (GTK_BOX (priv->box), priv->entry);
|
||||
gtk_editable_init_delegate (GTK_EDITABLE (entry));
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_dispose (GObject *object)
|
||||
{
|
||||
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (object);
|
||||
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
|
||||
|
||||
if (priv->entry)
|
||||
gtk_editable_finish_delegate (GTK_EDITABLE (entry));
|
||||
|
||||
g_clear_pointer (&priv->entry, gtk_widget_unparent);
|
||||
g_clear_pointer (&priv->box, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (demo_tagged_entry_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_finalize (GObject *object)
|
||||
{
|
||||
G_OBJECT_CLASS (demo_tagged_entry_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
if (gtk_editable_delegate_set_property (object, prop_id, value, pspec))
|
||||
return;
|
||||
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
if (gtk_editable_delegate_get_property (object, prop_id, value, pspec))
|
||||
return;
|
||||
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (widget);
|
||||
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
|
||||
|
||||
gtk_widget_measure (priv->box, orientation, for_size,
|
||||
minimum, natural,
|
||||
minimum_baseline, natural_baseline);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (widget);
|
||||
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
|
||||
|
||||
gtk_widget_size_allocate (priv->box,
|
||||
&(GtkAllocation) { 0, 0, width, height },
|
||||
baseline);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_class_init (DemoTaggedEntryClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = demo_tagged_entry_dispose;
|
||||
object_class->finalize = demo_tagged_entry_finalize;
|
||||
object_class->get_property = demo_tagged_entry_get_property;
|
||||
object_class->set_property = demo_tagged_entry_set_property;
|
||||
|
||||
widget_class->measure = demo_tagged_entry_measure;
|
||||
widget_class->size_allocate = demo_tagged_entry_size_allocate;
|
||||
widget_class->grab_focus = demo_tagged_entry_grab_focus;
|
||||
|
||||
gtk_editable_install_properties (object_class, 1);
|
||||
|
||||
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_ENTRY_ACCESSIBLE);
|
||||
gtk_widget_class_set_css_name (widget_class, "entry");
|
||||
}
|
||||
|
||||
static GtkEditable *
|
||||
demo_tagged_entry_get_delegate (GtkEditable *editable)
|
||||
{
|
||||
DemoTaggedEntry *entry = DEMO_TAGGED_ENTRY (editable);
|
||||
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
|
||||
|
||||
return GTK_EDITABLE (priv->entry);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_editable_init (GtkEditableInterface *iface)
|
||||
{
|
||||
iface->get_delegate = demo_tagged_entry_get_delegate;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
demo_tagged_entry_new (void)
|
||||
{
|
||||
return GTK_WIDGET (g_object_new (DEMO_TYPE_TAGGED_ENTRY, NULL));
|
||||
}
|
||||
|
||||
void
|
||||
demo_tagged_entry_add_tag (DemoTaggedEntry *entry,
|
||||
GtkWidget *tag)
|
||||
{
|
||||
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
|
||||
|
||||
g_return_if_fail (DEMO_IS_TAGGED_ENTRY (entry));
|
||||
|
||||
gtk_box_append (GTK_BOX (priv->box), tag);
|
||||
}
|
||||
|
||||
void
|
||||
demo_tagged_entry_insert_tag_after (DemoTaggedEntry *entry,
|
||||
GtkWidget *tag,
|
||||
GtkWidget *sibling)
|
||||
{
|
||||
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
|
||||
|
||||
g_return_if_fail (DEMO_IS_TAGGED_ENTRY (entry));
|
||||
|
||||
if (sibling == NULL)
|
||||
gtk_box_append (GTK_BOX (priv->box), tag);
|
||||
else
|
||||
gtk_box_insert_child_after (GTK_BOX (priv->box), tag, sibling);
|
||||
}
|
||||
|
||||
void
|
||||
demo_tagged_entry_remove_tag (DemoTaggedEntry *entry,
|
||||
GtkWidget *tag)
|
||||
{
|
||||
DemoTaggedEntryPrivate *priv = demo_tagged_entry_get_instance_private (entry);
|
||||
|
||||
g_return_if_fail (DEMO_IS_TAGGED_ENTRY (entry));
|
||||
|
||||
gtk_box_remove (GTK_BOX (priv->box), tag);
|
||||
}
|
||||
|
||||
struct _DemoTaggedEntryTag
|
||||
{
|
||||
GtkWidget parent;
|
||||
GtkWidget *box;
|
||||
GtkWidget *label;
|
||||
GtkWidget *button;
|
||||
|
||||
gboolean has_close_button;
|
||||
char *style;
|
||||
};
|
||||
|
||||
struct _DemoTaggedEntryTagClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_LABEL,
|
||||
PROP_HAS_CLOSE_BUTTON,
|
||||
};
|
||||
|
||||
enum {
|
||||
SIGNAL_CLICKED,
|
||||
SIGNAL_BUTTON_CLICKED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0, };
|
||||
|
||||
G_DEFINE_TYPE (DemoTaggedEntryTag, demo_tagged_entry_tag, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
on_released (GtkGestureClick *gesture,
|
||||
int n_press,
|
||||
double x,
|
||||
double y,
|
||||
DemoTaggedEntryTag *tag)
|
||||
{
|
||||
g_signal_emit (tag, signals[SIGNAL_CLICKED], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_tag_init (DemoTaggedEntryTag *tag)
|
||||
{
|
||||
GtkGesture *gesture;
|
||||
GtkCssProvider *provider;
|
||||
|
||||
tag->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_widget_set_parent (tag->box, GTK_WIDGET (tag));
|
||||
tag->label = gtk_label_new ("");
|
||||
gtk_box_append (GTK_BOX (tag->box), tag->label);
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
g_signal_connect (gesture, "released", G_CALLBACK (on_released), tag);
|
||||
gtk_widget_add_controller (GTK_WIDGET (tag), GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_resource (provider, "/tagged_entry/tagstyle.css");
|
||||
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||||
GTK_STYLE_PROVIDER (provider),
|
||||
800);
|
||||
g_object_unref (provider);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_tag_dispose (GObject *object)
|
||||
{
|
||||
DemoTaggedEntryTag *tag = DEMO_TAGGED_ENTRY_TAG (object);
|
||||
|
||||
g_clear_pointer (&tag->box, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (demo_tagged_entry_tag_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_tag_finalize (GObject *object)
|
||||
{
|
||||
DemoTaggedEntryTag *tag = DEMO_TAGGED_ENTRY_TAG (object);
|
||||
|
||||
g_clear_pointer (&tag->box, gtk_widget_unparent);
|
||||
g_clear_pointer (&tag->style, g_free);
|
||||
|
||||
G_OBJECT_CLASS (demo_tagged_entry_tag_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_tag_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
DemoTaggedEntryTag *tag = DEMO_TAGGED_ENTRY_TAG (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_LABEL:
|
||||
demo_tagged_entry_tag_set_label (tag, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_HAS_CLOSE_BUTTON:
|
||||
demo_tagged_entry_tag_set_has_close_button (tag, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_tag_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
DemoTaggedEntryTag *tag = DEMO_TAGGED_ENTRY_TAG (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_LABEL:
|
||||
g_value_set_string (value, demo_tagged_entry_tag_get_label (tag));
|
||||
break;
|
||||
|
||||
case PROP_HAS_CLOSE_BUTTON:
|
||||
g_value_set_boolean (value, demo_tagged_entry_tag_get_has_close_button (tag));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_tag_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
DemoTaggedEntryTag *tag = DEMO_TAGGED_ENTRY_TAG (widget);
|
||||
|
||||
gtk_widget_measure (tag->box, orientation, for_size,
|
||||
minimum, natural,
|
||||
minimum_baseline, natural_baseline);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_tag_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
DemoTaggedEntryTag *tag = DEMO_TAGGED_ENTRY_TAG (widget);
|
||||
|
||||
gtk_widget_size_allocate (tag->box,
|
||||
&(GtkAllocation) { 0, 0, width, height },
|
||||
baseline);
|
||||
}
|
||||
|
||||
static void
|
||||
demo_tagged_entry_tag_class_init (DemoTaggedEntryTagClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->dispose = demo_tagged_entry_tag_dispose;
|
||||
object_class->finalize = demo_tagged_entry_tag_finalize;
|
||||
object_class->set_property = demo_tagged_entry_tag_set_property;
|
||||
object_class->get_property = demo_tagged_entry_tag_get_property;
|
||||
|
||||
widget_class->measure = demo_tagged_entry_tag_measure;
|
||||
widget_class->size_allocate = demo_tagged_entry_tag_size_allocate;
|
||||
|
||||
signals[SIGNAL_CLICKED] =
|
||||
g_signal_new ("clicked",
|
||||
DEMO_TYPE_TAGGED_ENTRY_TAG,
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
signals[SIGNAL_BUTTON_CLICKED] =
|
||||
g_signal_new ("button-clicked",
|
||||
DEMO_TYPE_TAGGED_ENTRY_TAG,
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
g_object_class_install_property (object_class, PROP_LABEL,
|
||||
g_param_spec_string ("label", "Label", "Label",
|
||||
NULL, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (object_class, PROP_HAS_CLOSE_BUTTON,
|
||||
g_param_spec_boolean ("has-close-button", "Has close button", "Whether this tag has a close button",
|
||||
FALSE, G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
|
||||
|
||||
gtk_widget_class_set_css_name (widget_class, "tag");
|
||||
}
|
||||
|
||||
DemoTaggedEntryTag *
|
||||
demo_tagged_entry_tag_new (const char *label)
|
||||
{
|
||||
return DEMO_TAGGED_ENTRY_TAG (g_object_new (DEMO_TYPE_TAGGED_ENTRY_TAG,
|
||||
"label", label,
|
||||
NULL));
|
||||
}
|
||||
|
||||
const char *
|
||||
demo_tagged_entry_tag_get_label (DemoTaggedEntryTag *tag)
|
||||
{
|
||||
g_return_val_if_fail (DEMO_IS_TAGGED_ENTRY_TAG (tag), NULL);
|
||||
|
||||
return gtk_label_get_label (GTK_LABEL (tag->label));
|
||||
}
|
||||
|
||||
void
|
||||
demo_tagged_entry_tag_set_label (DemoTaggedEntryTag *tag,
|
||||
const char *label)
|
||||
{
|
||||
g_return_if_fail (DEMO_IS_TAGGED_ENTRY_TAG (tag));
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (tag->label), label);
|
||||
}
|
||||
|
||||
static void
|
||||
on_button_clicked (GtkButton *button,
|
||||
DemoTaggedEntryTag *tag)
|
||||
{
|
||||
g_signal_emit (tag, signals[SIGNAL_BUTTON_CLICKED], 0);
|
||||
}
|
||||
|
||||
void
|
||||
demo_tagged_entry_tag_set_has_close_button (DemoTaggedEntryTag *tag,
|
||||
gboolean has_close_button)
|
||||
{
|
||||
g_return_if_fail (DEMO_IS_TAGGED_ENTRY_TAG (tag));
|
||||
|
||||
if ((tag->button != NULL) == has_close_button)
|
||||
return;
|
||||
|
||||
if (!has_close_button && tag->button)
|
||||
{
|
||||
gtk_box_remove (GTK_BOX (tag->box), tag->button);
|
||||
tag->button = NULL;
|
||||
}
|
||||
else if (has_close_button && tag->button == NULL)
|
||||
{
|
||||
GtkWidget *image;
|
||||
|
||||
image = gtk_image_new_from_icon_name ("window-close-symbolic");
|
||||
tag->button = gtk_button_new ();
|
||||
gtk_box_append (GTK_BOX (tag->button), image);
|
||||
gtk_widget_set_halign (tag->button, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (tag->button, GTK_ALIGN_CENTER);
|
||||
gtk_button_set_has_frame (GTK_BUTTON (tag->button), FALSE);
|
||||
gtk_box_append (GTK_BOX (tag->box), tag->button);
|
||||
g_signal_connect (tag->button, "clicked", G_CALLBACK (on_button_clicked), tag);
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (tag), "has-close-button");
|
||||
}
|
||||
|
||||
gboolean
|
||||
demo_tagged_entry_tag_get_has_close_button (DemoTaggedEntryTag *tag)
|
||||
{
|
||||
g_return_val_if_fail (DEMO_IS_TAGGED_ENTRY_TAG (tag), FALSE);
|
||||
|
||||
return tag->button != NULL;
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2019 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* - Matthias Clasen <mclasen@redhat.com>
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __DEMO_TAGGED_ENTRY_H__
|
||||
#define __DEMO_TAGGED_ENTRY_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define DEMO_TYPE_TAGGED_ENTRY (demo_tagged_entry_get_type ())
|
||||
#define DEMO_TAGGED_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEMO_TYPE_TAGGED_ENTRY, DemoTaggedEntry))
|
||||
#define DEMO_TAGGED_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DEMO_TYPE_TAGGED_ENTRY, DemoTaggedEntryClass))
|
||||
#define DEMO_IS_TAGGED_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEMO_TYPE_TAGGED_ENTRY))
|
||||
#define DEMO_IS_TAGGED_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DEMO_TYPE_TAGGED_ENTRY))
|
||||
#define DEMO_TAGGED_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DEMO_TYPE_TAGGED_ENTRY, DemoTaggedEntryClass))
|
||||
|
||||
typedef struct _DemoTaggedEntry DemoTaggedEntry;
|
||||
typedef struct _DemoTaggedEntryClass DemoTaggedEntryClass;
|
||||
|
||||
struct _DemoTaggedEntry
|
||||
{
|
||||
GtkWidget parent;
|
||||
};
|
||||
|
||||
struct _DemoTaggedEntryClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
#define DEMO_TYPE_TAGGED_ENTRY_TAG (demo_tagged_entry_tag_get_type ())
|
||||
#define DEMO_TAGGED_ENTRY_TAG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEMO_TYPE_TAGGED_ENTRY_TAG, DemoTaggedEntryTag))
|
||||
#define DEMO_TAGGED_ENTRY_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DEMO_TYPE_TAGGED_ENTRY_TAG, DemoTaggedEntryTag))
|
||||
#define DEMO_IS_TAGGED_ENTRY_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEMO_TYPE_TAGGED_ENTRY_TAG))
|
||||
#define DEMO_IS_TAGGED_ENTRY_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DEMO_TYPE_TAGGED_ENTRY_TAG))
|
||||
#define DEMO_TAGGED_ENTRY_TAG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DEMO_TYPE_TAGGED_ENTRY_TAG, DemoTaggedEntryTagClass))
|
||||
|
||||
typedef struct _DemoTaggedEntryTag DemoTaggedEntryTag;
|
||||
typedef struct _DemoTaggedEntryTagClass DemoTaggedEntryTagClass;
|
||||
|
||||
|
||||
GType demo_tagged_entry_get_type (void) G_GNUC_CONST;
|
||||
GType demo_tagged_entry_tag_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GtkWidget * demo_tagged_entry_new (void);
|
||||
|
||||
void demo_tagged_entry_add_tag (DemoTaggedEntry *entry,
|
||||
GtkWidget *tag);
|
||||
|
||||
void demo_tagged_entry_insert_tag_after (DemoTaggedEntry *entry,
|
||||
GtkWidget *tag,
|
||||
GtkWidget *sibling);
|
||||
|
||||
void demo_tagged_entry_remove_tag (DemoTaggedEntry *entry,
|
||||
GtkWidget *tag);
|
||||
|
||||
DemoTaggedEntryTag *
|
||||
demo_tagged_entry_tag_new (const char *label);
|
||||
|
||||
const char * demo_tagged_entry_tag_get_label (DemoTaggedEntryTag *tag);
|
||||
|
||||
void demo_tagged_entry_tag_set_label (DemoTaggedEntryTag *tag,
|
||||
const char *label);
|
||||
|
||||
gboolean demo_tagged_entry_tag_get_has_close_button (DemoTaggedEntryTag *tag);
|
||||
|
||||
void demo_tagged_entry_tag_set_has_close_button (DemoTaggedEntryTag *tag,
|
||||
gboolean has_close_button);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __DEMO_TAGGED_ENTRY_H__ */
|
||||
+31
-63
@@ -25,36 +25,11 @@ message_dialog_clicked (GtkButton *button,
|
||||
"number of times:");
|
||||
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
|
||||
"%d", i);
|
||||
g_signal_connect (dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
|
||||
gtk_widget_show (dialog);
|
||||
gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
gtk_widget_destroy (dialog);
|
||||
i++;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GtkWidget *local_entry1;
|
||||
GtkWidget *local_entry2;
|
||||
GtkWidget *global_entry1;
|
||||
GtkWidget *global_entry2;
|
||||
} ResponseData;
|
||||
|
||||
static void
|
||||
on_dialog_response (GtkDialog *dialog,
|
||||
int response,
|
||||
gpointer user_data)
|
||||
{
|
||||
ResponseData *data = user_data;
|
||||
|
||||
if (response == GTK_RESPONSE_OK)
|
||||
{
|
||||
gtk_editable_set_text (GTK_EDITABLE (data->global_entry1),
|
||||
gtk_editable_get_text (GTK_EDITABLE (data->local_entry1)));
|
||||
gtk_editable_set_text (GTK_EDITABLE (data->global_entry2),
|
||||
gtk_editable_get_text (GTK_EDITABLE (data->local_entry2)));
|
||||
}
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (dialog));
|
||||
}
|
||||
|
||||
static void
|
||||
interactive_dialog_clicked (GtkButton *button,
|
||||
gpointer user_data)
|
||||
@@ -67,7 +42,7 @@ interactive_dialog_clicked (GtkButton *button,
|
||||
GtkWidget *local_entry1;
|
||||
GtkWidget *local_entry2;
|
||||
GtkWidget *label;
|
||||
ResponseData *data;
|
||||
gint response;
|
||||
|
||||
dialog = gtk_dialog_new_with_buttons ("Interactive Dialog",
|
||||
GTK_WINDOW (window),
|
||||
@@ -81,20 +56,20 @@ interactive_dialog_clicked (GtkButton *button,
|
||||
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
|
||||
gtk_box_append (GTK_BOX (content_area), hbox);
|
||||
gtk_container_add (GTK_CONTAINER (content_area), hbox);
|
||||
|
||||
image = gtk_image_new_from_icon_name ("dialog-question");
|
||||
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
|
||||
gtk_box_append (GTK_BOX (hbox), image);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), image);
|
||||
|
||||
table = gtk_grid_new ();
|
||||
gtk_grid_set_row_spacing (GTK_GRID (table), 4);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (table), 4);
|
||||
gtk_box_append (GTK_BOX (hbox), table);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), table);
|
||||
label = gtk_label_new_with_mnemonic ("_Entry 1");
|
||||
gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
|
||||
local_entry1 = gtk_entry_new ();
|
||||
gtk_editable_set_text (GTK_EDITABLE (local_entry1), gtk_editable_get_text (GTK_EDITABLE (entry1)));
|
||||
gtk_entry_set_text (GTK_ENTRY (local_entry1), gtk_entry_get_text (GTK_ENTRY (entry1)));
|
||||
gtk_grid_attach (GTK_GRID (table), local_entry1, 1, 0, 1, 1);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), local_entry1);
|
||||
|
||||
@@ -102,22 +77,19 @@ interactive_dialog_clicked (GtkButton *button,
|
||||
gtk_grid_attach (GTK_GRID (table), label, 0, 1, 1, 1);
|
||||
|
||||
local_entry2 = gtk_entry_new ();
|
||||
gtk_editable_set_text (GTK_EDITABLE (local_entry2), gtk_editable_get_text (GTK_EDITABLE (entry2)));
|
||||
gtk_entry_set_text (GTK_ENTRY (local_entry2), gtk_entry_get_text (GTK_ENTRY (entry2)));
|
||||
gtk_grid_attach (GTK_GRID (table), local_entry2, 1, 1, 1, 1);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), local_entry2);
|
||||
|
||||
data = g_new (ResponseData, 1);
|
||||
data->local_entry1 = local_entry1;
|
||||
data->local_entry2 = local_entry2;
|
||||
data->global_entry1 = entry1;
|
||||
data->global_entry2 = entry2;
|
||||
response = gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
|
||||
g_signal_connect_data (dialog, "response",
|
||||
G_CALLBACK (on_dialog_response),
|
||||
data, (GClosureNotify) g_free,
|
||||
0);
|
||||
if (response == GTK_RESPONSE_OK)
|
||||
{
|
||||
gtk_entry_set_text (GTK_ENTRY (entry1), gtk_entry_get_text (GTK_ENTRY (local_entry1)));
|
||||
gtk_entry_set_text (GTK_ENTRY (entry2), gtk_entry_get_text (GTK_ENTRY (local_entry2)));
|
||||
}
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
@@ -133,51 +105,47 @@ do_dialog (GtkWidget *do_widget)
|
||||
|
||||
if (!window)
|
||||
{
|
||||
window = gtk_window_new ();
|
||||
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), "Dialogs and Message Boxes");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
frame = gtk_frame_new ("Dialogs");
|
||||
gtk_widget_set_margin_start (frame, 8);
|
||||
gtk_widget_set_margin_end (frame, 8);
|
||||
gtk_widget_set_margin_top (frame, 8);
|
||||
gtk_widget_set_margin_bottom (frame, 8);
|
||||
gtk_window_set_child (GTK_WINDOW (window), frame);
|
||||
g_object_set (frame, "margin", 8, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (window), frame);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
||||
gtk_widget_set_margin_start (vbox, 8);
|
||||
gtk_widget_set_margin_end (vbox, 8);
|
||||
gtk_widget_set_margin_top (vbox, 8);
|
||||
gtk_widget_set_margin_bottom (vbox, 8);
|
||||
gtk_frame_set_child (GTK_FRAME (frame), vbox);
|
||||
g_object_set (vbox, "margin", 8, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
||||
|
||||
/* Standard message dialog */
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
|
||||
gtk_box_append (GTK_BOX (vbox), hbox);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
||||
button = gtk_button_new_with_mnemonic ("_Message Dialog");
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (message_dialog_clicked), NULL);
|
||||
gtk_box_append (GTK_BOX (hbox), button);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), button);
|
||||
|
||||
gtk_box_append (GTK_BOX (vbox), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
|
||||
gtk_container_add (GTK_CONTAINER (vbox), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
|
||||
|
||||
/* Interactive dialog*/
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
|
||||
gtk_box_append (GTK_BOX (vbox), hbox);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
||||
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
|
||||
button = gtk_button_new_with_mnemonic ("_Interactive Dialog");
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (interactive_dialog_clicked), NULL);
|
||||
gtk_box_append (GTK_BOX (hbox), vbox2);
|
||||
gtk_box_append (GTK_BOX (vbox2), button);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), vbox2);
|
||||
gtk_container_add (GTK_CONTAINER (vbox2), button);
|
||||
|
||||
table = gtk_grid_new ();
|
||||
gtk_grid_set_row_spacing (GTK_GRID (table), 4);
|
||||
gtk_grid_set_column_spacing (GTK_GRID (table), 4);
|
||||
gtk_box_append (GTK_BOX (hbox), table);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), table);
|
||||
|
||||
label = gtk_label_new_with_mnemonic ("_Entry 1");
|
||||
gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
|
||||
@@ -196,7 +164,7 @@ do_dialog (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
+232
-471
@@ -1,418 +1,235 @@
|
||||
/* Drag-and-Drop
|
||||
*
|
||||
* This demo shows dragging colors and widgets.
|
||||
* The items in this demo can be moved, recolored
|
||||
* and rotated.
|
||||
* I can't believe its not glade!
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <string.h>
|
||||
|
||||
G_DECLARE_FINAL_TYPE (CanvasItem, canvas_item, CANVAS, ITEM, GtkWidget)
|
||||
|
||||
struct _CanvasItem {
|
||||
GtkWidget parent;
|
||||
|
||||
GtkWidget *fixed;
|
||||
GtkWidget *label;
|
||||
|
||||
double r;
|
||||
double angle;
|
||||
double delta;
|
||||
|
||||
GtkWidget *editor;
|
||||
typedef struct _GtkDemoWidget GtkDemoWidget;
|
||||
struct _GtkDemoWidget
|
||||
{
|
||||
GType type;
|
||||
union {
|
||||
char *text;
|
||||
gboolean active;
|
||||
};
|
||||
};
|
||||
|
||||
struct _CanvasItemClass {
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (CanvasItem, canvas_item, GTK_TYPE_WIDGET)
|
||||
|
||||
static int n_items = 0;
|
||||
|
||||
static void
|
||||
set_color (CanvasItem *item,
|
||||
GdkRGBA *color)
|
||||
static gpointer
|
||||
copy_demo_widget (gpointer data)
|
||||
{
|
||||
char *css;
|
||||
char *str;
|
||||
GtkStyleContext *context;
|
||||
GtkCssProvider *provider;
|
||||
GtkDemoWidget *demo = g_memdup (data, sizeof (GtkDemoWidget));
|
||||
|
||||
str = gdk_rgba_to_string (color);
|
||||
css = g_strdup_printf ("* { background: %s; padding: 10px; margin: 1px; }", str);
|
||||
if (demo->type == GTK_TYPE_LABEL)
|
||||
demo->text = g_strdup (demo->text);
|
||||
|
||||
context = gtk_widget_get_style_context (item->label);
|
||||
provider = g_object_get_data (G_OBJECT (context), "style-provider");
|
||||
if (provider)
|
||||
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider));
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider, css, -1);
|
||||
gtk_style_context_add_provider (gtk_widget_get_style_context (item->label), GTK_STYLE_PROVIDER (provider), 800);
|
||||
g_object_set_data_full (G_OBJECT (context), "style-provider", provider, g_object_unref);
|
||||
|
||||
g_free (str);
|
||||
g_free (css);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
item_drag_drop (GtkDropTarget *dest,
|
||||
const GValue *value,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
GtkWidget *label = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
|
||||
CanvasItem *item = CANVAS_ITEM (gtk_widget_get_parent (gtk_widget_get_parent (label)));
|
||||
|
||||
set_color (item, g_value_get_boxed (value));
|
||||
|
||||
return TRUE;
|
||||
return demo;
|
||||
}
|
||||
|
||||
static void
|
||||
apply_transform (CanvasItem *item)
|
||||
free_demo_widget (gpointer data)
|
||||
{
|
||||
GskTransform *transform;
|
||||
double x, y;
|
||||
GtkDemoWidget *demo = data;
|
||||
|
||||
x = gtk_widget_get_allocated_width (item->label) / 2.0;
|
||||
y = gtk_widget_get_allocated_height (item->label) / 2.0;
|
||||
item->r = sqrt (x*x + y*y);
|
||||
if (demo->type == GTK_TYPE_LABEL)
|
||||
g_free (demo->text);
|
||||
|
||||
transform = gsk_transform_translate (
|
||||
gsk_transform_rotate (
|
||||
gsk_transform_translate (NULL,
|
||||
&(graphene_point_t) { item->r, item->r }),
|
||||
item->angle + item->delta),
|
||||
&(graphene_point_t) { - x, - y });
|
||||
|
||||
gtk_fixed_set_child_transform (GTK_FIXED (item->fixed), item->label, transform);
|
||||
gsk_transform_unref (transform);
|
||||
g_free (demo);
|
||||
}
|
||||
|
||||
static void
|
||||
angle_changed (GtkGestureRotate *gesture,
|
||||
double angle,
|
||||
double delta)
|
||||
#define GTK_TYPE_DEMO_WIDGET (gtk_demo_widget_get_type ())
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GtkDemoWidget, gtk_demo_widget, copy_demo_widget, free_demo_widget)
|
||||
|
||||
static GtkDemoWidget *
|
||||
serialize_widget (GtkWidget *widget)
|
||||
{
|
||||
CanvasItem *item = CANVAS_ITEM (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
|
||||
GtkDemoWidget *demo;
|
||||
|
||||
item->delta = angle / M_PI * 180.0;
|
||||
demo = g_new0 (GtkDemoWidget, 1);
|
||||
demo->type = G_OBJECT_TYPE (widget);
|
||||
|
||||
apply_transform (item);
|
||||
}
|
||||
if (GTK_IS_LABEL (widget))
|
||||
{
|
||||
demo->text = g_strdup (gtk_label_get_text (GTK_LABEL (widget)));
|
||||
}
|
||||
else if (GTK_IS_SPINNER (widget))
|
||||
{
|
||||
g_object_get (widget, "active", &demo->active, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("Type %s not supported\n", g_type_name (demo->type));
|
||||
}
|
||||
|
||||
static void
|
||||
rotate_done (GtkGesture *gesture)
|
||||
{
|
||||
CanvasItem *item = CANVAS_ITEM (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
|
||||
|
||||
item->angle = item->angle + item->delta;
|
||||
item->delta = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
click_done (GtkGesture *gesture)
|
||||
{
|
||||
GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
|
||||
GtkWidget *canvas = gtk_widget_get_parent (item);
|
||||
GtkWidget *last_child;
|
||||
|
||||
last_child = gtk_widget_get_last_child (canvas);
|
||||
if (item != last_child)
|
||||
gtk_widget_insert_after (item, canvas, last_child);
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_item_init (CanvasItem *item)
|
||||
{
|
||||
char *text;
|
||||
char *id;
|
||||
GdkRGBA rgba;
|
||||
GtkDropTarget *dest;
|
||||
GtkGesture *gesture;
|
||||
|
||||
n_items++;
|
||||
|
||||
text = g_strdup_printf ("Item %d", n_items);
|
||||
item->label = gtk_label_new (text);
|
||||
g_free (text);
|
||||
|
||||
item->fixed = gtk_fixed_new ();
|
||||
gtk_widget_set_parent (item->fixed, GTK_WIDGET (item));
|
||||
gtk_fixed_put (GTK_FIXED (item->fixed), item->label, 0, 0);
|
||||
|
||||
gtk_widget_add_css_class (item->label, "frame");
|
||||
|
||||
id = g_strdup_printf ("item%d", n_items);
|
||||
gtk_widget_set_name (item->label, id);
|
||||
g_free (id);
|
||||
|
||||
gdk_rgba_parse (&rgba, "yellow");
|
||||
set_color (item, &rgba);
|
||||
|
||||
item->angle = 0;
|
||||
|
||||
dest = gtk_drop_target_new (GDK_TYPE_RGBA, GDK_ACTION_COPY);
|
||||
g_signal_connect (dest, "drop", G_CALLBACK (item_drag_drop), NULL);
|
||||
gtk_widget_add_controller (GTK_WIDGET (item->label), GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
gesture = gtk_gesture_rotate_new ();
|
||||
g_signal_connect (gesture, "angle-changed", G_CALLBACK (angle_changed), NULL);
|
||||
g_signal_connect (gesture, "end", G_CALLBACK (rotate_done), NULL);
|
||||
gtk_widget_add_controller (GTK_WIDGET (item), GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
g_signal_connect (gesture, "released", G_CALLBACK (click_done), NULL);
|
||||
gtk_widget_add_controller (GTK_WIDGET (item), GTK_EVENT_CONTROLLER (gesture));
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_item_dispose (GObject *object)
|
||||
{
|
||||
CanvasItem *item = CANVAS_ITEM (object);
|
||||
|
||||
g_clear_pointer (&item->fixed, gtk_widget_unparent);
|
||||
g_clear_pointer (&item->editor, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (canvas_item_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_item_map (GtkWidget *widget)
|
||||
{
|
||||
CanvasItem *item = CANVAS_ITEM (widget);
|
||||
|
||||
GTK_WIDGET_CLASS (canvas_item_parent_class)->map (widget);
|
||||
|
||||
apply_transform (item);
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_item_class_init (CanvasItemClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->dispose = canvas_item_dispose;
|
||||
|
||||
widget_class->map = canvas_item_map;
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||
gtk_widget_class_set_css_name (widget_class, "item");
|
||||
return demo;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
canvas_item_new (void)
|
||||
deserialize_widget (GtkDemoWidget *demo)
|
||||
{
|
||||
CanvasItem *item = g_object_new (canvas_item_get_type (), NULL);
|
||||
GtkWidget *widget = NULL;
|
||||
|
||||
return GTK_WIDGET (item);
|
||||
if (demo->type == GTK_TYPE_LABEL)
|
||||
{
|
||||
widget = gtk_label_new (demo->text);
|
||||
}
|
||||
else if (demo->type == GTK_TYPE_SPINNER)
|
||||
{
|
||||
widget = g_object_new (demo->type, "active", demo->active, NULL);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (widget), "demo");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("Type %s not supported\n", g_type_name (demo->type));
|
||||
}
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
static GdkPaintable *
|
||||
canvas_item_get_drag_icon (CanvasItem *item)
|
||||
{
|
||||
return gtk_widget_paintable_new (item->fixed);
|
||||
}
|
||||
static double pos_x, pos_y;
|
||||
|
||||
static gboolean
|
||||
canvas_item_is_editing (CanvasItem *item)
|
||||
static void
|
||||
new_label_cb (GtkMenuItem *item,
|
||||
gpointer data)
|
||||
{
|
||||
return item->editor != NULL;
|
||||
GtkFixed *fixed = data;
|
||||
GtkWidget *widget;
|
||||
|
||||
widget = gtk_label_new ("Label");
|
||||
gtk_fixed_put (fixed, widget, pos_x, pos_y);
|
||||
}
|
||||
|
||||
static void
|
||||
scale_changed (GtkRange *range,
|
||||
CanvasItem *item)
|
||||
new_spinner_cb (GtkMenuItem *item,
|
||||
gpointer data)
|
||||
{
|
||||
item->angle = gtk_range_get_value (range);
|
||||
apply_transform (item);
|
||||
GtkFixed *fixed = data;
|
||||
GtkWidget *widget;
|
||||
|
||||
widget = gtk_spinner_new ();
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (widget), "demo");
|
||||
gtk_spinner_start (GTK_SPINNER (widget));
|
||||
gtk_fixed_put (fixed, widget, pos_x, pos_y);
|
||||
}
|
||||
|
||||
static void
|
||||
text_changed (GtkEditable *editable,
|
||||
GParamSpec *pspec,
|
||||
CanvasItem *item)
|
||||
copy_cb (GtkWidget *child)
|
||||
{
|
||||
gtk_label_set_text (GTK_LABEL (item->label), gtk_editable_get_text (editable));
|
||||
apply_transform (item);
|
||||
GdkClipboard *clipboard;
|
||||
GtkDemoWidget *demo;
|
||||
|
||||
g_print ("Copy %s\n", G_OBJECT_TYPE_NAME (child));
|
||||
|
||||
demo = serialize_widget (child);
|
||||
|
||||
clipboard = gdk_display_get_clipboard (gdk_display_get_default ());
|
||||
gdk_clipboard_set (clipboard, GTK_TYPE_DEMO_WIDGET, demo);
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_item_stop_editing (CanvasItem *item)
|
||||
delete_cb (GtkWidget *child)
|
||||
{
|
||||
GtkWidget *scale;
|
||||
|
||||
if (!item->editor)
|
||||
return;
|
||||
|
||||
scale = gtk_widget_get_last_child (item->editor);
|
||||
g_signal_handlers_disconnect_by_func (scale, scale_changed, item);
|
||||
|
||||
gtk_fixed_remove (GTK_FIXED (gtk_widget_get_parent (item->editor)), item->editor);
|
||||
item->editor = NULL;
|
||||
gtk_widget_destroy (child);
|
||||
}
|
||||
|
||||
static void
|
||||
canvas_item_start_editing (CanvasItem *item)
|
||||
cut_cb (GtkWidget *child)
|
||||
{
|
||||
GtkWidget *canvas = gtk_widget_get_parent (GTK_WIDGET (item));
|
||||
GtkWidget *entry;
|
||||
GtkWidget *scale;
|
||||
double x, y;
|
||||
|
||||
if (item->editor)
|
||||
return;
|
||||
|
||||
item->editor = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||
|
||||
entry = gtk_entry_new ();
|
||||
|
||||
gtk_editable_set_text (GTK_EDITABLE (entry),
|
||||
gtk_label_get_text (GTK_LABEL (item->label)));
|
||||
|
||||
gtk_editable_set_width_chars (GTK_EDITABLE (entry), 12);
|
||||
g_signal_connect (entry, "notify::text", G_CALLBACK (text_changed), item);
|
||||
g_signal_connect_swapped (entry, "activate", G_CALLBACK (canvas_item_stop_editing), item);
|
||||
|
||||
gtk_box_append (GTK_BOX (item->editor), entry);
|
||||
|
||||
scale = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 360, 1);
|
||||
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
|
||||
gtk_range_set_value (GTK_RANGE (scale), fmod (item->angle, 360));
|
||||
|
||||
g_signal_connect (scale, "value-changed", G_CALLBACK (scale_changed), item);
|
||||
|
||||
gtk_box_append (GTK_BOX (item->editor), scale);
|
||||
|
||||
gtk_widget_translate_coordinates (GTK_WIDGET (item), canvas, 0, 0, &x, &y);
|
||||
gtk_fixed_put (GTK_FIXED (canvas), item->editor, x, y + 2 * item->r);
|
||||
gtk_widget_grab_focus (entry);
|
||||
|
||||
}
|
||||
|
||||
static GdkContentProvider *
|
||||
prepare (GtkDragSource *source,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
GtkWidget *canvas;
|
||||
GtkWidget *item;
|
||||
|
||||
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
|
||||
item = gtk_widget_pick (canvas, x, y, GTK_PICK_DEFAULT);
|
||||
|
||||
item = gtk_widget_get_ancestor (item, canvas_item_get_type ());
|
||||
if (!item)
|
||||
return NULL;
|
||||
|
||||
g_object_set_data (G_OBJECT (canvas), "dragged-item", item);
|
||||
|
||||
return gdk_content_provider_new_typed (GTK_TYPE_WIDGET, item);
|
||||
copy_cb (child);
|
||||
delete_cb (child);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin (GtkDragSource *source,
|
||||
GdkDrag *drag)
|
||||
value_read (GObject *source,
|
||||
GAsyncResult *res,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *canvas;
|
||||
CanvasItem *item;
|
||||
GdkPaintable *paintable;
|
||||
GdkClipboard *clipboard = GDK_CLIPBOARD (source);
|
||||
GError *error = NULL;
|
||||
const GValue *value;
|
||||
GtkDemoWidget *demo;
|
||||
GtkWidget *widget = NULL;
|
||||
|
||||
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
|
||||
item = CANVAS_ITEM (g_object_get_data (G_OBJECT (canvas), "dragged-item"));
|
||||
value = gdk_clipboard_read_value_finish (clipboard, res, &error);
|
||||
|
||||
paintable = canvas_item_get_drag_icon (item);
|
||||
gtk_drag_source_set_icon (source, paintable, item->r, item->r);
|
||||
g_object_unref (paintable);
|
||||
if (value == NULL)
|
||||
{
|
||||
g_print ("error: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_widget_set_opacity (GTK_WIDGET (item), 0.3);
|
||||
if (!G_VALUE_HOLDS (value, GTK_TYPE_DEMO_WIDGET))
|
||||
{
|
||||
g_print ("can't handle clipboard contents\n");
|
||||
return;
|
||||
}
|
||||
|
||||
demo = g_value_get_boxed (value);
|
||||
widget = deserialize_widget (demo);
|
||||
|
||||
gtk_fixed_put (GTK_FIXED (data), widget, pos_x, pos_y);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_end (GtkDragSource *source,
|
||||
GdkDrag *drag)
|
||||
paste_cb (GtkWidget *fixed)
|
||||
{
|
||||
GtkWidget *canvas;
|
||||
GtkWidget *item;
|
||||
GdkClipboard *clipboard;
|
||||
|
||||
canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
|
||||
item = g_object_get_data (G_OBJECT (canvas), "dragged-item");
|
||||
g_object_set_data (G_OBJECT (canvas), "dragged-item", NULL);
|
||||
|
||||
gtk_widget_set_opacity (item, 1.0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drag_cancel (GtkDragSource *source,
|
||||
GdkDrag *drag,
|
||||
GdkDragCancelReason reason)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
drag_drop (GtkDropTarget *target,
|
||||
const GValue *value,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
CanvasItem *item;
|
||||
GtkWidget *canvas;
|
||||
GtkWidget *last_child;
|
||||
|
||||
item = g_value_get_object (value);
|
||||
|
||||
canvas = gtk_widget_get_parent (GTK_WIDGET (item));
|
||||
last_child = gtk_widget_get_last_child (canvas);
|
||||
if (GTK_WIDGET (item) != last_child)
|
||||
gtk_widget_insert_after (GTK_WIDGET (item), canvas, last_child);
|
||||
|
||||
gtk_fixed_move (GTK_FIXED (canvas), GTK_WIDGET (item), x - item->r, y - item->r);
|
||||
|
||||
return TRUE;
|
||||
clipboard = gdk_display_get_clipboard (gdk_display_get_default ());
|
||||
if (gdk_content_formats_contain_gtype (gdk_clipboard_get_formats (clipboard), GTK_TYPE_DEMO_WIDGET))
|
||||
{
|
||||
g_print ("Paste %s\n", g_type_name (GTK_TYPE_DEMO_WIDGET));
|
||||
gdk_clipboard_read_value_async (clipboard, GTK_TYPE_DEMO_WIDGET, 0, NULL, value_read, fixed);
|
||||
}
|
||||
else
|
||||
g_print ("Don't know how to handle clipboard contents\n");
|
||||
}
|
||||
|
||||
static void
|
||||
new_item_cb (GtkWidget *button, gpointer data)
|
||||
edit_label_done (GtkWidget *entry, gpointer data)
|
||||
{
|
||||
GtkWidget *canvas = data;
|
||||
GtkWidget *popover;
|
||||
GtkWidget *item;
|
||||
GdkRectangle rect;
|
||||
GtkWidget *fixed = gtk_widget_get_parent (entry);
|
||||
GtkWidget *label;
|
||||
int x, y;
|
||||
|
||||
popover = gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER);
|
||||
gtk_popover_get_pointing_to (GTK_POPOVER (popover), &rect);
|
||||
gtk_container_child_get (GTK_CONTAINER (fixed), entry, "x", &x, "y", &y, NULL);
|
||||
|
||||
item = canvas_item_new ();
|
||||
gtk_fixed_put (GTK_FIXED (canvas), item, rect.x, rect.y);
|
||||
apply_transform (CANVAS_ITEM (item));
|
||||
label = GTK_WIDGET (g_object_get_data (G_OBJECT (entry), "label"));
|
||||
gtk_label_set_text (GTK_LABEL (label), gtk_entry_get_text (GTK_ENTRY (entry)));
|
||||
|
||||
gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER)));
|
||||
gtk_widget_destroy (entry);
|
||||
}
|
||||
|
||||
static void
|
||||
edit_cb (GtkWidget *button, GtkWidget *child)
|
||||
edit_cb (GtkWidget *child)
|
||||
{
|
||||
CanvasItem *item = CANVAS_ITEM (child);
|
||||
GtkWidget *fixed = gtk_widget_get_parent (child);
|
||||
int x, y;
|
||||
|
||||
if (button)
|
||||
gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER)));
|
||||
gtk_container_child_get (GTK_CONTAINER (fixed), child, "x", &x, "y", &y, NULL);
|
||||
|
||||
if (!canvas_item_is_editing (item))
|
||||
canvas_item_start_editing (item);
|
||||
}
|
||||
if (GTK_IS_LABEL (child))
|
||||
{
|
||||
GtkWidget *entry = gtk_entry_new ();
|
||||
|
||||
static void
|
||||
delete_cb (GtkWidget *button, GtkWidget *child)
|
||||
{
|
||||
GtkWidget *canvas = gtk_widget_get_parent (child);
|
||||
g_object_set_data (G_OBJECT (entry), "label", child);
|
||||
|
||||
gtk_fixed_remove (GTK_FIXED (canvas), child);
|
||||
gtk_entry_set_text (GTK_ENTRY (entry), gtk_label_get_text (GTK_LABEL (child)));
|
||||
g_signal_connect (entry, "activate", G_CALLBACK (edit_label_done), NULL);
|
||||
gtk_fixed_put (GTK_FIXED (fixed), entry, x, y);
|
||||
gtk_widget_grab_focus (entry);
|
||||
}
|
||||
else if (GTK_IS_SPINNER (child))
|
||||
{
|
||||
gboolean active;
|
||||
|
||||
gtk_popover_popdown (GTK_POPOVER (gtk_widget_get_ancestor (button, GTK_TYPE_POPOVER)));
|
||||
g_object_get (child, "active", &active, NULL);
|
||||
g_object_set (child, "active", !active, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -426,46 +243,69 @@ pressed_cb (GtkGesture *gesture,
|
||||
GtkWidget *child;
|
||||
|
||||
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
|
||||
child = gtk_widget_pick (widget, x, y, GTK_PICK_DEFAULT);
|
||||
child = gtk_widget_get_ancestor (child, canvas_item_get_type ());
|
||||
child = gtk_widget_pick (widget, x, y);
|
||||
|
||||
if (gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture)) == GDK_BUTTON_SECONDARY)
|
||||
{
|
||||
GdkRectangle rect;
|
||||
GtkWidget *menu;
|
||||
GtkWidget *box;
|
||||
GtkWidget *item;
|
||||
GdkClipboard *clipboard;
|
||||
|
||||
menu = gtk_popover_new ();
|
||||
gtk_widget_set_parent (menu, widget);
|
||||
gtk_popover_set_has_arrow (GTK_POPOVER (menu), FALSE);
|
||||
gtk_popover_set_pointing_to (GTK_POPOVER (menu), &(GdkRectangle){ x, y, 1, 1});
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_popover_set_child (GTK_POPOVER (menu), box);
|
||||
pos_x = x;
|
||||
pos_y = y;
|
||||
|
||||
item = gtk_button_new_with_label ("New");
|
||||
gtk_button_set_has_frame (GTK_BUTTON (item), FALSE);
|
||||
g_signal_connect (item, "clicked", G_CALLBACK (new_item_cb), widget);
|
||||
gtk_box_append (GTK_BOX (box), item);
|
||||
menu = gtk_menu_new ();
|
||||
item = gtk_menu_item_new_with_label ("New Label");
|
||||
g_signal_connect (item, "activate", G_CALLBACK (new_label_cb), widget);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
item = gtk_menu_item_new_with_label ("New Spinner");
|
||||
g_signal_connect (item, "activate", G_CALLBACK (new_spinner_cb), widget);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
|
||||
item = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_box_append (GTK_BOX (box), item);
|
||||
item = gtk_separator_menu_item_new ();
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
|
||||
item = gtk_button_new_with_label ("Edit");
|
||||
gtk_button_set_has_frame (GTK_BUTTON (item), FALSE);
|
||||
item = gtk_menu_item_new_with_label ("Edit");
|
||||
gtk_widget_set_sensitive (item, child != NULL && child != widget);
|
||||
g_signal_connect (item, "clicked", G_CALLBACK (edit_cb), child);
|
||||
gtk_box_append (GTK_BOX (box), item);
|
||||
g_signal_connect_swapped (item, "activate", G_CALLBACK (edit_cb), child);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
|
||||
item = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_box_append (GTK_BOX (box), item);
|
||||
item = gtk_separator_menu_item_new ();
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
|
||||
item = gtk_button_new_with_label ("Delete");
|
||||
gtk_button_set_has_frame (GTK_BUTTON (item), FALSE);
|
||||
item = gtk_menu_item_new_with_label ("Cut");
|
||||
gtk_widget_set_sensitive (item, child != NULL && child != widget);
|
||||
g_signal_connect (item, "clicked", G_CALLBACK (delete_cb), child);
|
||||
gtk_box_append (GTK_BOX (box), item);
|
||||
g_signal_connect_swapped (item, "activate", G_CALLBACK (cut_cb), child);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
item = gtk_menu_item_new_with_label ("Copy");
|
||||
gtk_widget_set_sensitive (item, child != NULL && child != widget);
|
||||
g_signal_connect_swapped (item, "activate", G_CALLBACK (copy_cb), child);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
item = gtk_menu_item_new_with_label ("Paste");
|
||||
clipboard = gdk_display_get_clipboard (gdk_display_get_default ());
|
||||
gtk_widget_set_sensitive (item,
|
||||
gdk_content_formats_contain_gtype (gdk_clipboard_get_formats (clipboard), GTK_TYPE_DEMO_WIDGET));
|
||||
g_signal_connect_swapped (item, "activate", G_CALLBACK (paste_cb), widget);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
item = gtk_menu_item_new_with_label ("Delete");
|
||||
gtk_widget_set_sensitive (item, child != NULL && child != widget);
|
||||
g_signal_connect_swapped (item, "activate", G_CALLBACK (delete_cb), child);
|
||||
gtk_container_add (GTK_CONTAINER (menu), item);
|
||||
|
||||
gtk_popover_popup (GTK_POPOVER (menu));
|
||||
rect.x = x;
|
||||
rect.y = y;
|
||||
rect.width = 0;
|
||||
rect.height = 0;
|
||||
|
||||
gtk_menu_popup_at_rect (GTK_MENU (menu),
|
||||
gtk_widget_get_surface (widget),
|
||||
&rect,
|
||||
GDK_GRAVITY_NORTH_WEST,
|
||||
GDK_GRAVITY_NORTH_WEST,
|
||||
NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,57 +318,17 @@ released_cb (GtkGesture *gesture,
|
||||
{
|
||||
GtkWidget *widget;
|
||||
GtkWidget *child;
|
||||
CanvasItem *item;
|
||||
|
||||
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
|
||||
child = gtk_widget_pick (widget, x, y, 0);
|
||||
item = (CanvasItem *)gtk_widget_get_ancestor (child, canvas_item_get_type ());
|
||||
if (!item)
|
||||
return;
|
||||
child = gtk_widget_pick (widget, x, y);
|
||||
|
||||
if (gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture)) == GDK_BUTTON_PRIMARY)
|
||||
{
|
||||
if (canvas_item_is_editing (item))
|
||||
canvas_item_stop_editing (item);
|
||||
else
|
||||
canvas_item_start_editing (item);
|
||||
if (child != NULL && child != widget)
|
||||
edit_cb (child);
|
||||
}
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
canvas_new (void)
|
||||
{
|
||||
GtkWidget *canvas;
|
||||
GtkDragSource *source;
|
||||
GtkDropTarget *dest;
|
||||
GtkGesture *gesture;
|
||||
|
||||
canvas = gtk_fixed_new ();
|
||||
gtk_widget_set_hexpand (canvas, TRUE);
|
||||
gtk_widget_set_vexpand (canvas, TRUE);
|
||||
gtk_widget_add_css_class (canvas, "frame");
|
||||
|
||||
source = gtk_drag_source_new ();
|
||||
gtk_drag_source_set_actions (source, GDK_ACTION_MOVE);
|
||||
g_signal_connect (source, "prepare", G_CALLBACK (prepare), NULL);
|
||||
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL);
|
||||
g_signal_connect (source, "drag-end", G_CALLBACK (drag_end), NULL);
|
||||
g_signal_connect (source, "drag-cancel", G_CALLBACK (drag_cancel), NULL);
|
||||
gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (source));
|
||||
|
||||
dest = gtk_drop_target_new (GTK_TYPE_WIDGET, GDK_ACTION_MOVE);
|
||||
g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), NULL);
|
||||
gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (dest));
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), 0);
|
||||
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), NULL);
|
||||
g_signal_connect (gesture, "released", G_CALLBACK (released_cb), NULL);
|
||||
gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
GtkWidget *
|
||||
@@ -536,82 +336,43 @@ do_dnd (GtkWidget *do_widget)
|
||||
{
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *button;
|
||||
GtkWidget *sw;
|
||||
GtkWidget *canvas;
|
||||
GtkWidget *box, *box2, *box3;
|
||||
const char *colors[] = {
|
||||
"red", "green", "blue", "magenta", "orange", "gray", "black", "yellow",
|
||||
"white", "gray", "brown", "pink", "cyan", "bisque", "gold", "maroon",
|
||||
"navy", "orchid", "olive", "peru", "salmon", "silver", "wheat",
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
int x, y;
|
||||
GtkWidget *vbox, *fixed;
|
||||
GtkGesture *multipress;
|
||||
GtkCssProvider *provider;
|
||||
|
||||
button = gtk_color_button_new ();
|
||||
g_object_unref (g_object_ref_sink (button));
|
||||
|
||||
window = gtk_window_new ();
|
||||
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), "Drag-and-Drop");
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Drag-and-drop");
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_box_append (GTK_BOX (box), box2);
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
|
||||
canvas = canvas_new ();
|
||||
gtk_box_append (GTK_BOX (box2), canvas);
|
||||
fixed = gtk_fixed_new ();
|
||||
gtk_container_add (GTK_CONTAINER (vbox), fixed);
|
||||
gtk_widget_set_hexpand (fixed, TRUE);
|
||||
gtk_widget_set_vexpand (fixed, TRUE);
|
||||
|
||||
n_items = 0;
|
||||
multipress = gtk_gesture_multi_press_new ();
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (multipress), 0);
|
||||
g_signal_connect (multipress, "pressed", G_CALLBACK (pressed_cb), NULL);
|
||||
g_signal_connect (multipress, "released", G_CALLBACK (released_cb), NULL);
|
||||
gtk_widget_add_controller (fixed, GTK_EVENT_CONTROLLER (multipress));
|
||||
|
||||
x = y = 40;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
GtkWidget *item;
|
||||
|
||||
item = canvas_item_new ();
|
||||
gtk_fixed_put (GTK_FIXED (canvas), item, x, y);
|
||||
apply_transform (CANVAS_ITEM (item));
|
||||
|
||||
x += 150;
|
||||
y += 100;
|
||||
}
|
||||
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_NEVER);
|
||||
gtk_box_append (GTK_BOX (box), sw);
|
||||
|
||||
box3 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_widget_add_css_class (box3, "linked");
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), box3);
|
||||
|
||||
for (i = 0; colors[i]; i++)
|
||||
{
|
||||
GdkRGBA rgba;
|
||||
GtkWidget *swatch;
|
||||
|
||||
gdk_rgba_parse (&rgba, colors[i]);
|
||||
|
||||
swatch = g_object_new (g_type_from_name ("GtkColorSwatch"),
|
||||
"rgba", &rgba,
|
||||
"selectable", FALSE,
|
||||
NULL);
|
||||
gtk_box_append (GTK_BOX (box3), swatch);
|
||||
}
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_resource (provider, "/dnd/dnd.css");
|
||||
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||||
GTK_STYLE_PROVIDER (provider),
|
||||
800);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
spinner.demo {
|
||||
opacity: 1;
|
||||
}
|
||||
+55
-172
@@ -42,9 +42,7 @@ create_surface (GtkWidget *widget)
|
||||
}
|
||||
|
||||
static void
|
||||
scribble_resize (GtkWidget *widget,
|
||||
int width,
|
||||
int height)
|
||||
scribble_size_allocate (GtkWidget *widget)
|
||||
{
|
||||
create_surface (widget);
|
||||
}
|
||||
@@ -125,164 +123,49 @@ drag_end (GtkGestureDrag *gesture,
|
||||
}
|
||||
|
||||
static void
|
||||
oval_path (cairo_t *cr,
|
||||
double xc, double yc,
|
||||
double xr, double yr)
|
||||
checkerboard_draw (GtkDrawingArea *da,
|
||||
cairo_t *cr,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
cairo_save (cr);
|
||||
gint i, j, xcount, ycount;
|
||||
|
||||
cairo_translate (cr, xc, yc);
|
||||
cairo_scale (cr, 1.0, yr / xr);
|
||||
cairo_move_to (cr, xr, 0.0);
|
||||
cairo_arc (cr,
|
||||
0, 0,
|
||||
xr,
|
||||
0, 2 * G_PI);
|
||||
cairo_close_path (cr);
|
||||
#define CHECK_SIZE 10
|
||||
#define SPACING 2
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
/* At the start of a draw handler, a clip region has been set on
|
||||
* the Cairo context, and the contents have been cleared to the
|
||||
* widget's background color. The docs for
|
||||
* gdk_surface_begin_paint_region() give more details on how this
|
||||
* works.
|
||||
*/
|
||||
|
||||
/* Fill the given area with checks in the standard style
|
||||
* for showing compositing effects.
|
||||
*
|
||||
* It would make sense to do this as a repeating surface,
|
||||
* but most implementations of RENDER currently have broken
|
||||
* implementations of repeat + transform, even when the
|
||||
* transform is a translation.
|
||||
*/
|
||||
static void
|
||||
fill_checks (cairo_t *cr,
|
||||
int x, int y,
|
||||
int width, int height)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
#define CHECK_SIZE 16
|
||||
|
||||
cairo_rectangle (cr, x, y, width, height);
|
||||
cairo_set_source_rgb (cr, 0.4, 0.4, 0.4);
|
||||
cairo_fill (cr);
|
||||
|
||||
/* Only works for CHECK_SIZE a power of 2 */
|
||||
j = x & (-CHECK_SIZE);
|
||||
|
||||
for (; j < height; j += CHECK_SIZE)
|
||||
xcount = 0;
|
||||
i = SPACING;
|
||||
while (i < width)
|
||||
{
|
||||
i = y & (-CHECK_SIZE);
|
||||
for (; i < width; i += CHECK_SIZE)
|
||||
if ((i / CHECK_SIZE + j / CHECK_SIZE) % 2 == 0)
|
||||
j = SPACING;
|
||||
ycount = xcount % 2; /* start with even/odd depending on row */
|
||||
while (j < height)
|
||||
{
|
||||
if (ycount % 2)
|
||||
cairo_set_source_rgb (cr, 0.45777, 0, 0.45777);
|
||||
else
|
||||
cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
|
||||
/* If we're outside the clip, this will do nothing.
|
||||
*/
|
||||
cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE);
|
||||
cairo_fill (cr);
|
||||
|
||||
j += CHECK_SIZE + SPACING;
|
||||
++ycount;
|
||||
}
|
||||
|
||||
i += CHECK_SIZE + SPACING;
|
||||
++xcount;
|
||||
}
|
||||
|
||||
cairo_set_source_rgb (cr, 0.7, 0.7, 0.7);
|
||||
cairo_fill (cr);
|
||||
|
||||
#undef CHECK_SIZE
|
||||
}
|
||||
|
||||
/* Draw a red, green, and blue circle equally spaced inside
|
||||
* the larger circle of radius r at (xc, yc)
|
||||
*/
|
||||
static void
|
||||
draw_3circles (cairo_t *cr,
|
||||
double xc, double yc,
|
||||
double radius,
|
||||
double alpha)
|
||||
{
|
||||
double subradius = radius * (2 / 3. - 0.1);
|
||||
|
||||
cairo_set_source_rgba (cr, 1., 0., 0., alpha);
|
||||
oval_path (cr,
|
||||
xc + radius / 3. * cos (G_PI * (0.5)),
|
||||
yc - radius / 3. * sin (G_PI * (0.5)),
|
||||
subradius, subradius);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0., 1., 0., alpha);
|
||||
oval_path (cr,
|
||||
xc + radius / 3. * cos (G_PI * (0.5 + 2/.3)),
|
||||
yc - radius / 3. * sin (G_PI * (0.5 + 2/.3)),
|
||||
subradius, subradius);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_set_source_rgba (cr, 0., 0., 1., alpha);
|
||||
oval_path (cr,
|
||||
xc + radius / 3. * cos (G_PI * (0.5 + 4/.3)),
|
||||
yc - radius / 3. * sin (G_PI * (0.5 + 4/.3)),
|
||||
subradius, subradius);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
groups_draw (GtkDrawingArea *darea,
|
||||
cairo_t *cr,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
cairo_surface_t *overlay, *punch, *circles;
|
||||
cairo_t *overlay_cr, *punch_cr, *circles_cr;
|
||||
|
||||
/* Fill the background */
|
||||
double radius = 0.5 * (width < height ? width : height) - 10;
|
||||
double xc = width / 2.;
|
||||
double yc = height / 2.;
|
||||
|
||||
overlay = cairo_surface_create_similar (cairo_get_target (cr),
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
width, height);
|
||||
|
||||
punch = cairo_surface_create_similar (cairo_get_target (cr),
|
||||
CAIRO_CONTENT_ALPHA,
|
||||
width, height);
|
||||
|
||||
circles = cairo_surface_create_similar (cairo_get_target (cr),
|
||||
CAIRO_CONTENT_COLOR_ALPHA,
|
||||
width, height);
|
||||
|
||||
fill_checks (cr, 0, 0, width, height);
|
||||
|
||||
/* Draw a black circle on the overlay
|
||||
*/
|
||||
overlay_cr = cairo_create (overlay);
|
||||
cairo_set_source_rgb (overlay_cr, 0., 0., 0.);
|
||||
oval_path (overlay_cr, xc, yc, radius, radius);
|
||||
cairo_fill (overlay_cr);
|
||||
|
||||
/* Draw 3 circles to the punch surface, then cut
|
||||
* that out of the main circle in the overlay
|
||||
*/
|
||||
punch_cr = cairo_create (punch);
|
||||
draw_3circles (punch_cr, xc, yc, radius, 1.0);
|
||||
cairo_destroy (punch_cr);
|
||||
|
||||
cairo_set_operator (overlay_cr, CAIRO_OPERATOR_DEST_OUT);
|
||||
cairo_set_source_surface (overlay_cr, punch, 0, 0);
|
||||
cairo_paint (overlay_cr);
|
||||
|
||||
/* Now draw the 3 circles in a subgroup again
|
||||
* at half intensity, and use OperatorAdd to join up
|
||||
* without seams.
|
||||
*/
|
||||
circles_cr = cairo_create (circles);
|
||||
|
||||
cairo_set_operator (circles_cr, CAIRO_OPERATOR_OVER);
|
||||
draw_3circles (circles_cr, xc, yc, radius, 0.5);
|
||||
cairo_destroy (circles_cr);
|
||||
|
||||
cairo_set_operator (overlay_cr, CAIRO_OPERATOR_ADD);
|
||||
cairo_set_source_surface (overlay_cr, circles, 0, 0);
|
||||
cairo_paint (overlay_cr);
|
||||
|
||||
cairo_destroy (overlay_cr);
|
||||
|
||||
cairo_set_source_surface (cr, overlay, 0, 0);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_surface_destroy (overlay);
|
||||
cairo_surface_destroy (punch);
|
||||
cairo_surface_destroy (circles);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -306,7 +189,7 @@ do_drawingarea (GtkWidget *do_widget)
|
||||
|
||||
if (!window)
|
||||
{
|
||||
window = gtk_window_new ();
|
||||
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), "Drawing Area");
|
||||
@@ -315,29 +198,28 @@ do_drawingarea (GtkWidget *do_widget)
|
||||
G_CALLBACK (close_window), NULL);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
||||
gtk_widget_set_margin_start (vbox, 16);
|
||||
gtk_widget_set_margin_end (vbox, 16);
|
||||
gtk_widget_set_margin_top (vbox, 16);
|
||||
gtk_widget_set_margin_bottom (vbox, 16);
|
||||
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
||||
g_object_set (vbox, "margin", 16, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
|
||||
/*
|
||||
* Create the groups area
|
||||
* Create the checkerboard area
|
||||
*/
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_markup (GTK_LABEL (label),
|
||||
"<u>Knockout groups</u>");
|
||||
gtk_box_append (GTK_BOX (vbox), label);
|
||||
"<u>Checkerboard pattern</u>");
|
||||
gtk_container_add (GTK_CONTAINER (vbox), label);
|
||||
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
||||
gtk_widget_set_vexpand (frame, TRUE);
|
||||
gtk_box_append (GTK_BOX (vbox), frame);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), frame);
|
||||
|
||||
da = gtk_drawing_area_new ();
|
||||
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 100);
|
||||
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 100);
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), groups_draw, NULL, NULL);
|
||||
gtk_frame_set_child (GTK_FRAME (frame), da);
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), checkerboard_draw, NULL, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (frame), da);
|
||||
|
||||
/*
|
||||
* Create the scribble area
|
||||
@@ -346,20 +228,21 @@ do_drawingarea (GtkWidget *do_widget)
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_markup (GTK_LABEL (label),
|
||||
"<u>Scribble area</u>");
|
||||
gtk_box_append (GTK_BOX (vbox), label);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), label);
|
||||
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_widget_set_vexpand (frame, TRUE);
|
||||
gtk_box_append (GTK_BOX (vbox), frame);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), frame);
|
||||
|
||||
da = gtk_drawing_area_new ();
|
||||
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 100);
|
||||
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 100);
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), scribble_draw, NULL, NULL);
|
||||
gtk_frame_set_child (GTK_FRAME (frame), da);
|
||||
gtk_container_add (GTK_CONTAINER (frame), da);
|
||||
|
||||
g_signal_connect (da, "resize",
|
||||
G_CALLBACK (scribble_resize), NULL);
|
||||
g_signal_connect (da, "size-allocate",
|
||||
G_CALLBACK (scribble_size_allocate), NULL);
|
||||
|
||||
drag = gtk_gesture_drag_new ();
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (drag), GDK_BUTTON_PRIMARY);
|
||||
@@ -374,7 +257,7 @@ do_drawingarea (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -275,9 +275,6 @@ cell_edited (GtkCellRendererText *cell,
|
||||
g_array_index (articles, Item, i).product, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
gtk_tree_path_free (path);
|
||||
@@ -348,28 +345,27 @@ do_editable_cells (GtkWidget *do_widget)
|
||||
GtkTreeModel *items_model;
|
||||
GtkTreeModel *numbers_model;
|
||||
|
||||
window = gtk_window_new ();
|
||||
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), "Editable Cells");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
||||
gtk_widget_set_margin_start (vbox, 5);
|
||||
gtk_widget_set_margin_end (vbox, 5);
|
||||
gtk_widget_set_margin_top (vbox, 5);
|
||||
gtk_widget_set_margin_bottom (vbox, 5);
|
||||
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
||||
g_object_set (vbox, "margin", 5, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
|
||||
gtk_box_append (GTK_BOX (vbox),
|
||||
gtk_container_add (GTK_CONTAINER (vbox),
|
||||
gtk_label_new ("Shopping list (you can edit the cells!)"));
|
||||
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
|
||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_SHADOW_ETCHED_IN);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_box_append (GTK_BOX (vbox), sw);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), sw);
|
||||
|
||||
/* create models */
|
||||
items_model = create_items_model ();
|
||||
@@ -386,22 +382,22 @@ do_editable_cells (GtkWidget *do_widget)
|
||||
g_object_unref (numbers_model);
|
||||
g_object_unref (items_model);
|
||||
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), treeview);
|
||||
gtk_container_add (GTK_CONTAINER (sw), treeview);
|
||||
|
||||
/* some buttons */
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
|
||||
gtk_box_append (GTK_BOX (vbox), hbox);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
||||
|
||||
button = gtk_button_new_with_label ("Add item");
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (add_item), treeview);
|
||||
gtk_box_append (GTK_BOX (hbox), button);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), button);
|
||||
|
||||
button = gtk_button_new_with_label ("Remove item");
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (remove_item), treeview);
|
||||
gtk_box_append (GTK_BOX (hbox), button);
|
||||
gtk_container_add (GTK_CONTAINER (hbox), button);
|
||||
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 320, 200);
|
||||
}
|
||||
@@ -409,7 +405,7 @@ do_editable_cells (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/* Entry/Entry Buffer
|
||||
*
|
||||
* 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_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 Buffer");
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
||||
g_object_set (vbox, "margin", 5, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_markup (GTK_LABEL (label),
|
||||
"Entries share a buffer. Typing in one is reflected in the other.");
|
||||
gtk_container_add (GTK_CONTAINER (vbox), label);
|
||||
|
||||
/* 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))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
/* Creates a tree model containing the completions */
|
||||
static GtkTreeModel *
|
||||
GtkTreeModel *
|
||||
create_completion_model (void)
|
||||
{
|
||||
GtkListStore *store;
|
||||
@@ -45,27 +45,26 @@ do_entry_completion (GtkWidget *do_widget)
|
||||
|
||||
if (!window)
|
||||
{
|
||||
window = gtk_window_new ();
|
||||
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 Completion");
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
||||
gtk_widget_set_margin_start (vbox, 5);
|
||||
gtk_widget_set_margin_end (vbox, 5);
|
||||
gtk_widget_set_margin_top (vbox, 5);
|
||||
gtk_widget_set_margin_bottom (vbox, 5);
|
||||
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
||||
g_object_set (vbox, "margin", 5, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_markup (GTK_LABEL (label), "Completion demo, try writing <b>total</b> or <b>gnome</b> for example.");
|
||||
gtk_box_append (GTK_BOX (vbox), label);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), label);
|
||||
|
||||
/* Create our entry */
|
||||
entry = gtk_entry_new ();
|
||||
gtk_box_append (GTK_BOX (vbox), entry);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), entry);
|
||||
|
||||
/* Create the completion object */
|
||||
completion = gtk_entry_completion_new ();
|
||||
@@ -86,7 +85,7 @@ do_entry_completion (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/* Entry/Entry Undo
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
GtkWidget *
|
||||
do_entry_undo (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window = NULL;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *label;
|
||||
GtkWidget *entry;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
window = gtk_window_new ();
|
||||
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_resizable (GTK_WINDOW (window), FALSE);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
||||
gtk_widget_set_margin_start (vbox, 5);
|
||||
gtk_widget_set_margin_end (vbox, 5);
|
||||
gtk_widget_set_margin_top (vbox, 5);
|
||||
gtk_widget_set_margin_bottom (vbox, 5);
|
||||
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_markup (GTK_LABEL (label),
|
||||
"Use Primary+z or Primary+Shift+z to undo or redo changes");
|
||||
gtk_box_append (GTK_BOX (vbox), label);
|
||||
|
||||
/* Create our entry */
|
||||
entry = gtk_entry_new ();
|
||||
gtk_editable_set_enable_undo (GTK_EDITABLE (entry), TRUE);
|
||||
gtk_box_append (GTK_BOX (vbox), entry);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -15,7 +15,7 @@ static GtkWidget *window = NULL;
|
||||
static void
|
||||
response_cb (GtkDialog *dialog, gint response_id)
|
||||
{
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
window = NULL;
|
||||
}
|
||||
|
||||
@@ -31,14 +31,13 @@ do_expander (GtkWidget *do_widget)
|
||||
GtkWidget *toplevel;
|
||||
GtkWidget *area;
|
||||
GtkWidget *expander;
|
||||
GtkWidget *label;
|
||||
GtkWidget *sw;
|
||||
GtkWidget *tv;
|
||||
GtkTextBuffer *buffer;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
toplevel = GTK_WIDGET (gtk_widget_get_root (do_widget));
|
||||
toplevel = gtk_widget_get_toplevel (do_widget);
|
||||
window = gtk_message_dialog_new_with_markup (GTK_WINDOW (toplevel),
|
||||
0,
|
||||
GTK_MESSAGE_ERROR,
|
||||
@@ -51,19 +50,13 @@ 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_widget_set_vexpand (label, FALSE);
|
||||
|
||||
expander = gtk_expander_new ("Details:");
|
||||
gtk_widget_set_vexpand (expander, TRUE);
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (sw), 100);
|
||||
gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
|
||||
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||
GTK_POLICY_NEVER,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (sw), TRUE);
|
||||
|
||||
tv = gtk_text_view_new ();
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
@@ -78,9 +71,9 @@ do_expander (GtkWidget *do_widget)
|
||||
"A second paragraph will contain even more "
|
||||
"innuendo, just to make you scroll down or "
|
||||
"resize the window. Do it already !", -1);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), tv);
|
||||
gtk_expander_set_child (GTK_EXPANDER (expander), sw);
|
||||
gtk_box_append (GTK_BOX (area), expander);
|
||||
gtk_container_add (GTK_CONTAINER (sw), tv);
|
||||
gtk_container_add (GTK_CONTAINER (expander), sw);
|
||||
gtk_container_add (GTK_CONTAINER (area), expander);
|
||||
g_signal_connect (expander, "notify::expanded",
|
||||
G_CALLBACK (expander_cb), window);
|
||||
|
||||
@@ -90,7 +83,7 @@ do_expander (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -122,10 +122,12 @@ 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));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
store = (GtkListStore*)gtk_builder_get_object (builder, "liststore1");
|
||||
|
||||
@@ -198,7 +200,7 @@ do_filtermodel (GtkWidget *do_widget)
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<object class="GtkListStore" id="liststore1">
|
||||
@@ -31,10 +30,7 @@
|
||||
<property name="title" translatable="yes">Filter Model</property>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid1">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="row-spacing">10</property>
|
||||
<property name="column-spacing">10</property>
|
||||
<property name="column-homogeneous">1</property>
|
||||
@@ -48,14 +44,15 @@
|
||||
<accessibility>
|
||||
<relation type="label-for" target="treeview1"/>
|
||||
</accessibility>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="treeview1">
|
||||
<property name="can-focus">1</property>
|
||||
<property name="model">liststore1</property>
|
||||
<property name="headers-clickable">0</property>
|
||||
<child internal-child="selection">
|
||||
@@ -86,14 +83,15 @@
|
||||
<accessibility>
|
||||
<relation type="labelled-by" target="label1"/>
|
||||
</accessibility>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="treeview2">
|
||||
<property name="can-focus">1</property>
|
||||
<property name="headers-clickable">0</property>
|
||||
<property name="search-column">0</property>
|
||||
<child internal-child="selection">
|
||||
@@ -136,11 +134,11 @@
|
||||
<accessibility>
|
||||
<relation type="labelled-by" target="label2"/>
|
||||
</accessibility>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label2">
|
||||
@@ -152,11 +150,11 @@
|
||||
<accessibility>
|
||||
<relation type="label-for" target="treeview2"/>
|
||||
</accessibility>
|
||||
<layout>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label3">
|
||||
@@ -168,14 +166,15 @@
|
||||
<accessibility>
|
||||
<relation type="label-for" target="treeview3"/>
|
||||
</accessibility>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="treeview3">
|
||||
<property name="can-focus">1</property>
|
||||
<property name="headers-clickable">0</property>
|
||||
<property name="search-column">0</property>
|
||||
<child internal-child="selection">
|
||||
@@ -200,11 +199,11 @@
|
||||
<accessibility>
|
||||
<relation type="labelled-by" target="label3"/>
|
||||
</accessibility>
|
||||
<layout>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
+42
-58
@@ -22,11 +22,29 @@ gsize n_icon_names = 0;
|
||||
static void
|
||||
init_icon_names (GtkIconTheme *theme)
|
||||
{
|
||||
GPtrArray *icons;
|
||||
GList *l, *icon_list;
|
||||
|
||||
if (icon_names)
|
||||
return;
|
||||
|
||||
icon_names = gtk_icon_theme_get_icon_names (theme);
|
||||
n_icon_names = g_strv_length (icon_names);
|
||||
icon_list = gtk_icon_theme_list_icons (theme, NULL);
|
||||
icons = g_ptr_array_new ();
|
||||
|
||||
for (l = icon_list; l; l = l->next)
|
||||
{
|
||||
if (g_str_has_suffix (l->data, "symbolic"))
|
||||
continue;
|
||||
|
||||
g_ptr_array_add (icons, g_strdup (l->data));
|
||||
}
|
||||
|
||||
n_icon_names = icons->len;
|
||||
g_ptr_array_add (icons, NULL); /* NULL-terminate the array */
|
||||
icon_names = (char **) g_ptr_array_free (icons, FALSE);
|
||||
|
||||
/* don't free strings, we assigned them to the array */
|
||||
g_list_free_full (icon_list, g_free);
|
||||
}
|
||||
|
||||
static const char *
|
||||
@@ -37,16 +55,13 @@ get_random_icon_name (GtkIconTheme *theme)
|
||||
return icon_names[g_random_int_range(0, n_icon_names)];
|
||||
}
|
||||
|
||||
/* Can't be static because it's also used in iconscroll.c */
|
||||
GtkWidget *
|
||||
create_icon (void)
|
||||
{
|
||||
GtkWidget *image;
|
||||
|
||||
image = gtk_image_new ();
|
||||
image = gtk_image_new_from_icon_name (get_random_icon_name (gtk_icon_theme_get_default ()));
|
||||
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (image),
|
||||
get_random_icon_name (gtk_icon_theme_get_for_display (gtk_widget_get_display (image))));
|
||||
|
||||
return image;
|
||||
}
|
||||
@@ -62,7 +77,7 @@ create_blurred_button (void)
|
||||
{
|
||||
GtkWidget *w = gtk_button_new ();
|
||||
|
||||
gtk_widget_add_css_class (w, "blurred-button");
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (w), "blurred-button");
|
||||
|
||||
return w;
|
||||
}
|
||||
@@ -109,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;
|
||||
@@ -149,26 +164,6 @@ create_switch (void)
|
||||
return w;
|
||||
}
|
||||
|
||||
static void
|
||||
mapped (GtkWidget *w)
|
||||
{
|
||||
gtk_menu_button_popup (GTK_MENU_BUTTON (w));
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_menu_button (void)
|
||||
{
|
||||
GtkWidget *w = gtk_menu_button_new ();
|
||||
GtkWidget *popover = gtk_popover_new ();
|
||||
|
||||
gtk_popover_set_child (GTK_POPOVER (popover), gtk_button_new_with_label ("Hey!"));
|
||||
gtk_popover_set_autohide (GTK_POPOVER (popover), FALSE);
|
||||
gtk_menu_button_set_popover (GTK_MENU_BUTTON (w), popover);
|
||||
g_signal_connect (w, "map", G_CALLBACK (mapped), NULL);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
GtkWidget * (*create_func) (void);
|
||||
@@ -184,7 +179,6 @@ static const struct {
|
||||
{ "Video", create_video },
|
||||
{ "Gears", create_gears },
|
||||
{ "Switch", create_switch },
|
||||
{ "Menubutton", create_menu_button },
|
||||
};
|
||||
|
||||
static int selected_widget_type = -1;
|
||||
@@ -194,7 +188,7 @@ static void
|
||||
set_widget_type (GtkFishbowl *fishbowl,
|
||||
int widget_type_index)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *window, *headerbar;
|
||||
|
||||
if (widget_type_index == selected_widget_type)
|
||||
return;
|
||||
@@ -204,14 +198,15 @@ set_widget_type (GtkFishbowl *fishbowl,
|
||||
gtk_fishbowl_set_creation_func (fishbowl,
|
||||
widget_types[selected_widget_type].create_func);
|
||||
|
||||
window = GTK_WIDGET (gtk_widget_get_root (GTK_WIDGET (fishbowl)));
|
||||
gtk_window_set_title (GTK_WINDOW (window),
|
||||
widget_types[selected_widget_type].name);
|
||||
window = gtk_widget_get_toplevel (GTK_WIDGET (fishbowl));
|
||||
headerbar = gtk_window_get_titlebar (GTK_WINDOW (window));
|
||||
gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar),
|
||||
widget_types[selected_widget_type].name);
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -225,8 +220,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;
|
||||
@@ -239,23 +234,6 @@ fishbowl_prev_button_clicked_cb (GtkButton *source,
|
||||
set_widget_type (fishbowl, new_index);
|
||||
}
|
||||
|
||||
void
|
||||
fishbowl_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");
|
||||
else
|
||||
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)
|
||||
@@ -280,23 +258,29 @@ 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),
|
||||
NULL);
|
||||
gtk_builder_connect_signals (builder, NULL);
|
||||
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
bowl = GTK_WIDGET (gtk_builder_get_object (builder, "bowl"));
|
||||
selected_widget_type = -1;
|
||||
set_widget_type (GTK_FISHBOWL (bowl), 0);
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
gtk_widget_realize (window);
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
+51
-19
@@ -1,9 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="title" translatable="yes">Fishbowl</property>
|
||||
<property name="default-width">400</property>
|
||||
<property name="default-height">400</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="">
|
||||
<property name="show-title-buttons">1</property>
|
||||
@@ -15,42 +12,77 @@
|
||||
<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">
|
||||
<child>
|
||||
<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>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkToggleButton" id="changes_allow">
|
||||
<property name="icon-name">changes-allow</property>
|
||||
<property name="has-frame">0</property>
|
||||
<signal name="notify::active" handler="fishbowl_changes_toggled_cb"/>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" bind-source="bowl" bind-property="framerate"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Icons, </property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label" bind-source="bowl" bind-property="count"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="changes_allow">
|
||||
<property name="visible" bind-source="changes_allow" bind-property="active" bind-flags="invert-boolean"/>
|
||||
<property name="icon-name">changes-allow</property>
|
||||
<property name="relief">none</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="changes_prevent">
|
||||
<property name="active" bind-source="changes_allow" bind-property="active" bind-flags="bidirectional|invert-boolean">1</property>
|
||||
<property name="visible" bind-source="changes_prevent" bind-property="active" bind-flags="invert-boolean">0</property>
|
||||
<property name="icon-name">changes-prevent</property>
|
||||
<property name="relief">none</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFishbowl" id="bowl">
|
||||
<property name="visible">True</property>
|
||||
<property name="overflow">hidden</property>
|
||||
<property name="animating">True</property>
|
||||
<property name="benchmark" bind-source="changes_allow" bind-property="active" bind-flags="invert-boolean | sync-create"/>
|
||||
<property name="benchmark" bind-source="changes_allow" bind-property="active" bind-flags="invert-boolean">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
/* Fixed layout
|
||||
*
|
||||
* GtkFixed is a container that allows placing and transforming
|
||||
* widgets manually.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
/* This enumeration determines the paint order */
|
||||
enum {
|
||||
FACE_BACK,
|
||||
FACE_LEFT,
|
||||
FACE_BOTTOM,
|
||||
FACE_RIGHT,
|
||||
FACE_TOP,
|
||||
FACE_FRONT,
|
||||
|
||||
N_FACES
|
||||
};
|
||||
|
||||
/* Map face widgets to CSS classes */
|
||||
static struct {
|
||||
GtkWidget *face;
|
||||
const char *css_class;
|
||||
} faces[N_FACES] = {
|
||||
[FACE_BACK] = { NULL, "back", },
|
||||
[FACE_LEFT] = { NULL, "left", },
|
||||
[FACE_RIGHT] = { NULL, "right", },
|
||||
[FACE_TOP] = { NULL, "top", },
|
||||
[FACE_BOTTOM] = { NULL, "bottom", },
|
||||
[FACE_FRONT] = { NULL, "front", },
|
||||
};
|
||||
|
||||
static GtkWidget *
|
||||
create_faces (void)
|
||||
{
|
||||
GtkWidget *fixed = gtk_fixed_new ();
|
||||
int face_size = 200;
|
||||
float w, h, d, p;
|
||||
|
||||
gtk_widget_set_overflow (fixed, GTK_OVERFLOW_VISIBLE);
|
||||
|
||||
w = (float) face_size / 2.f;
|
||||
h = (float) face_size / 2.f;
|
||||
d = (float) face_size / 2.f;
|
||||
p = face_size * 3.f;
|
||||
|
||||
for (int i = 0; i < N_FACES; i++)
|
||||
{
|
||||
GskTransform *transform = NULL;
|
||||
|
||||
/* Add a face */
|
||||
faces[i].face = gtk_frame_new (NULL);
|
||||
gtk_widget_set_size_request (faces[i].face, face_size, face_size);
|
||||
gtk_widget_add_css_class (faces[i].face, faces[i].css_class);
|
||||
gtk_fixed_put (GTK_FIXED (fixed), faces[i].face, 0, 0);
|
||||
|
||||
/* Set up the transformation for each face */
|
||||
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (w, h));
|
||||
transform = gsk_transform_perspective (transform, p);
|
||||
transform = gsk_transform_rotate_3d (transform, -30.f, graphene_vec3_x_axis ());
|
||||
transform = gsk_transform_rotate_3d (transform, 135.f, graphene_vec3_y_axis ());
|
||||
transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (0, 0, -face_size / 6.f));
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case FACE_FRONT:
|
||||
transform = gsk_transform_rotate_3d (transform, 0.f, graphene_vec3_y_axis ());
|
||||
break;
|
||||
|
||||
case FACE_BACK:
|
||||
transform = gsk_transform_rotate_3d (transform, -180.f, graphene_vec3_y_axis ());
|
||||
break;
|
||||
|
||||
case FACE_RIGHT:
|
||||
transform = gsk_transform_rotate_3d (transform, 90.f, graphene_vec3_y_axis ());
|
||||
break;
|
||||
|
||||
case FACE_LEFT:
|
||||
transform = gsk_transform_rotate_3d (transform, -90.f, graphene_vec3_y_axis ());
|
||||
break;
|
||||
|
||||
case FACE_TOP:
|
||||
transform = gsk_transform_rotate_3d (transform, 90.f, graphene_vec3_x_axis ());
|
||||
break;
|
||||
|
||||
case FACE_BOTTOM:
|
||||
transform = gsk_transform_rotate_3d (transform, -90.f, graphene_vec3_x_axis ());
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (0, 0, d));
|
||||
transform = gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (-w, -h, 0));
|
||||
|
||||
gtk_fixed_set_child_transform (GTK_FIXED (fixed), faces[i].face, transform);
|
||||
gsk_transform_unref (transform);
|
||||
}
|
||||
|
||||
return fixed;
|
||||
}
|
||||
|
||||
static GtkWidget *demo_window = NULL;
|
||||
static GtkCssProvider *provider = NULL;
|
||||
|
||||
static void
|
||||
close_window (GtkWidget *widget)
|
||||
{
|
||||
/* Reset the state */
|
||||
for (int i = 0; i < N_FACES; i++)
|
||||
faces[i].face = NULL;
|
||||
|
||||
gtk_style_context_remove_provider_for_display (gdk_display_get_default (),
|
||||
GTK_STYLE_PROVIDER (provider));
|
||||
provider = NULL;
|
||||
|
||||
demo_window = NULL;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
create_demo_window (GtkWidget *do_widget)
|
||||
{
|
||||
GtkWidget *window, *sw, *fixed, *cube;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Fixed layout");
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
|
||||
g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
|
||||
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_window_set_child (GTK_WINDOW (window), sw);
|
||||
|
||||
fixed = gtk_fixed_new ();
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), fixed);
|
||||
gtk_widget_set_halign (GTK_WIDGET (fixed), GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_valign (GTK_WIDGET (fixed), GTK_ALIGN_CENTER);
|
||||
|
||||
cube = create_faces ();
|
||||
gtk_fixed_put (GTK_FIXED (fixed), cube, 0, 0);
|
||||
gtk_widget_set_overflow (fixed, GTK_OVERFLOW_VISIBLE);
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_resource (provider, "/fixed/fixed.css");
|
||||
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||||
GTK_STYLE_PROVIDER (provider),
|
||||
800);
|
||||
g_object_unref (provider);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
GtkWidget*
|
||||
do_fixed (GtkWidget *do_widget)
|
||||
{
|
||||
if (demo_window == NULL)
|
||||
demo_window = create_demo_window (do_widget);
|
||||
|
||||
if (!gtk_widget_get_visible (demo_window))
|
||||
gtk_widget_show (demo_window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (demo_window));
|
||||
|
||||
return demo_window;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
frame.front {
|
||||
border: 2px solid white;
|
||||
background-color: rgba(228, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
frame.back {
|
||||
border: 2px solid white;
|
||||
background-color: rgba(228, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
frame.right {
|
||||
border: 2px solid white;
|
||||
background-color: rgba(127, 231, 25, 0.8);
|
||||
}
|
||||
|
||||
frame.left {
|
||||
border: 2px solid white;
|
||||
background-color: rgba(127, 231, 25, 0.8);
|
||||
}
|
||||
|
||||
frame.top {
|
||||
border: 2px solid white;
|
||||
background-color: rgba(114, 159, 207, 0.8);
|
||||
}
|
||||
|
||||
frame.bottom {
|
||||
border: 2px solid white;
|
||||
background-color: rgba(114, 159, 207, 0.8);
|
||||
}
|
||||
@@ -4,8 +4,6 @@
|
||||
* as needed and support sorting and filtering.
|
||||
*
|
||||
* The children of a GtkFlowBox are regular widgets
|
||||
*
|
||||
* The dataset used here has 665 colors.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
@@ -39,7 +37,7 @@ color_swatch_new (const gchar *color)
|
||||
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (area), 24);
|
||||
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (area), 24);
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw_color, (gpointer) color, NULL);
|
||||
gtk_button_set_child (GTK_BUTTON (button), area);
|
||||
gtk_container_add (GTK_CONTAINER (button), area);
|
||||
|
||||
return button;
|
||||
}
|
||||
@@ -721,12 +719,14 @@ do_flowbox (GtkWidget *do_widget)
|
||||
|
||||
if (!window)
|
||||
{
|
||||
window = gtk_window_new ();
|
||||
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), "Flow Box");
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
||||
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
scrolled = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||
@@ -735,17 +735,17 @@ do_flowbox (GtkWidget *do_widget)
|
||||
gtk_flow_box_set_max_children_per_line (GTK_FLOW_BOX (flowbox), 30);
|
||||
gtk_flow_box_set_selection_mode (GTK_FLOW_BOX (flowbox), GTK_SELECTION_NONE);
|
||||
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), flowbox);
|
||||
gtk_window_set_child (GTK_WINDOW (window), scrolled);
|
||||
gtk_container_add (GTK_CONTAINER (scrolled), flowbox);
|
||||
gtk_container_add (GTK_CONTAINER (window), scrolled);
|
||||
|
||||
for (i = 0; colors[i]; i++)
|
||||
gtk_flow_box_insert (GTK_FLOW_BOX (flowbox), color_swatch_new (colors[i]), -1);
|
||||
gtk_container_add (GTK_CONTAINER (flowbox), color_swatch_new (colors[i]));
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.12"/>
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="default-width">600</property>
|
||||
<property name="default-height">500</property>
|
||||
<property name="title">Font Explorer</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<property name="show-title-buttons">1</property>
|
||||
<property name="title">Font Explorer</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="reset">
|
||||
<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>
|
||||
@@ -26,23 +26,22 @@
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="can-focus">1</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="margin-start">10</property>
|
||||
<property name="margin-end">10</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="margin">10</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkFontButton" id="font">
|
||||
<property name="can-focus">1</property>
|
||||
<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>
|
||||
@@ -61,8 +60,9 @@
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<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>
|
||||
@@ -108,10 +108,7 @@
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<property name="margin-start">20</property>
|
||||
<property name="margin-end">20</property>
|
||||
<property name="margin-top">20</property>
|
||||
<property name="margin-bottom">20</property>
|
||||
<property name="margin">20</property>
|
||||
<property name="spacing">20</property>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
@@ -139,7 +136,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>
|
||||
@@ -183,7 +180,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>
|
||||
|
||||
+685
-191
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user