Compare commits
27 Commits
css-variab
...
pango2
Author | SHA1 | Date | |
---|---|---|---|
|
02985ad305 | ||
|
08153dfa20 | ||
|
1f856e4e82 | ||
|
9ca41e00d6 | ||
|
8ebc9418e8 | ||
|
113583c28e | ||
|
30f0d360d3 | ||
|
2a3cd03648 | ||
|
390ec02e05 | ||
|
94c48dba75 | ||
|
82ff952ac0 | ||
|
d9110eadf1 | ||
|
49ceffa41e | ||
|
14e1df0370 | ||
|
f7c4b26c59 | ||
|
a13cfde2a9 | ||
|
3a5d161b8a | ||
|
baabb57df3 | ||
|
a69d39d945 | ||
|
646149bc72 | ||
|
b01eb0600c | ||
|
5b92bf51a0 | ||
|
8ab180b3a9 | ||
|
897195b2f5 | ||
|
d595cc1c55 | ||
|
2841256260 | ||
|
ff0fec0f7d |
@@ -1,10 +1,9 @@
|
||||
# See https://www.apertis.org/policies/coding_conventions/#code-formatting
|
||||
# See https://wiki.apertis.org/Guidelines/Coding_conventions#Code_formatting
|
||||
BasedOnStyle: GNU
|
||||
AlwaysBreakAfterDefinitionReturnType: All
|
||||
BreakBeforeBinaryOperators: None
|
||||
BinPackParameters: false
|
||||
SpaceAfterCStyleCast: true
|
||||
PointerAlignment: Right
|
||||
# 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
|
||||
|
1
.gitignore
vendored
@@ -1,2 +1 @@
|
||||
/subprojects/*/
|
||||
.flatpak-builder/
|
||||
|
355
.gitlab-ci.yml
@@ -3,7 +3,6 @@ include:
|
||||
file: 'flatpak/flatpak_ci_initiative.yml'
|
||||
|
||||
stages:
|
||||
- check
|
||||
- build
|
||||
- analysis
|
||||
- docs
|
||||
@@ -22,43 +21,29 @@ stages:
|
||||
|
||||
# Common variables
|
||||
variables:
|
||||
COMMON_MESON_FLAGS: "-Dwerror=true -Dcairo:werror=false -Dgi-docgen:werror=false -Dgraphene:werror=false -Dlibepoxy:werror=false -Dlibsass:werror=false -Dpango:werror=false -Dsassc:werror=false -Dgdk-pixbuf:werror=false -Dglib:werror=false -Dlibcloudproviders:werror=false -Dlibpng:werror=false -Dlibtiff:werror=false -Dsysprof:werror=false -Dwayland-protocols:werror=false -Dharfbuzz:werror=false -Dfreetype2:werror=false -Dfontconfig:werror=false -Dfribidi:werror=false -Dlibffi:werror=false -Dlibjpeg-turbo:werror=false -Dmutest:werror=false -Dpixman:werror=false -Dproxy-libintl:werror=false"
|
||||
COMMON_MESON_FLAGS: "-Dwerror=true -Dglib:werror=false -Dpango:werror=false -Dgtk-doc:werror=false -Dwayland-protocols:werror=false -Dsysprof:werror=false"
|
||||
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true"
|
||||
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled -Dbuild-testsuite=true -Dintrospection=enabled"
|
||||
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled"
|
||||
MESON_TEST_TIMEOUT_MULTIPLIER: 3
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v49"
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v38"
|
||||
FLATPAK_IMAGE: "registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master"
|
||||
|
||||
workflow:
|
||||
rules:
|
||||
# run merge request pipelines
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
# do not run branch pipelines if corresponding merge requests exist...
|
||||
# (this avoids duplicate pipelines)
|
||||
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
|
||||
when: never
|
||||
# ...but otherwise run branch pipelines
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
# run tag pipelines
|
||||
- if: $CI_COMMIT_TAG
|
||||
|
||||
default:
|
||||
retry:
|
||||
max: 2
|
||||
when:
|
||||
- 'runner_system_failure'
|
||||
- 'stuck_or_timeout_failure'
|
||||
- 'scheduler_failure'
|
||||
- 'api_failure'
|
||||
interruptible: true
|
||||
.only-default:
|
||||
only:
|
||||
- branches
|
||||
except:
|
||||
- tags
|
||||
|
||||
style-check-diff:
|
||||
extends: .only-default
|
||||
image: $FEDORA_IMAGE
|
||||
stage: check
|
||||
when: manual
|
||||
stage: .pre
|
||||
allow_failure: true
|
||||
script:
|
||||
- .gitlab-ci/run-style-check-diff.sh
|
||||
|
||||
.build-fedora-default:
|
||||
extends: .only-default
|
||||
image: $FEDORA_IMAGE
|
||||
artifacts:
|
||||
when: always
|
||||
@@ -66,8 +51,6 @@ style-check-diff:
|
||||
junit:
|
||||
- "${CI_PROJECT_DIR}/_build/report-x11.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-wayland.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-wayland_gl.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-wayland_gles2.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-broadway.xml"
|
||||
name: "gtk-${CI_COMMIT_REF_NAME}"
|
||||
paths:
|
||||
@@ -78,14 +61,17 @@ style-check-diff:
|
||||
- "${CI_PROJECT_DIR}/_build/testsuite/reftests/output/*/*.node"
|
||||
- "${CI_PROJECT_DIR}/_build/testsuite/tools/output/*/*"
|
||||
- "${CI_PROJECT_DIR}/_build/testsuite/gsk/compare/*/*/*.png"
|
||||
- "${CI_PROJECT_DIR}/_build/testsuite/gsk/compare/*/*/*.node"
|
||||
- "${CI_PROJECT_DIR}/_build/testsuite/css/output/*/*.syscap"
|
||||
- "${CI_PROJECT_DIR}/_build/testsuite/headless/*/*.log"
|
||||
- "${CI_PROJECT_DIR}/_build_hello/meson-logs"
|
||||
cache:
|
||||
key: "$CI_JOB_NAME"
|
||||
paths:
|
||||
- _ccache/
|
||||
- subprojects/gdk-pixbuf/
|
||||
- subprojects/glib/
|
||||
- subprojects/graphene/
|
||||
- subprojects/libepoxy/
|
||||
- subprojects/pango/
|
||||
|
||||
fedora-x86_64:
|
||||
extends: .build-fedora-default
|
||||
@@ -95,19 +81,19 @@ fedora-x86_64:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=debug --default-library=both"
|
||||
script:
|
||||
- .gitlab-ci/show-info-linux.sh
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- meson subprojects download
|
||||
- meson subprojects update --reset
|
||||
- meson setup
|
||||
${COMMON_MESON_FLAGS}
|
||||
${EXTRA_MESON_FLAGS}
|
||||
${BACKEND_FLAGS}
|
||||
${FEATURE_FLAGS}
|
||||
- meson subprojects update
|
||||
- mkdir _install
|
||||
- meson --prefix=${CI_PROJECT_DIR}/_install
|
||||
${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} ${BACKEND_FLAGS} ${FEATURE_FLAGS}
|
||||
_build
|
||||
- meson compile -C _build
|
||||
- .gitlab-ci/run-tests.sh _build x11 gtk
|
||||
# only repeat test runs that are likely affected by test setups
|
||||
- .gitlab-ci/run-tests.sh _build wayland_gl gtk:gdk,gtk:gsk-gl
|
||||
- meson install -C _build
|
||||
- PKG_CONFIG_PATH=${CI_PROJECT_DIR}/_install/lib64/pkgconfig:${CI_PROJECT_DIR}/_install/share/pkgconfig meson setup _build_hello examples/hello
|
||||
- LD_LIBRARY_PATH=${CI_PROJECT_DIR}/_install/lib64 meson compile -C _build_hello
|
||||
- .gitlab-ci/run-tests.sh _build x11
|
||||
- .gitlab-ci/run-tests.sh _build wayland
|
||||
- .gitlab-ci/run-tests.sh _build waylandgles
|
||||
- .gitlab-ci/run-tests.sh _build broadway
|
||||
|
||||
release-build:
|
||||
extends: .build-fedora-default
|
||||
@@ -117,71 +103,38 @@ release-build:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=release"
|
||||
script:
|
||||
- .gitlab-ci/show-info-linux.sh
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- meson subprojects download
|
||||
- meson subprojects update --reset
|
||||
- mkdir _install
|
||||
- meson setup
|
||||
--prefix=${CI_PROJECT_DIR}/_install
|
||||
${COMMON_MESON_FLAGS}
|
||||
${EXTRA_MESON_FLAGS}
|
||||
${BACKEND_FLAGS}
|
||||
${FEATURE_FLAGS}
|
||||
- meson subprojects update
|
||||
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} ${BACKEND_FLAGS} ${FEATURE_FLAGS}
|
||||
_build
|
||||
- meson compile -C _build
|
||||
- meson install -C _build
|
||||
- PKG_CONFIG_PATH=${CI_PROJECT_DIR}/_install/lib64/pkgconfig:${CI_PROJECT_DIR}/_install/share/pkgconfig meson setup _build_hello examples/hello
|
||||
- LD_LIBRARY_PATH=${CI_PROJECT_DIR}/_install/lib64 meson compile -C _build_hello
|
||||
- .gitlab-ci/run-tests.sh _build wayland gtk
|
||||
# only repeat test runs that are likely affected by test setups
|
||||
- .gitlab-ci/run-tests.sh _build wayland_gles2 gtk:gdk,gtk:gsk-gl
|
||||
- ninja -C _build
|
||||
- .gitlab-ci/run-tests.sh _build x11
|
||||
|
||||
fedora-clang:
|
||||
installed-tests:
|
||||
extends: .build-fedora-default
|
||||
stage: build
|
||||
needs: []
|
||||
variables:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=release"
|
||||
EXTRA_MESON_FLAGS: "--prefix=/usr --libdir=/usr/lib64 -Dinstall-tests=true"
|
||||
G_TEST_ACCESSIBLE: 1
|
||||
script:
|
||||
- .gitlab-ci/show-info-linux.sh
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- export CC=clang
|
||||
- meson subprojects download
|
||||
- meson subprojects update --reset
|
||||
- meson setup
|
||||
${COMMON_MESON_FLAGS}
|
||||
${EXTRA_MESON_FLAGS}
|
||||
${BACKEND_FLAGS}
|
||||
${FEATURE_FLAGS}
|
||||
- meson subprojects update
|
||||
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} ${BACKEND_FLAGS} ${FEATURE_FLAGS}
|
||||
_build
|
||||
- meson compile -C _build
|
||||
- ninja -C _build
|
||||
- sudo ninja -C _build install
|
||||
- dbus-run-session xvfb-run -a -s "-screen 0 1024x768x24"
|
||||
gnome-desktop-testing-runner
|
||||
--report-directory=_build/installed-tests-report/failed/
|
||||
--parallel=0
|
||||
gtk-4.0
|
||||
artifacts:
|
||||
paths:
|
||||
- "_build/installed-tests-report/"
|
||||
|
||||
fedora-mingw64:
|
||||
extends: .build-fedora-default
|
||||
stage: build
|
||||
needs: []
|
||||
before_script:
|
||||
- sudo dnf install -y
|
||||
mingw64-filesystem
|
||||
mingw64-gcc
|
||||
mingw64-binutils
|
||||
mingw64-cairo
|
||||
mingw64-gdk-pixbuf
|
||||
mingw64-gstreamer1-plugins-bad-free
|
||||
mingw64-glib2
|
||||
mingw64-libepoxy
|
||||
mingw64-pango
|
||||
# mingw64-graphene (rawhide)
|
||||
script:
|
||||
- .gitlab-ci/show-info-linux.sh
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- pip3 install --user meson~=1.0
|
||||
- meson subprojects download
|
||||
- meson subprojects update --reset
|
||||
- meson -Dintrospection=disabled -Dgraphene:introspection=disabled _build
|
||||
- meson compile -C _build
|
||||
|
||||
.mingw-defaults:
|
||||
extends: .only-default
|
||||
stage: build
|
||||
tags:
|
||||
- win32-ps
|
||||
@@ -211,64 +164,39 @@ msys2-mingw64:
|
||||
- "${CI_PROJECT_DIR}/_build/gtkdll.tar.gz"
|
||||
|
||||
macos:
|
||||
rules:
|
||||
# Do not run in forks as the runner is not available there.
|
||||
# (except for dehesselle who maintains the runner)
|
||||
- if: $CI_PROJECT_NAMESPACE != "GNOME" && $CI_PROJECT_NAMESPACE != "dehesselle"
|
||||
when: never
|
||||
- if: $RUNNER == "macosintel"
|
||||
variables:
|
||||
SDKROOT: /opt/sdks/MacOSX10.13.4.sdk
|
||||
NINJA_PKG: $CI_API_V4_URL/projects/30745/packages/generic/ninja_macos/v1.11.1.1+9/ninja-1.11.1.1-cp38-cp38-macosx_11_0_x86_64.whl
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- if: $RUNNER == "macosarm"
|
||||
variables:
|
||||
SDKROOT: /opt/sdks/MacOSX11.3.sdk
|
||||
NINJA_PKG: ninja==1.11.1.1
|
||||
extends: .only-default
|
||||
only:
|
||||
- branches@GNOME/gtk
|
||||
stage: build
|
||||
parallel:
|
||||
matrix:
|
||||
- RUNNER: [ "macosintel", "macosarm" ]
|
||||
tags:
|
||||
- ${RUNNER}
|
||||
- macos
|
||||
needs: []
|
||||
variables:
|
||||
EXTRA_MESON_FLAGS: ""
|
||||
BACKEND_FLAGS: "-Dx11-backend=false -Dbroadway-backend=true"
|
||||
FEATURE_FLAGS: "-Dmedia-gstreamer=disabled -Dintrospection=enabled -Dgobject-introspection:werror=false"
|
||||
TMPDIR: /Users/Shared/work/tmp
|
||||
PIP_CACHE_DIR: /Users/Shared/build/cache
|
||||
PIPENV_CACHE_DIR: $PIP_CACHE_DIR
|
||||
PYTHONPYCACHEPREFIX: $PIP_CACHE_DIR
|
||||
before_script:
|
||||
- .gitlab-ci/show-info-macos.sh
|
||||
- python3 -m venv .venv
|
||||
# Building the introspection feature requires pkg-config and bison.
|
||||
- curl -L $CI_API_V4_URL/projects/30437/packages/generic/pkgconfig/v0.29.2+10/pkg-config-0.29.2+10_$(uname -m).tar.xz | tar -C .venv -xJ
|
||||
- curl -L $CI_API_V4_URL/projects/30438/packages/generic/bison/v3.8.2+3/bison-3.8.2+3_$(uname -m).tar.xz | tar -C .venv -xJ
|
||||
- source .venv/bin/activate
|
||||
- pip3 install meson==1.3.2 $NINJA_PKG
|
||||
# We're not setting up ccache here on purpose as it accelerates the build
|
||||
# so much that it triggers race conditions in the gobject-introspection
|
||||
# subproject.
|
||||
- bash .gitlab-ci/show-info-osx.sh
|
||||
- pip3 install --user meson==0.60.3
|
||||
- pip3 install --user ninja
|
||||
- export PATH=/Users/gitlabrunner/Library/Python/3.7/bin:$PATH
|
||||
- export MESON_FORCE_BACKTRACE=1
|
||||
script:
|
||||
- meson setup
|
||||
${COMMON_MESON_FLAGS}
|
||||
${EXTRA_MESON_FLAGS}
|
||||
${BACKEND_FLAGS}
|
||||
${FEATURE_FLAGS}
|
||||
- meson -Dx11-backend=false
|
||||
-Dbroadway-backend=true
|
||||
-Dmacos-backend=true
|
||||
-Dmedia-gstreamer=disabled
|
||||
-Dintrospection=disabled
|
||||
-Dcpp_std=c++11
|
||||
-Dpixman:tests=disabled
|
||||
_build
|
||||
- meson compile -C _build
|
||||
- ninja -C _build
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- "${CI_PROJECT_DIR}/_build/meson-logs"
|
||||
|
||||
vs2017-x64:
|
||||
extends: .only-default
|
||||
# TODO: Uncomment this when ready to merge.
|
||||
# rules:
|
||||
# - if: $CI_PROJECT_NAMESPACE == "GNOME"
|
||||
#only:
|
||||
# - branches@GNOME/gtk
|
||||
stage: build
|
||||
tags:
|
||||
- win32-ps
|
||||
@@ -281,7 +209,7 @@ vs2017-x64:
|
||||
- "${CI_PROJECT_DIR}/_build/meson-logs"
|
||||
|
||||
.flatpak-defaults:
|
||||
image: "quay.io/gnome_infrastructure/gnome-runtime-images:gnome-master"
|
||||
image: $FLATPAK_IMAGE
|
||||
stage: flatpak
|
||||
allow_failure: true
|
||||
tags:
|
||||
@@ -291,104 +219,73 @@ vs2017-x64:
|
||||
- "${APPID}-dev.flatpak"
|
||||
- 'repo.tar'
|
||||
expire_in: 1 day
|
||||
rules:
|
||||
# Only build Flatpak bundles automatically on main
|
||||
- if: $CI_COMMIT_BRANCH == "main"
|
||||
- if: $CI_COMMIT_BRANCH != "main"
|
||||
when: "manual"
|
||||
script:
|
||||
- bash -x ./.gitlab-ci/flatpak-build.sh "${APPID}"
|
||||
|
||||
flatpak:demo:
|
||||
extends: '.flatpak-defaults'
|
||||
# Manual jobs, for branches and MRs
|
||||
.flatpak-manual:
|
||||
extends: .flatpak-defaults
|
||||
when: manual
|
||||
|
||||
# Only build Flatpak bundles automatically on main
|
||||
.flatpak-main:
|
||||
extends: .flatpak-defaults
|
||||
only:
|
||||
- main
|
||||
|
||||
flatpak-manual:demo:
|
||||
extends: .flatpak-manual
|
||||
needs: []
|
||||
variables:
|
||||
APPID: org.gtk.Demo4
|
||||
|
||||
flatpak:demo:aarch64:
|
||||
extends: '.flatpak-defaults'
|
||||
flatpak-main:demo:
|
||||
extends: .flatpak-main
|
||||
needs: []
|
||||
tags:
|
||||
- flatpak-aarch64
|
||||
variables:
|
||||
APPID: org.gtk.Demo4
|
||||
|
||||
flatpak:widget-factory:
|
||||
extends: '.flatpak-defaults'
|
||||
flatpak-manual:widget-factory:
|
||||
extends: .flatpak-manual
|
||||
needs: []
|
||||
variables:
|
||||
APPID: org.gtk.WidgetFactory4
|
||||
|
||||
flatpak:widget-factory:aarch64:
|
||||
extends: '.flatpak-defaults'
|
||||
flatpak-main:widget-factory:
|
||||
extends: .flatpak-main
|
||||
needs: []
|
||||
tags:
|
||||
- flatpak-aarch64
|
||||
variables:
|
||||
APPID: org.gtk.WidgetFactory4
|
||||
|
||||
flatpak:icon-browser:
|
||||
extends: '.flatpak-defaults'
|
||||
flatpak-manual:icon-browser:
|
||||
extends: .flatpak-manual
|
||||
needs: []
|
||||
variables:
|
||||
APPID: org.gtk.IconBrowser4
|
||||
|
||||
flatpak:icon-browser:aarch64:
|
||||
extends: '.flatpak-defaults'
|
||||
flatpak-main:icon-browser:
|
||||
extends: .flatpak-main
|
||||
needs: []
|
||||
tags:
|
||||
- flatpak-aarch64
|
||||
variables:
|
||||
APPID: org.gtk.IconBrowser4
|
||||
|
||||
flatpak:node-editor:
|
||||
extends: '.flatpak-defaults'
|
||||
needs: []
|
||||
variables:
|
||||
APPID: org.gtk.gtk4.NodeEditor
|
||||
|
||||
flatpak:node-editor:aarch64:
|
||||
extends: '.flatpak-defaults'
|
||||
needs: []
|
||||
tags:
|
||||
- flatpak-aarch64
|
||||
variables:
|
||||
APPID: org.gtk.gtk4.NodeEditor
|
||||
|
||||
# Publish the demo apps to the GNOME Nightly repo
|
||||
# https://wiki.gnome.org/Apps/Nightly
|
||||
# https://gitlab.gnome.org/GNOME/Initiatives/-/wikis/DevOps-with-Flatpak
|
||||
nightly demo:
|
||||
extends: '.publish_nightly'
|
||||
needs: ['flatpak:demo']
|
||||
|
||||
nightly demo aarch64:
|
||||
extends: '.publish_nightly'
|
||||
needs: ['flatpak:demo:aarch64']
|
||||
dependencies: ['flatpak-main:demo']
|
||||
needs: ['flatpak-main:demo']
|
||||
|
||||
nightly factory:
|
||||
extends: '.publish_nightly'
|
||||
needs: ['flatpak:widget-factory']
|
||||
|
||||
nightly factory aarch64:
|
||||
extends: '.publish_nightly'
|
||||
needs: ['flatpak:widget-factory:aarch64']
|
||||
dependencies: ['flatpak-main:widget-factory']
|
||||
needs: ['flatpak-main:widget-factory']
|
||||
|
||||
nightly icon-browser:
|
||||
extends: '.publish_nightly'
|
||||
needs: ['flatpak:icon-browser']
|
||||
|
||||
nightly icon-browser aarch64:
|
||||
extends: '.publish_nightly'
|
||||
needs: ['flatpak:icon-browser:aarch64']
|
||||
|
||||
nightly node-editor:
|
||||
extends: '.publish_nightly'
|
||||
needs: ['flatpak:node-editor']
|
||||
|
||||
nightly node-editor aarch64:
|
||||
extends: '.publish_nightly'
|
||||
needs: ['flatpak:node-editor:aarch64']
|
||||
dependencies: ['flatpak-main:icon-browser']
|
||||
needs: ['flatpak-main:icon-browser']
|
||||
|
||||
static-scan:
|
||||
image: $FEDORA_IMAGE
|
||||
@@ -397,21 +294,15 @@ static-scan:
|
||||
variables:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=debug"
|
||||
script:
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- meson setup
|
||||
${COMMON_MESON_FLAGS}
|
||||
${EXTRA_MESON_FLAGS}
|
||||
${BACKEND_FLAGS}
|
||||
${FEATURE_FLAGS}
|
||||
_scan_build
|
||||
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} _scan_build
|
||||
- ninja -C _scan_build scan-build
|
||||
artifacts:
|
||||
paths:
|
||||
- _scan_build/meson-logs
|
||||
allow_failure: true
|
||||
|
||||
# Run tests with the address sanitizer. We need to turn off introspection
|
||||
# and f16c, since they are incompatible with asan
|
||||
# Run tests with the address sanitizer. We need to turn off introspection,
|
||||
# since it is incompatible with asan
|
||||
asan-build:
|
||||
image: $FEDORA_IMAGE
|
||||
tags: [ asan ]
|
||||
@@ -419,39 +310,22 @@ asan-build:
|
||||
needs: []
|
||||
variables:
|
||||
script:
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- CC=clang meson setup
|
||||
--buildtype=debugoptimized
|
||||
-Db_sanitize=address
|
||||
-Db_lundef=false
|
||||
-Dbuild-demos=false
|
||||
-Dbuild-tests=false
|
||||
-Dbuild-examples=false
|
||||
-Dintrospection=disabled
|
||||
-Df16c=disabled
|
||||
_build
|
||||
- CC=clang meson --buildtype=debugoptimized -Db_sanitize=address -Db_lundef=false -Dintrospection=disabled _build
|
||||
- ninja -C _build
|
||||
- .gitlab-ci/run-tests.sh _build wayland gtk
|
||||
- .gitlab-ci/run-tests.sh _build wayland
|
||||
artifacts:
|
||||
paths:
|
||||
- _build/meson-logs
|
||||
allow_failure: true
|
||||
|
||||
reference:
|
||||
image: $FEDORA_IMAGE
|
||||
stage: docs
|
||||
needs: []
|
||||
variables:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=release --force-fallback-for=gdk-pixbuf,pango"
|
||||
script:
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- meson setup
|
||||
${COMMON_MESON_FLAGS}
|
||||
--buildtype=release
|
||||
--force-fallback-for=gdk-pixbuf,pango
|
||||
-Dintrospection=enabled
|
||||
-Ddocumentation=true
|
||||
-Dgdk-pixbuf:gtk_doc=true
|
||||
-Dpango:documentation=true
|
||||
-Dbuild-demos=false
|
||||
-Dbuild-examples=false
|
||||
-Dbuild-tests=false
|
||||
-Dbuild-testsuite=false
|
||||
_build
|
||||
- meson ${COMMON_MESON_FLAGS} ${EXTRA_MESON_FLAGS} -Dgtk_doc=true -Dgdk-pixbuf:gtk_doc=true -Dpango:gtk_doc=true _build
|
||||
- meson compile -C _build
|
||||
- mkdir -p _reference/
|
||||
- mv _build/docs/reference/gdk/gdk4/ _reference/gdk4/
|
||||
@@ -474,10 +348,9 @@ reference:
|
||||
publish-docs:
|
||||
image: fedora:latest
|
||||
stage: publish
|
||||
interruptible: false
|
||||
needs: ['reference']
|
||||
script:
|
||||
- "curl -X POST -F token=${PAGES_TRIGGER_TOKEN} -F ref=docs-gtk-org https://gitlab.gnome.org/api/v4/projects/665/trigger/pipeline"
|
||||
rules:
|
||||
- if: $CI_COMMIT_REF_NAME == "main"
|
||||
|
||||
only:
|
||||
refs:
|
||||
- main
|
||||
|
@@ -1,7 +1,9 @@
|
||||
FROM fedora:39
|
||||
FROM fedora:36
|
||||
|
||||
RUN dnf -y install \
|
||||
adwaita-icon-theme \
|
||||
atk-devel \
|
||||
at-spi2-atk-devel \
|
||||
avahi-gobject-devel \
|
||||
cairo-devel \
|
||||
cairo-gobject-devel \
|
||||
@@ -17,7 +19,6 @@ RUN dnf -y install \
|
||||
desktop-file-utils \
|
||||
diffutils \
|
||||
elfutils-libelf-devel \
|
||||
expat-devel \
|
||||
fribidi-devel \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
@@ -29,8 +30,7 @@ RUN dnf -y install \
|
||||
glib2-static \
|
||||
glibc-devel \
|
||||
glibc-headers \
|
||||
glslc \
|
||||
gnupg2 \
|
||||
gnome-desktop-testing \
|
||||
gobject-introspection-devel \
|
||||
graphene-devel \
|
||||
graphviz \
|
||||
@@ -71,22 +71,18 @@ RUN dnf -y install \
|
||||
mesa-libEGL-devel \
|
||||
mesa-libGLES-devel \
|
||||
meson \
|
||||
mutter \
|
||||
ninja-build \
|
||||
pango-devel \
|
||||
pcre-devel \
|
||||
pcre-static \
|
||||
pipewire \
|
||||
pipewire-gstreamer \
|
||||
python3 \
|
||||
python3-docutils \
|
||||
python3-gobject \
|
||||
python3-jinja2 \
|
||||
python3-markdown \
|
||||
python3-packaging \
|
||||
python3-pip \
|
||||
python3-pydbus \
|
||||
python3-pygments \
|
||||
python3-toml \
|
||||
python3-typogrify \
|
||||
python3-wheel \
|
||||
redhat-rpm-config \
|
||||
@@ -97,8 +93,9 @@ RUN dnf -y install \
|
||||
weston \
|
||||
weston-libs \
|
||||
which \
|
||||
wireplumber \
|
||||
xorg-x11-server-Xvfb \
|
||||
&& dnf install -y 'dnf-command(builddep)' \
|
||||
&& dnf builddep -y wayland \
|
||||
&& dnf clean all
|
||||
|
||||
# Enable sudo for wheel users
|
||||
|
@@ -16,18 +16,18 @@ flatpak-builder \
|
||||
flatpak build ${builddir} meson \
|
||||
--prefix=/app \
|
||||
--libdir=/app/lib \
|
||||
--buildtype=debugoptimized \
|
||||
--buildtype=release \
|
||||
-Dx11-backend=true \
|
||||
-Dwayland-backend=true \
|
||||
-Dprint-backends=file \
|
||||
-Dbuild-tests=false \
|
||||
-Dbuild-testsuite=false \
|
||||
-Dbuild-examples=false \
|
||||
-Dintrospection=disabled \
|
||||
-Dbuild-demos=true \
|
||||
-Ddemos=true \
|
||||
-Dprofile=devel \
|
||||
_flatpak_build
|
||||
|
||||
flatpak build --env=CI_COMMIT_SHORT_SHA=$CI_COMMIT_SHORT_SHA ${builddir} ninja -C _flatpak_build install
|
||||
flatpak build ${builddir} ninja -C _flatpak_build install
|
||||
|
||||
flatpak-builder \
|
||||
--user --disable-rofiles-fuse \
|
||||
|
@@ -324,7 +324,7 @@ for line in args.infile:
|
||||
units.append(unit)
|
||||
|
||||
report = {}
|
||||
report['date'] = datetime.datetime.now(datetime.UTC)
|
||||
report['date'] = datetime.datetime.utcnow()
|
||||
report['locale_date'] = report['date'].strftime("%c")
|
||||
report['project_name'] = args.project_name
|
||||
report['backend'] = args.backend
|
||||
|
@@ -44,7 +44,7 @@ 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.now(datetime.UTC).isoformat(timespec='minutes'))
|
||||
testsuites.set('timestamp', datetime.datetime.utcnow().isoformat(timespec='minutes'))
|
||||
|
||||
suites = {}
|
||||
for line in args.infile:
|
||||
|
@@ -23,7 +23,6 @@ push=0
|
||||
list=0
|
||||
print_help=0
|
||||
no_login=0
|
||||
no_cache=0
|
||||
|
||||
while (($# > 0)); do
|
||||
case "${1%%=*}" in
|
||||
@@ -35,7 +34,6 @@ while (($# > 0)); do
|
||||
--base|-b) read_arg base "$@" || shift;;
|
||||
--version|-v) read_arg base_version "$@" || shift;;
|
||||
--no-login) no_login=1;;
|
||||
--no-cache) no_cache=1;;
|
||||
*) echo -e "\e[1;31mERROR\e[0m: Unknown option '$1'"; exit 1;;
|
||||
esac
|
||||
shift
|
||||
@@ -105,21 +103,11 @@ TAG="${REGISTRY}/gnome/gtk/${base}:${base_version}"
|
||||
|
||||
if [ $build == 1 ]; then
|
||||
echo -e "\e[1;32mBUILDING\e[0m: ${base} as ${TAG}"
|
||||
if [ $no_cache == 0 ]; then
|
||||
${CMD} build \
|
||||
${format} \
|
||||
--build-arg HOST_USER_ID="$UID" \
|
||||
--tag "${TAG}" \
|
||||
--file "${base}.Dockerfile" .
|
||||
else
|
||||
${CMD} build \
|
||||
${format} \
|
||||
--no-cache \
|
||||
--build-arg HOST_USER_ID="$UID" \
|
||||
--tag "${TAG}" \
|
||||
--file "${base}.Dockerfile" .
|
||||
fi
|
||||
|
||||
${CMD} build \
|
||||
${format} \
|
||||
--build-arg HOST_USER_ID="$UID" \
|
||||
--tag "${TAG}" \
|
||||
--file "${base}.Dockerfile" .
|
||||
exit $?
|
||||
fi
|
||||
|
||||
@@ -138,8 +126,7 @@ if [ $run == 1 ]; then
|
||||
echo -e "\e[1;32mRUNNING\e[0m: ${base} as ${TAG}"
|
||||
${CMD} run \
|
||||
--rm \
|
||||
--userns=keep-id \
|
||||
--volume "$(pwd)/..:/home/user/app:rw,z" \
|
||||
--volume "$(pwd)/..:/home/user/app" \
|
||||
--workdir "/home/user/app" \
|
||||
--tty \
|
||||
--interactive "${TAG}" \
|
||||
|
@@ -1,32 +0,0 @@
|
||||
#!/usr/bin/sh
|
||||
#
|
||||
builddir=$1
|
||||
suite=$2
|
||||
unit=$3
|
||||
|
||||
echo "** builddir: ${builddir}"
|
||||
echo "** suite: ${suite}"
|
||||
echo "** unit: ${unit}"
|
||||
|
||||
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=wayland \
|
||||
--suite=${suite} \
|
||||
--no-suite=failing \
|
||||
--no-suite=flaky \
|
||||
--no-suite=wayland_failing \
|
||||
--no-suite=gsk-compare-broadway \
|
||||
--verbose \
|
||||
"${unit}"
|
||||
|
||||
exit_code=$?
|
||||
kill ${compositor}
|
||||
|
||||
exit ${exit_code}
|
@@ -2,43 +2,25 @@
|
||||
|
||||
set -e
|
||||
|
||||
ancestor_horizon=31 # days (one month)
|
||||
|
||||
# Recently, git is picky about directory ownership. Tell it not to worry.
|
||||
git config --global --add safe.directory "$PWD"
|
||||
|
||||
# We need to add a new remote for the upstream target branch, since this script
|
||||
# could be running in a personal fork of the repository which has out of date
|
||||
# branches.
|
||||
#
|
||||
# Limit the fetch to a certain date horizon to limit the amount of data we get.
|
||||
# If the branch was forked from origin/main before this horizon, it should
|
||||
# probably be rebased.
|
||||
if ! git ls-remote --exit-code upstream >/dev/null 2>&1 ; then
|
||||
# We need to add a new remote for the upstream main, since this script could
|
||||
# be running in a personal fork of the repository which has out of date branches.
|
||||
if [ "${CI_PROJECT_NAMESPACE}" != "GNOME" ]; then
|
||||
echo "Retrieving the current upstream repository from ${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}..."
|
||||
git remote add upstream https://gitlab.gnome.org/GNOME/gtk.git
|
||||
git fetch upstream
|
||||
ORIGIN="upstream"
|
||||
else
|
||||
echo "Reusing the existing repository on ${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}"
|
||||
ORIGIN="origin"
|
||||
fi
|
||||
|
||||
# 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/main` or `upstream/glib-2-62`).
|
||||
# `${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}` or `${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}`
|
||||
# are only defined if we’re running in a merge request pipeline,
|
||||
# fall back to `${CI_DEFAULT_BRANCH}` or `${CI_COMMIT_BRANCH}` respectively
|
||||
# otherwise.
|
||||
|
||||
source_branch="${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME:-${CI_COMMIT_BRANCH}}"
|
||||
target_branch="${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-${CI_DEFAULT_BRANCH}}"
|
||||
git fetch --shallow-since="$(date --date="${ancestor_horizon} days ago" +%Y-%m-%d)" origin "${source_branch}"
|
||||
git fetch --shallow-since="$(date --date="${ancestor_horizon} days ago" +%Y-%m-%d)" upstream "${target_branch}"
|
||||
|
||||
newest_common_ancestor_sha=$(git merge-base upstream/${target_branch} origin/${source_branch})
|
||||
if [ -z "${newest_common_ancestor_sha}" ]; then
|
||||
echo "Couldn’t find common ancestor with upstream main branch. This typically"
|
||||
echo "happens if you branched from main a long time ago. Please update"
|
||||
echo "your clone, rebase, and re-push your branch."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# `upstream/main` 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 "${ORIGIN}/${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=$?
|
||||
|
||||
@@ -54,7 +36,7 @@ exit_status=$?
|
||||
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/main/docs/CODING-STYLE.md"
|
||||
echo " https://gitlab.gnome.org/GNOME/gtk/blob/main/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."
|
||||
|
@@ -1,31 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
set +x
|
||||
set +e
|
||||
|
||||
srcdir=$( pwd )
|
||||
builddir=$1
|
||||
setup=$2
|
||||
suite=$3
|
||||
multiplier=${MESON_TEST_TIMEOUT_MULTIPLIER:-1}
|
||||
backend=$2
|
||||
|
||||
# Ignore memory leaks lower in dependencies
|
||||
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp:print_suppressions=0:detect_leaks=0:allocator_may_return_null=1
|
||||
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp:print_suppressions=0
|
||||
export G_SLICE=always-malloc
|
||||
|
||||
case "${setup}" in
|
||||
x11*)
|
||||
case "${backend}" in
|
||||
x11)
|
||||
xvfb-run -a -s "-screen 0 1024x768x24 -noreset" \
|
||||
meson test -C ${builddir} \
|
||||
--quiet \
|
||||
--timeout-multiplier "${multiplier}" \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${setup} \
|
||||
--suite=${suite//,/ --suite=} \
|
||||
--no-suite=failing \
|
||||
--no-suite=${setup}_failing \
|
||||
--no-suite=flaky \
|
||||
--no-suite=headless \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
--no-suite=gsk-compare-broadway
|
||||
|
||||
# Store the exit code for the CI run, but always
|
||||
@@ -33,7 +26,7 @@ case "${setup}" in
|
||||
exit_code=$?
|
||||
;;
|
||||
|
||||
wayland*)
|
||||
wayland)
|
||||
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
|
||||
|
||||
weston --backend=headless-backend.so --socket=wayland-5 --idle-time=0 &
|
||||
@@ -41,22 +34,35 @@ case "${setup}" in
|
||||
export WAYLAND_DISPLAY=wayland-5
|
||||
|
||||
meson test -C ${builddir} \
|
||||
--quiet \
|
||||
--timeout-multiplier "${multiplier}" \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${setup} \
|
||||
--suite=${suite//,/ --suite=} \
|
||||
--no-suite=failing \
|
||||
--no-suite=${setup}_failing \
|
||||
--no-suite=flaky \
|
||||
--no-suite=headless \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
--no-suite=gsk-compare-broadway
|
||||
exit_code=$?
|
||||
|
||||
exit_code=$?
|
||||
kill ${compositor}
|
||||
;;
|
||||
|
||||
broadway*)
|
||||
waylandgles)
|
||||
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
|
||||
|
||||
weston --backend=headless-backend.so --socket=wayland-6 --idle-time=0 &
|
||||
compositor=$!
|
||||
export WAYLAND_DISPLAY=wayland-6
|
||||
|
||||
meson test -C ${builddir} \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
--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 &
|
||||
@@ -64,22 +70,19 @@ case "${setup}" in
|
||||
export BROADWAY_DISPLAY=:5
|
||||
|
||||
meson test -C ${builddir} \
|
||||
--quiet \
|
||||
--timeout-multiplier "${multiplier}" \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${setup} \
|
||||
--suite=${suite//,/ --suite=} \
|
||||
--no-suite=failing \
|
||||
--no-suite=${setup}_failing \
|
||||
--no-suite=flaky \
|
||||
--no-suite=headless \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
--no-suite=gsk-compare-opengl
|
||||
|
||||
# don't let Broadway failures fail the run, for now
|
||||
exit_code=0
|
||||
kill ${server}
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Failed to add ${setup} to .gitlab-ci/run-tests.sh"
|
||||
echo "Failed to add ${backend} to .gitlab-ci/run-tests.sh"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
@@ -88,18 +91,17 @@ esac
|
||||
cd ${builddir}
|
||||
|
||||
$srcdir/.gitlab-ci/meson-junit-report.py \
|
||||
--project-name=gtk \
|
||||
--backend="${setup}" \
|
||||
--job-id="${CI_JOB_NAME}" \
|
||||
--output="report-${setup}.xml" \
|
||||
"meson-logs/testlog-${setup}.json"
|
||||
|
||||
--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="${setup}" \
|
||||
--job-id="${CI_JOB_NAME}" \
|
||||
--reftest-output-dir="testsuite/reftests/output/${setup}" \
|
||||
--output="report-${setup}.html" \
|
||||
"meson-logs/testlog-${setup}.json"
|
||||
--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
|
||||
|
@@ -3,11 +3,6 @@
|
||||
set -eux -o pipefail
|
||||
|
||||
xcodebuild -version || :
|
||||
|
||||
if [ -z "$SDKROOT" ]; then
|
||||
xcodebuild -showsdks || :
|
||||
else
|
||||
echo "SDKROOT = $SDKROOT"
|
||||
fi
|
||||
xcodebuild -showsdks || :
|
||||
|
||||
system_profiler SPSoftwareDataType || :
|
@@ -5,8 +5,8 @@ call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliar
|
||||
@echo on
|
||||
|
||||
:: FIXME: make warnings fatal
|
||||
pip3 install --upgrade --user meson~=0.64 || goto :error
|
||||
meson setup -Dbackend_max_links=1 -Ddebug=false -Dmedia-gstreamer=disabled -Dvulkan=disabled _build || goto :error
|
||||
pip3 install --upgrade --user meson==0.60.3 || goto :error
|
||||
meson -Ddebug=false -Dmedia-gstreamer=disabled _build || goto :error
|
||||
ninja -C _build || goto :error
|
||||
|
||||
goto :EOF
|
||||
|
@@ -28,27 +28,44 @@ pacman --noconfirm -S --needed \
|
||||
mingw-w64-$MSYS2_ARCH-graphene \
|
||||
mingw-w64-$MSYS2_ARCH-json-glib \
|
||||
mingw-w64-$MSYS2_ARCH-libepoxy \
|
||||
mingw-w64-$MSYS2_ARCH-pango \
|
||||
mingw-w64-$MSYS2_ARCH-pango2 \
|
||||
mingw-w64-$MSYS2_ARCH-fribidi \
|
||||
mingw-w64-$MSYS2_ARCH-gst-plugins-bad-libs \
|
||||
mingw-w64-$MSYS2_ARCH-shared-mime-info \
|
||||
mingw-w64-$MSYS2_ARCH-python-gobject \
|
||||
mingw-w64-$MSYS2_ARCH-shaderc \
|
||||
mingw-w64-$MSYS2_ARCH-vulkan \
|
||||
mingw-w64-$MSYS2_ARCH-vulkan-headers
|
||||
mingw-w64-$MSYS2_ARCH-python-gobject
|
||||
|
||||
mkdir -p _ccache
|
||||
export CCACHE_BASEDIR="$(pwd)"
|
||||
export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache"
|
||||
|
||||
# https://gitlab.gnome.org/GNOME/gtk/-/issues/2243
|
||||
# https://gitlab.gnome.org/GNOME/gtk/-/issues/3002
|
||||
|
||||
if ! pkg-config --atleast-version=2.66.0 glib-2.0; then
|
||||
git clone https://gitlab.gnome.org/GNOME/glib.git _glib
|
||||
meson setup _glib_build _glib
|
||||
meson compile -C _glib_build
|
||||
meson install -C _glib_build
|
||||
fi
|
||||
pkg-config --modversion glib-2.0
|
||||
|
||||
if ! pkg-config --atleast-version=1.50.0 pango; then
|
||||
git clone https://gitlab.gnome.org/GNOME/pango.git _pango
|
||||
meson setup _pango_build _pango
|
||||
meson compile -C _pango_build
|
||||
meson install -C _pango_build
|
||||
fi
|
||||
pkg-config --modversion pango
|
||||
|
||||
# Build
|
||||
ccache --zero-stats
|
||||
ccache --show-stats
|
||||
export CCACHE_DISABLE=true
|
||||
meson setup \
|
||||
meson \
|
||||
-Dx11-backend=false \
|
||||
-Dwayland-backend=false \
|
||||
-Dwin32-backend=true \
|
||||
-Dvulkan=disabled \
|
||||
-Dintrospection=enabled \
|
||||
-Dgtk:werror=true \
|
||||
_build
|
||||
|
45
AUTHORS
@@ -7,7 +7,7 @@ Peter Mattis <petm@xcf.berkeley.edu>
|
||||
Spencer Kimball <spencer@xcf.berkeley.edu>
|
||||
Josh MacDonald <jmacd@xcf.berkeley.edu>
|
||||
|
||||
The team that build GTK 2 (in alphabetical order)
|
||||
The Team that build GTK 2 (in alphabetical order)
|
||||
-------------------------------------------------
|
||||
Shawn T. Amundson <amundson@gtk.org>
|
||||
Jerome Bolliet <bolliet@gtk.org>
|
||||
@@ -28,8 +28,9 @@ Jay Painter <jpaint@gtk.org>
|
||||
Manish Singh <manish@gtk.org>
|
||||
Owen Taylor <otaylor@gtk.org>
|
||||
|
||||
The team that built GTK 3
|
||||
-------------------------
|
||||
The current team (GTK 3 and 4)
|
||||
------------------------------
|
||||
|
||||
Jonas Ådahl <jadahl@gmail.com>
|
||||
Tim Bäder <mail@baedert.org>
|
||||
Emmanuele Bassi <ebassi@gnome.org>
|
||||
@@ -39,16 +40,6 @@ Carlos Garnacho <mrgarnacho@gmail.com>
|
||||
Alexander Larsson <alexl@redhat.com>
|
||||
Benjamin Otte <otte@gnome.org>
|
||||
|
||||
The current team (GTK 4)
|
||||
------------------------
|
||||
Jonas Ådahl <jadahl@gmail.com>
|
||||
Emmanuele Bassi <ebassi@gnome.org>
|
||||
Christian Hergert <chergert@gnome.org>
|
||||
Chun-wei Fan <fanchunwei@src.gnome.org>
|
||||
Matthias Clasen <mclasen@redhat.com>
|
||||
Carlos Garnacho <mrgarnacho@gmail.com>
|
||||
Benjamin Otte <otte@gnome.org>
|
||||
|
||||
|
||||
There are many others who have contributed patches; we thank them,
|
||||
GTK is much better because of them.
|
||||
@@ -58,15 +49,35 @@ Over time, GTK has incorporated some pieces of software which
|
||||
started as independent projects. We list the original authors here:
|
||||
|
||||
|
||||
MS-Windows theme engine
|
||||
-----------------------
|
||||
Raymond Penners
|
||||
Dom Lachowicz
|
||||
|
||||
|
||||
Pixbuf theme engine
|
||||
-------------------
|
||||
Owen Taylor
|
||||
|
||||
|
||||
IME input method
|
||||
----------------
|
||||
Takuro Ashie
|
||||
Kazuki IWAMOTO
|
||||
|
||||
MacOS backend
|
||||
-------------
|
||||
|
||||
Mac OS X backend
|
||||
----------------
|
||||
Anders Carlsson
|
||||
|
||||
GtkInspector (originally gtkparasite)
|
||||
-------------------------------------
|
||||
|
||||
DirectFB backend
|
||||
----------------
|
||||
Denis Oliver Kropp
|
||||
Sven Neumann
|
||||
Mike Emmel
|
||||
|
||||
|
||||
gtkparasite
|
||||
-----------
|
||||
Christian Hammond
|
||||
|
@@ -21,7 +21,7 @@ many things that we value:
|
||||
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` [room on matrix](https://matrix.to/#/#gtk:gnome.org)
|
||||
- the `#gtk` IRC channel on irc.gnome.org
|
||||
- the [gtk tag on the GNOME Discourse instance](https://discourse.gnome.org/tag/gtk)
|
||||
|
||||
You can also look at the GTK tag on [Stack
|
||||
@@ -35,7 +35,8 @@ The issue tracker is meant to be used for actionable issues only.
|
||||
|
||||
You should not open a new issue for security related questions.
|
||||
|
||||
When in doubt, follow the process for [GNOME security issues](https://security.gnome.org/).
|
||||
When in doubt, send an email to the [security](mailto:security@gnome.org)
|
||||
mailing list.
|
||||
|
||||
### Bug reports
|
||||
|
||||
@@ -43,7 +44,6 @@ If you're reporting a bug make sure to list:
|
||||
|
||||
0. which version of GTK are you using?
|
||||
0. which operating system are you using?
|
||||
0. what display and graphics driver are you using?
|
||||
0. the necessary steps to reproduce the issue
|
||||
0. the expected outcome
|
||||
0. a description of the behavior; screenshots are also welcome
|
||||
@@ -144,28 +144,33 @@ $ git clone https://gitlab.gnome.org/yourusername/gtk.git
|
||||
$ cd gtk
|
||||
```
|
||||
|
||||
**Note**: if you plan to push changes to back to the main repository and
|
||||
have a GNOME account, you can skip the fork, and use the following instead:
|
||||
|
||||
```sh
|
||||
$ git clone git@gitlab.gnome.org:GNOME/gtk.git
|
||||
$ cd gtk
|
||||
```
|
||||
|
||||
To compile the Git version of GTK on your system, you will need to
|
||||
configure your build using Meson:
|
||||
|
||||
```sh
|
||||
$ meson setup _builddir .
|
||||
$ meson compile -C _builddir
|
||||
$ meson _builddir .
|
||||
$ cd _builddir
|
||||
$ ninja
|
||||
```
|
||||
|
||||
Typically, you should work on your own branch:
|
||||
|
||||
```sh
|
||||
$ git switch -C your-branch
|
||||
$ git checkout -b your-branch
|
||||
```
|
||||
|
||||
Once you've finished working on the bug fix or feature, push the branch
|
||||
to the Git repository and open a new merge request, to let the GTK
|
||||
maintainers review your contribution.
|
||||
|
||||
**Important**: Do **not** attach a diff or a patch file to a GitLab issue.
|
||||
Patches cannot be reviewed, and do not not go through the CI pipeline. If
|
||||
you wish to submit your changes to GTK, always use a merge request.
|
||||
|
||||
### Code reviews
|
||||
|
||||
Each contribution is reviewed by the core developers of the GTK project.
|
||||
@@ -208,7 +213,7 @@ Closes #1234
|
||||
`git commit -a --author "Joe Coder <joe@coder.org>"` and `--signoff`.
|
||||
|
||||
- If your commit is addressing an issue, use the
|
||||
[GitLab syntax](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
|
||||
[GitLab syntax](https://docs.gitlab.com/ce/user/project/issues/automatic_issue_closing.html)
|
||||
to automatically close the issue when merging the commit with the upstream
|
||||
repository:
|
||||
|
||||
@@ -238,11 +243,13 @@ people committing to GTK to follow a few rules:
|
||||
code, you should always ask. If your change is minor and you've been
|
||||
working on GTK for a while it probably isn't necessary to ask. But when
|
||||
in doubt, ask. Even if your change is correct, somebody may know a
|
||||
better way to do things.
|
||||
The `gtk` [room on matrix](https://matrix.to/#/#gtk:gnome.org) is also a
|
||||
good place to find GTK developers to discuss changes, but if you live
|
||||
outside of the EU/US time zones, the [gtk tag on the GNOME Discourse instance](https://discourse.gnome.org/tag/gtk)
|
||||
is the most certain and preferred method.
|
||||
better way to do things. If you are making changes to GTK, you should
|
||||
be subscribed to the [gtk-devel](https://mail.gnome.org/mailman/listinfo/gtk-devel-list)
|
||||
mailing list; this is a good place to ask about intended changes.
|
||||
The `#gtk` IRC channel on irc.gnome.org is also a good place to find GTK
|
||||
developers to discuss changes, but if you live outside of the EU/US time
|
||||
zones, an email to the gtk-devel mailing list is the most certain and
|
||||
preferred method.
|
||||
|
||||
0. Ask _first_.
|
||||
|
||||
@@ -257,4 +264,4 @@ people committing to GTK to follow a few rules:
|
||||
|
||||
If you have been contributing to GTK for a while and you don't have commit
|
||||
access to the repository, you may ask to obtain it following the [GNOME account
|
||||
process](https://handbook.gnome.org/infrastructure/developer-access.html).
|
||||
process](https://wiki.gnome.org/AccountsTeam/NewAccounts).
|
||||
|
42
README.md
@@ -67,13 +67,6 @@ building for:
|
||||
- [Graphene](https://github.com/ebassi/graphene)
|
||||
- [Xkb-common](https://github.com/xkbcommon/libxkbcommon)
|
||||
|
||||
If you are building the Wayland backend, you will also need:
|
||||
|
||||
- Wayland-client
|
||||
- Wayland-protocols
|
||||
- Wayland-cursor
|
||||
- Wayland-EGL
|
||||
|
||||
If you are building the X11 backend, you will also need:
|
||||
|
||||
- Xlib, and the following X extensions:
|
||||
@@ -86,24 +79,32 @@ If you are building the X11 backend, you will also need:
|
||||
- xdamage
|
||||
- xcomposite
|
||||
|
||||
If you are building the Wayland backend, you will also need:
|
||||
|
||||
- Wayland-client
|
||||
- Wayland-protocols
|
||||
- Wayland-cursor
|
||||
- Wayland-EGL
|
||||
|
||||
Once you have all the necessary dependencies, you can build GTK by using
|
||||
Meson:
|
||||
|
||||
```sh
|
||||
$ meson setup _build
|
||||
$ meson compile -C_build
|
||||
$ meson _build .
|
||||
$ cd _build
|
||||
$ ninja
|
||||
```
|
||||
|
||||
You can run the test suite using:
|
||||
|
||||
```sh
|
||||
$ meson test -C_build
|
||||
$ meson test
|
||||
```
|
||||
|
||||
And, finally, you can install GTK using:
|
||||
|
||||
```
|
||||
$ sudo meson install -C_build
|
||||
$ sudo ninja install
|
||||
```
|
||||
|
||||
Complete information about installing GTK and related libraries
|
||||
@@ -115,17 +116,24 @@ docs/reference/gtk/html/gtk-building.html
|
||||
|
||||
Or [online](https://docs.gtk.org/gtk4/building.html)
|
||||
|
||||
Building from git
|
||||
-----------------
|
||||
Default branch renamed to `main`
|
||||
--------------------------------
|
||||
|
||||
The GTK sources are hosted on [gitlab.gnome.org](http://gitlab.gnome.org). The main
|
||||
development branch is called `main`, and stable branches are named after their minor
|
||||
version, for example `gtk-4-10`.
|
||||
The default development branch of GTK has been renamed to `main`.
|
||||
To update your local checkout, use:
|
||||
```sh
|
||||
git checkout master
|
||||
git branch -m master main
|
||||
git fetch
|
||||
git branch --unset-upstream
|
||||
git branch -u origin/main
|
||||
git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main
|
||||
```
|
||||
|
||||
How to report bugs
|
||||
------------------
|
||||
|
||||
Bugs should be reported on the [issues page](https://gitlab.gnome.org/GNOME/gtk/issues/).
|
||||
Bugs should be reported on the [issues page](https://gitlab.gnome.org/GNOME/gtk/issues/new).
|
||||
|
||||
In the bug report please include:
|
||||
|
||||
|
@@ -54,7 +54,8 @@
|
||||
"builddir" : true,
|
||||
"config-opts" : [
|
||||
"--libdir=/app/lib",
|
||||
"-Dtests=false"
|
||||
"-Dtests=false",
|
||||
"-Dbenchmarks=false"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
@@ -104,8 +105,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.bz2",
|
||||
"sha256": "475d589d51a7f8b3ba2ba4eda022b170e562ca3b760ee922c146b6c65856ef39"
|
||||
"url": "https://boostorg.jfrog.io/artifactory/main/release/1.69.0/source/boost_1_69_0.tar.bz2",
|
||||
"sha256": "8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -185,6 +186,7 @@
|
||||
"builddir" : true,
|
||||
"config-opts" : [
|
||||
"--libdir=/app/lib",
|
||||
"-Denable_vulkan=no",
|
||||
"-Dbuildtype=debugoptimized",
|
||||
"-Dprofile=devel"
|
||||
],
|
||||
|
@@ -54,7 +54,8 @@
|
||||
"builddir" : true,
|
||||
"config-opts" : [
|
||||
"--libdir=/app/lib",
|
||||
"-Dtests=false"
|
||||
"-Dtests=false",
|
||||
"-Dbenchmarks=false"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
@@ -114,6 +115,7 @@
|
||||
"builddir" : true,
|
||||
"config-opts" : [
|
||||
"--libdir=/app/lib",
|
||||
"-Denable_vulkan=no",
|
||||
"-Dbuildtype=debugoptimized",
|
||||
"-Dprofile=devel"
|
||||
],
|
||||
|
@@ -54,7 +54,8 @@
|
||||
"builddir" : true,
|
||||
"config-opts" : [
|
||||
"--libdir=/app/lib",
|
||||
"-Dtests=false"
|
||||
"-Dtests=false",
|
||||
"-Dbenchmarks=false"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
@@ -114,6 +115,7 @@
|
||||
"builddir" : true,
|
||||
"config-opts" : [
|
||||
"--libdir=/app/lib",
|
||||
"-Denable_vulkan=no",
|
||||
"-Dbuildtype=debugoptimized",
|
||||
"-Dprofile=devel"
|
||||
],
|
||||
@@ -130,6 +132,7 @@
|
||||
"env" : {
|
||||
"DBUS_SESSION_BUS_ADDRESS" : "''",
|
||||
"GSK_RENDERER" : "opengl",
|
||||
"GDK_DEBUG" : "vulkan-disable",
|
||||
"G_ENABLE_DEBUG" : "true"
|
||||
}
|
||||
}
|
||||
|
@@ -1,136 +0,0 @@
|
||||
{
|
||||
"app-id" : "org.gtk.gtk4.NodeEditor",
|
||||
"runtime" : "org.gnome.Platform",
|
||||
"runtime-version" : "master",
|
||||
"sdk" : "org.gnome.Sdk",
|
||||
"command" : "gtk4-node-editor",
|
||||
"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" : "meson",
|
||||
"builddir" : true,
|
||||
"config-opts" : [
|
||||
"-Ddocumentation=false"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.freedesktop.org/wayland/wayland.git",
|
||||
"branch" : "main"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "graphene",
|
||||
"buildsystem" : "meson",
|
||||
"builddir" : true,
|
||||
"config-opts" : [
|
||||
"--libdir=/app/lib",
|
||||
"-Dtests=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" : "pango",
|
||||
"buildsystem" : "meson",
|
||||
"builddir" : true,
|
||||
"config-opts" : [
|
||||
"--libdir=/app/lib"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.gnome.org/GNOME/pango.git",
|
||||
"branch" : "main"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "gtk",
|
||||
"buildsystem" : "meson",
|
||||
"builddir" : true,
|
||||
"config-opts" : [
|
||||
"--libdir=/app/lib",
|
||||
"-Dbuildtype=debugoptimized",
|
||||
"-Dprofile=devel"
|
||||
],
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "https://gitlab.gnome.org/GNOME/gtk.git",
|
||||
"branch" : "main"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"build-options" : {
|
||||
"env" : {
|
||||
"DBUS_SESSION_BUS_ADDRESS" : "''",
|
||||
"GSK_RENDERER" : "opengl",
|
||||
"G_ENABLE_DEBUG" : "true"
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,201 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2022 Collabora Inc.
|
||||
# 2023 Emmanuele Bassi
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
#
|
||||
# Original author: Xavier Claessens <xclaesse@gmail.com>
|
||||
|
||||
import argparse
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
# Disable line length warnings as wrapping the C code templates would be hard
|
||||
# flake8: noqa: E501
|
||||
|
||||
|
||||
def gen_versions_macros(args, current_major_version, current_minor_version, current_micro_version):
|
||||
with args.out_path.open("w", encoding="utf-8") as ofile, args.in_path.open(
|
||||
"r", encoding="utf-8"
|
||||
) as ifile:
|
||||
for line in ifile.readlines():
|
||||
if "@GDK_VERSIONS@" in line:
|
||||
ofile.write(
|
||||
textwrap.dedent(
|
||||
f"""\
|
||||
/**
|
||||
* GDK_MAJOR_VERSION:
|
||||
*
|
||||
* The major version component of the library's version, e.g. "1" for "1.2.3".
|
||||
*/
|
||||
#define GDK_MAJOR_VERSION ({current_major_version})
|
||||
|
||||
/**
|
||||
* GDK_MINOR_VERSION:
|
||||
*
|
||||
* The minor version component of the library's version, e.g. "2" for "1.2.3".
|
||||
*/
|
||||
#define GDK_MINOR_VERSION ({current_minor_version})
|
||||
|
||||
/**
|
||||
* GDK_MICRO_VERSION:
|
||||
*
|
||||
* The micro version component of the library's version, e.g. "3" for "1.2.3".
|
||||
*/
|
||||
#define GDK_MICRO_VERSION ({current_micro_version})
|
||||
"""
|
||||
)
|
||||
)
|
||||
for minor in range(0, current_minor_version + 2, 2):
|
||||
ofile.write(
|
||||
textwrap.dedent(
|
||||
f"""\
|
||||
/**
|
||||
* GDK_VERSION_{current_major_version}_{minor}:
|
||||
*
|
||||
* A macro that evaluates to the {current_major_version}.{minor} version of GTK, in a format
|
||||
* that can be used by the C pre-processor.
|
||||
*
|
||||
* Since: {current_major_version}.{minor}
|
||||
*/
|
||||
#define GDK_VERSION_{current_major_version}_{minor} (G_ENCODE_VERSION ({current_major_version}, {minor}))
|
||||
"""
|
||||
)
|
||||
)
|
||||
else:
|
||||
ofile.write(line)
|
||||
|
||||
|
||||
def gen_visibility_macros(args, current_major_version, current_minor_version, current_micro_version):
|
||||
"""
|
||||
Generates a set of macros for each minor stable version of GTK
|
||||
|
||||
- GDK_DEPRECATED
|
||||
- GDK_DEPRECATED_IN_…
|
||||
- GDK_DEPRECATED_MACRO_IN_…
|
||||
- GDK_DEPRECATED_ENUMERATOR_IN_…
|
||||
- GDK_DEPRECATED_TYPE_IN_…
|
||||
|
||||
- GDK_AVAILABLE_IN_ALL
|
||||
- GDK_AVAILABLE_IN_…
|
||||
- GDK_AVAILABLE_STATIC_INLINE_IN_…
|
||||
- GDK_AVAILABLE_MACRO_IN_…
|
||||
- GDK_AVAILABLE_ENUMERATOR_IN_…
|
||||
- GDK_AVAILABLE_TYPE_IN_…
|
||||
|
||||
- GDK_UNAVAILABLE(maj,min)
|
||||
- GDK_UNAVAILABLE_STATIC_INLINE(maj,min)
|
||||
"""
|
||||
|
||||
ns = args.namespace
|
||||
with args.out_path.open("w", encoding="utf-8") as f:
|
||||
f.write(
|
||||
textwrap.dedent(
|
||||
f"""\
|
||||
#pragma once
|
||||
|
||||
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined({ns}_STATIC_COMPILATION)
|
||||
# define _{ns}_EXPORT __declspec(dllexport)
|
||||
# define _{ns}_IMPORT __declspec(dllimport)
|
||||
#elif __GNUC__ >= 4
|
||||
# define _{ns}_EXPORT __attribute__((visibility("default")))
|
||||
# define _{ns}_IMPORT
|
||||
#else
|
||||
# define _{ns}_EXPORT
|
||||
# define _{ns}_IMPORT
|
||||
#endif
|
||||
#ifdef GTK_COMPILATION
|
||||
# define _{ns}_API _{ns}_EXPORT
|
||||
#else
|
||||
# define _{ns}_API _{ns}_IMPORT
|
||||
#endif
|
||||
|
||||
#define _{ns}_EXTERN _{ns}_API extern
|
||||
|
||||
#define {ns}_VAR _{ns}_EXTERN
|
||||
#define {ns}_AVAILABLE_IN_ALL _{ns}_EXTERN
|
||||
|
||||
#ifdef GDK_DISABLE_DEPRECATION_WARNINGS
|
||||
#define {ns}_DEPRECATED _{ns}_EXTERN
|
||||
#define {ns}_DEPRECATED_FOR(f) _{ns}_EXTERN
|
||||
#define {ns}_UNAVAILABLE(maj,min) _{ns}_EXTERN
|
||||
#define {ns}_UNAVAILABLE_STATIC_INLINE(maj,min)
|
||||
#else
|
||||
#define {ns}_DEPRECATED G_DEPRECATED _{ns}_EXTERN
|
||||
#define {ns}_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) _{ns}_EXTERN
|
||||
#define {ns}_UNAVAILABLE(maj,min) G_UNAVAILABLE(maj,min) _{ns}_EXTERN
|
||||
#define {ns}_UNAVAILABLE_STATIC_INLINE(maj,min) G_UNAVAILABLE(maj,min)
|
||||
#endif
|
||||
"""
|
||||
)
|
||||
)
|
||||
for minor in range(0, current_minor_version + 2, 2):
|
||||
f.write(
|
||||
textwrap.dedent(
|
||||
f"""
|
||||
#if GDK_VERSION_MIN_REQUIRED >= GDK_VERSION_4_{minor}
|
||||
#define {ns}_DEPRECATED_IN_{current_major_version}_{minor} {ns}_DEPRECATED
|
||||
#define {ns}_DEPRECATED_IN_{current_major_version}_{minor}_FOR(f) {ns}_DEPRECATED_FOR (f)
|
||||
#define {ns}_DEPRECATED_MACRO_IN_{current_major_version}_{minor} GDK_DEPRECATED_MACRO
|
||||
#define {ns}_DEPRECATED_MACRO_IN_{current_major_version}_{minor}_FOR(f) GDK_DEPRECATED_MACRO_FOR (f)
|
||||
#define {ns}_DEPRECATED_ENUMERATOR_IN_{current_major_version}_{minor} GDK_DEPRECATED_ENUMERATOR
|
||||
#define {ns}_DEPRECATED_ENUMERATOR_IN_{current_major_version}_{minor}_FOR(f) GDK_DEPRECATED_ENUMERATOR_FOR (f)
|
||||
#define {ns}_DEPRECATED_TYPE_IN_{current_major_version}_{minor} GDK_DEPRECATED_TYPE
|
||||
#define {ns}_DEPRECATED_TYPE_IN_{current_major_version}_{minor}_FOR(f) GDK_DEPRECATED_TYPE_FOR (f)
|
||||
#else
|
||||
#define {ns}_DEPRECATED_IN_{current_major_version}_{minor} _{ns}_EXTERN
|
||||
#define {ns}_DEPRECATED_IN_{current_major_version}_{minor}_FOR(f) _{ns}_EXTERN
|
||||
#define {ns}_DEPRECATED_MACRO_IN_{current_major_version}_{minor}
|
||||
#define {ns}_DEPRECATED_MACRO_IN_{current_major_version}_{minor}_FOR(f)
|
||||
#define {ns}_DEPRECATED_ENUMERATOR_IN_{current_major_version}_{minor}
|
||||
#define {ns}_DEPRECATED_ENUMERATOR_IN_{current_major_version}_{minor}_FOR(f)
|
||||
#define {ns}_DEPRECATED_TYPE_IN_{current_major_version}_{minor}
|
||||
#define {ns}_DEPRECATED_TYPE_IN_{current_major_version}_{minor}_FOR(f)
|
||||
#endif
|
||||
|
||||
#if GDK_VERSION_MAX_ALLOWED < GDK_VERSION_{current_major_version}_{minor}
|
||||
#define {ns}_AVAILABLE_IN_{current_major_version}_{minor} {ns}_UNAVAILABLE ({current_major_version}, {minor})
|
||||
#define {ns}_AVAILABLE_STATIC_INLINE_IN_{current_major_version}_{minor} GDK_UNAVAILABLE_STATIC_INLINE ({current_major_version}, {minor})
|
||||
#define {ns}_AVAILABLE_MACRO_IN_{current_major_version}_{minor} GDK_UNAVAILABLE_MACRO ({current_major_version}, {minor})
|
||||
#define {ns}_AVAILABLE_ENUMERATOR_IN_{current_major_version}_{minor} GDK_UNAVAILABLE_ENUMERATOR ({current_major_version}, {minor})
|
||||
#define {ns}_AVAILABLE_TYPE_IN_{current_major_version}_{minor} GDK_UNAVAILABLE_TYPE ({current_major_version}, {minor})
|
||||
#else
|
||||
#define {ns}_AVAILABLE_IN_{current_major_version}_{minor} _{ns}_EXTERN
|
||||
#define {ns}_AVAILABLE_STATIC_INLINE_IN_{current_major_version}_{minor}
|
||||
#define {ns}_AVAILABLE_MACRO_IN_{current_major_version}_{minor}
|
||||
#define {ns}_AVAILABLE_ENUMERATOR_IN_{current_major_version}_{minor}
|
||||
#define {ns}_AVAILABLE_TYPE_IN_{current_major_version}_{minor}
|
||||
#endif
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("gtk_version", help="Current GLib version")
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
versions_parser = subparsers.add_parser(
|
||||
"versions-macros", help="Generate versions macros"
|
||||
)
|
||||
versions_parser.add_argument("in_path", help="input file", type=Path)
|
||||
versions_parser.add_argument("out_path", help="output file", type=Path)
|
||||
versions_parser.set_defaults(func=gen_versions_macros)
|
||||
|
||||
visibility_parser = subparsers.add_parser(
|
||||
"visibility-macros", help="Generate visibility macros"
|
||||
)
|
||||
visibility_parser.add_argument("namespace", help="Macro namespace")
|
||||
visibility_parser.add_argument("out_path", help="output file", type=Path)
|
||||
visibility_parser.set_defaults(func=gen_visibility_macros)
|
||||
|
||||
args = parser.parse_args()
|
||||
version = [int(i) for i in args.gtk_version.split(".")]
|
||||
args.func(args, version[0], version[1], version[2])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
45
build-aux/meson/post-install.py
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
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_bindir = sys.argv[5]
|
||||
|
||||
gtk_moduledir = os.path.join(gtk_libdir, 'gtk-' + gtk_api_version, gtk_abi_version)
|
||||
gtk_printmodule_dir = os.path.join(gtk_moduledir, 'printbackends')
|
||||
gtk_mediamodule_dir = os.path.join(gtk_moduledir, 'media')
|
||||
|
||||
print('Compiling GSettings schemas...')
|
||||
glib_compile_schemas = subprocess.check_output(['pkg-config',
|
||||
'--variable=glib_compile_schemas',
|
||||
'gio-2.0']).strip()
|
||||
if not os.path.exists(glib_compile_schemas):
|
||||
# pkg-config variables only available since GLib 2.62.0.
|
||||
glib_compile_schemas = 'glib-compile-schemas'
|
||||
subprocess.call([glib_compile_schemas,
|
||||
os.path.join(gtk_datadir, 'glib-2.0', 'schemas')])
|
||||
|
||||
print('Updating icon cache...')
|
||||
update_icon_cache = os.path.join(gtk_bindir, 'gtk4-update-icon-cache')
|
||||
subprocess.call([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)
|
||||
gio_querymodules = subprocess.check_output(['pkg-config',
|
||||
'--variable=gio_querymodules',
|
||||
'gio-2.0']).strip()
|
||||
if not os.path.exists(gio_querymodules):
|
||||
# pkg-config variables only available since GLib 2.62.0.
|
||||
gio_querymodules = 'gio-querymodules'
|
||||
subprocess.call([gio_querymodules, gtk_printmodule_dir])
|
||||
|
||||
print('Updating module cache for media backends...')
|
||||
os.makedirs(gtk_mediamodule_dir, exist_ok=True)
|
||||
subprocess.call([gio_querymodules, gtk_mediamodule_dir])
|
@@ -1,41 +0,0 @@
|
||||
#ifndef _MSC_VER
|
||||
#pragma error "This header is for Microsoft VC or clang-cl only."
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
/* Make MSVC more pedantic, this is a recommended pragma list
|
||||
* from _Win32_Programming_ by Rector and Newcomer.
|
||||
*/
|
||||
#ifndef __clang__
|
||||
#pragma warning(error:4002) /* too many actual parameters for macro */
|
||||
#pragma warning(error:4003) /* not enough actual parameters for macro */
|
||||
#pragma warning(1:4010) /* single-line comment contains line-continuation character */
|
||||
#pragma warning(error:4013) /* 'function' undefined; assuming extern returning int */
|
||||
#pragma warning(1:4016) /* no function return type; using int as default */
|
||||
#pragma warning(error:4020) /* too many actual parameters */
|
||||
#pragma warning(error:4021) /* too few actual parameters */
|
||||
#pragma warning(error:4027) /* function declared without formal parameter list */
|
||||
#pragma warning(error:4029) /* declared formal parameter list different from definition */
|
||||
#pragma warning(error:4033) /* 'function' must return a value */
|
||||
#pragma warning(error:4035) /* 'function' : no return value */
|
||||
#pragma warning(error:4045) /* array bounds overflow */
|
||||
#pragma warning(error:4047) /* different levels of indirection */
|
||||
#pragma warning(error:4049) /* terminating line number emission */
|
||||
#pragma warning(error:4053) /* An expression of type void was used as an operand */
|
||||
#pragma warning(error:4071) /* no function prototype given */
|
||||
#pragma warning(disable:4101) /* unreferenced local variable */
|
||||
#pragma warning(error:4150)
|
||||
|
||||
/* G_NORETURN */
|
||||
#pragma warning(error:4646) /* function declared with __declspec(noreturn) has non-void return type */
|
||||
#pragma warning(error:4715) /* 'function': not all control paths return a value */
|
||||
#pragma warning(error:4098) /* 'void' function returning a value */
|
||||
|
||||
#pragma warning(disable:4244) /* No possible loss of data warnings */
|
||||
#pragma warning(disable:4305) /* No truncation from int to char warnings */
|
||||
|
||||
#pragma warning(error:4819) /* The file contains a character that cannot be represented in the current code page */
|
||||
#endif /* __clang__ */
|
||||
|
||||
/* work around Microsoft's premature attempt to deprecate the C-Library */
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_NONSTDC_NO_WARNINGS
|
@@ -202,36 +202,43 @@ constraint_editor_window_load (ConstraintEditorWindow *self,
|
||||
}
|
||||
|
||||
static void
|
||||
open_response_cb (GObject *source,
|
||||
GAsyncResult *result,
|
||||
void *user_data)
|
||||
open_response_cb (GtkNativeDialog *dialog,
|
||||
int response,
|
||||
ConstraintEditorWindow *self)
|
||||
{
|
||||
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
|
||||
ConstraintEditorWindow *self = user_data;
|
||||
GFile *file;
|
||||
gtk_native_dialog_hide (dialog);
|
||||
|
||||
file = gtk_file_dialog_open_finish (dialog, result, NULL);
|
||||
if (file)
|
||||
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)
|
||||
{
|
||||
GtkFileDialog *dialog;
|
||||
GFile *cwd;
|
||||
GtkFileChooserNative *dialog;
|
||||
|
||||
dialog = gtk_file_dialog_new ();
|
||||
gtk_file_dialog_set_title (dialog, "Open file");
|
||||
cwd = g_file_new_for_path (".");
|
||||
gtk_file_dialog_set_initial_folder (dialog, cwd);
|
||||
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);
|
||||
gtk_file_dialog_open (dialog, GTK_WINDOW (self), NULL, open_response_cb, self);
|
||||
g_object_unref (dialog);
|
||||
|
||||
g_signal_connect (dialog, "response", G_CALLBACK (open_response_cb), self);
|
||||
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -287,23 +294,22 @@ serialize_model (GListModel *list)
|
||||
|
||||
|
||||
static void
|
||||
save_response_cb (GObject *source,
|
||||
GAsyncResult *result,
|
||||
void *user_data)
|
||||
save_response_cb (GtkNativeDialog *dialog,
|
||||
int response,
|
||||
ConstraintEditorWindow *self)
|
||||
{
|
||||
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
|
||||
ConstraintEditorWindow *self = user_data;
|
||||
GFile *file;
|
||||
gtk_native_dialog_hide (dialog);
|
||||
|
||||
file = gtk_file_dialog_save_finish (dialog, result, NULL);
|
||||
if (file)
|
||||
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, strlen (text),
|
||||
NULL, FALSE,
|
||||
G_FILE_CREATE_NONE,
|
||||
@@ -312,46 +318,54 @@ save_response_cb (GObject *source,
|
||||
&error);
|
||||
if (error != NULL)
|
||||
{
|
||||
GtkAlertDialog *alert;
|
||||
GtkWidget *message_dialog;
|
||||
|
||||
alert = gtk_alert_dialog_new ("Saving failed");
|
||||
gtk_alert_dialog_set_detail (alert, error->message);
|
||||
gtk_alert_dialog_show (alert,
|
||||
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))));
|
||||
g_object_unref (alert);
|
||||
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)
|
||||
{
|
||||
GtkFileDialog *dialog;
|
||||
GFile *cwd;
|
||||
GtkFileChooserNative *dialog;
|
||||
|
||||
dialog = gtk_file_dialog_new ();
|
||||
gtk_file_dialog_set_title (dialog, "Save constraints");
|
||||
cwd = g_file_new_for_path (".");
|
||||
gtk_file_dialog_set_initial_folder (dialog, cwd);
|
||||
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);
|
||||
gtk_file_dialog_save (dialog,
|
||||
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (button))),
|
||||
NULL,
|
||||
save_response_cb, self);
|
||||
g_object_unref (dialog);
|
||||
|
||||
g_signal_connect (dialog, "response", G_CALLBACK (save_response_cb), self);
|
||||
gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog));
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_editor_window_dispose (GObject *object)
|
||||
constraint_editor_window_finalize (GObject *object)
|
||||
{
|
||||
gtk_widget_dispose_template (GTK_WIDGET (object), CONSTRAINT_EDITOR_WINDOW_TYPE);
|
||||
//ConstraintEditorWindow *self = (ConstraintEditorWindow *)object;
|
||||
|
||||
G_OBJECT_CLASS (constraint_editor_window_parent_class)->dispose (object);
|
||||
G_OBJECT_CLASS (constraint_editor_window_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static int child_counter;
|
||||
@@ -426,7 +440,7 @@ edit_constraint (ConstraintEditorWindow *win,
|
||||
|
||||
g_signal_connect (editor, "done", G_CALLBACK (constraint_editor_done), win);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
gtk_widget_show (window);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -459,7 +473,7 @@ edit_guide (ConstraintEditorWindow *win,
|
||||
gtk_window_set_child (GTK_WINDOW (window), GTK_WIDGET (editor));
|
||||
|
||||
g_signal_connect (editor, "done", G_CALLBACK (guide_editor_done), win);
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
gtk_widget_show (window);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -483,9 +497,7 @@ constraint_editor_window_class_init (ConstraintEditorWindowClass *class)
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
g_type_ensure (CONSTRAINT_VIEW_TYPE);
|
||||
|
||||
object_class->dispose = constraint_editor_window_dispose;
|
||||
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");
|
||||
|
@@ -20,7 +20,6 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "constraint-editor.h"
|
||||
#include "constraint-view.h"
|
||||
|
||||
struct _ConstraintEditor
|
||||
{
|
||||
@@ -65,7 +64,7 @@ static const char *
|
||||
get_target_name (GtkConstraintTarget *target)
|
||||
{
|
||||
if (target == NULL)
|
||||
return "Super";
|
||||
return "super";
|
||||
else if (GTK_IS_WIDGET (target))
|
||||
return gtk_widget_get_name (GTK_WIDGET (target));
|
||||
else if (GTK_IS_CONSTRAINT_GUIDE (target))
|
||||
@@ -79,29 +78,62 @@ constraint_target_combo (GListModel *model,
|
||||
GtkWidget *combo,
|
||||
gboolean is_source)
|
||||
{
|
||||
GtkStringList *targets;
|
||||
int i;
|
||||
|
||||
targets = gtk_string_list_new (NULL);
|
||||
|
||||
gtk_string_list_append (targets, "Super");
|
||||
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;
|
||||
|
||||
gtk_string_list_append (targets, get_target_name (GTK_CONSTRAINT_TARGET (item)));
|
||||
name = get_target_name (GTK_CONSTRAINT_TARGET (item));
|
||||
|
||||
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), name, name);
|
||||
g_object_unref (item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gtk_drop_down_set_model (GTK_DROP_DOWN (combo), G_LIST_MODEL (targets));
|
||||
g_object_unref (targets);
|
||||
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
|
||||
@@ -113,7 +145,7 @@ get_target (GListModel *model,
|
||||
if (id == NULL)
|
||||
return NULL;
|
||||
|
||||
if (strcmp ("Super", id) == 0)
|
||||
if (strcmp ("super", id) == 0)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < g_list_model_get_n_items (model); i++)
|
||||
@@ -137,65 +169,16 @@ get_target (GListModel *model,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
select_target (GtkDropDown *combo,
|
||||
const char *target_name)
|
||||
{
|
||||
GListModel *model = gtk_drop_down_get_model (combo);
|
||||
|
||||
for (unsigned int i = 0; i < g_list_model_get_n_items (model); i++)
|
||||
{
|
||||
GtkStringObject *s = g_list_model_get_item (model, i);
|
||||
|
||||
g_object_unref (s);
|
||||
if (strcmp (target_name, gtk_string_object_get_string (s)) == 0)
|
||||
{
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (combo), i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GtkConstraintAttribute
|
||||
get_attr (unsigned int id)
|
||||
get_target_attr (const char *id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0: return GTK_CONSTRAINT_ATTRIBUTE_NONE;
|
||||
case 1: return GTK_CONSTRAINT_ATTRIBUTE_LEFT;
|
||||
case 2: return GTK_CONSTRAINT_ATTRIBUTE_RIGHT;
|
||||
case 3: return GTK_CONSTRAINT_ATTRIBUTE_TOP;
|
||||
case 4: return GTK_CONSTRAINT_ATTRIBUTE_BOTTOM;
|
||||
case 5: return GTK_CONSTRAINT_ATTRIBUTE_START;
|
||||
case 6: return GTK_CONSTRAINT_ATTRIBUTE_END;
|
||||
case 7: return GTK_CONSTRAINT_ATTRIBUTE_WIDTH;
|
||||
case 8: return GTK_CONSTRAINT_ATTRIBUTE_HEIGHT;
|
||||
case 9: return GTK_CONSTRAINT_ATTRIBUTE_CENTER_X;
|
||||
case 10: return GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y;
|
||||
case 11: return GTK_CONSTRAINT_ATTRIBUTE_BASELINE;
|
||||
default: g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
static unsigned int
|
||||
get_attr_id (GtkConstraintAttribute attr)
|
||||
{
|
||||
switch (attr)
|
||||
{
|
||||
case GTK_CONSTRAINT_ATTRIBUTE_NONE: return 0;
|
||||
case GTK_CONSTRAINT_ATTRIBUTE_LEFT: return 1;
|
||||
case GTK_CONSTRAINT_ATTRIBUTE_RIGHT: return 2;
|
||||
case GTK_CONSTRAINT_ATTRIBUTE_TOP: return 3;
|
||||
case GTK_CONSTRAINT_ATTRIBUTE_BOTTOM: return 4;
|
||||
case GTK_CONSTRAINT_ATTRIBUTE_START: return 5;
|
||||
case GTK_CONSTRAINT_ATTRIBUTE_END: return 6;
|
||||
case GTK_CONSTRAINT_ATTRIBUTE_WIDTH: return 7;
|
||||
case GTK_CONSTRAINT_ATTRIBUTE_HEIGHT: return 8;
|
||||
case GTK_CONSTRAINT_ATTRIBUTE_CENTER_X: return 9;
|
||||
case GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y: return 10;
|
||||
case GTK_CONSTRAINT_ATTRIBUTE_BASELINE: return 11;
|
||||
default: g_assert_not_reached ();
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
|
||||
static const char *
|
||||
@@ -210,27 +193,15 @@ get_attr_nick (GtkConstraintAttribute attr)
|
||||
}
|
||||
|
||||
static GtkConstraintRelation
|
||||
get_relation (unsigned int id)
|
||||
get_relation (const char *id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0: return GTK_CONSTRAINT_RELATION_LE;
|
||||
case 1: return GTK_CONSTRAINT_RELATION_EQ;
|
||||
case 2: return GTK_CONSTRAINT_RELATION_GE;
|
||||
default: g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
static unsigned int
|
||||
get_relation_id (GtkConstraintRelation relation)
|
||||
{
|
||||
switch (relation)
|
||||
{
|
||||
case GTK_CONSTRAINT_RELATION_LE: return 0;
|
||||
case GTK_CONSTRAINT_RELATION_EQ: return 1;
|
||||
case GTK_CONSTRAINT_RELATION_GE: return 2;
|
||||
default: g_assert_not_reached ();
|
||||
}
|
||||
return relation;
|
||||
}
|
||||
|
||||
static const char *
|
||||
@@ -261,29 +232,15 @@ get_relation_display_name (GtkConstraintRelation relation)
|
||||
}
|
||||
|
||||
static GtkConstraintStrength
|
||||
get_strength (unsigned int id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0: return GTK_CONSTRAINT_STRENGTH_WEAK;
|
||||
case 1: return GTK_CONSTRAINT_STRENGTH_MEDIUM;
|
||||
case 2: return GTK_CONSTRAINT_STRENGTH_STRONG;
|
||||
case 3: return GTK_CONSTRAINT_STRENGTH_REQUIRED;
|
||||
default: g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
get_strength_id (GtkConstraintStrength strength)
|
||||
get_strength (const char *id)
|
||||
{
|
||||
switch (strength)
|
||||
{
|
||||
case GTK_CONSTRAINT_STRENGTH_WEAK: return 0;
|
||||
case GTK_CONSTRAINT_STRENGTH_MEDIUM: return 1;
|
||||
case GTK_CONSTRAINT_STRENGTH_STRONG: return 2;
|
||||
case GTK_CONSTRAINT_STRENGTH_REQUIRED: return 3;
|
||||
default: g_assert_not_reached ();
|
||||
}
|
||||
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 *
|
||||
@@ -335,7 +292,7 @@ static void
|
||||
create_constraint (GtkButton *button,
|
||||
ConstraintEditor *editor)
|
||||
{
|
||||
gpointer obj;
|
||||
const char *id;
|
||||
gpointer target;
|
||||
GtkConstraintAttribute target_attr;
|
||||
gpointer source;
|
||||
@@ -346,27 +303,25 @@ create_constraint (GtkButton *button,
|
||||
int strength;
|
||||
GtkConstraint *constraint;
|
||||
|
||||
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->target));
|
||||
if (obj)
|
||||
target = get_target (editor->model, gtk_string_object_get_string (GTK_STRING_OBJECT (obj)));
|
||||
else
|
||||
target = NULL;
|
||||
target_attr = get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->target_attr)));
|
||||
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);
|
||||
|
||||
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->source));
|
||||
if (obj)
|
||||
source = get_target (editor->model, gtk_string_object_get_string (GTK_STRING_OBJECT (obj)));
|
||||
else
|
||||
source = NULL;
|
||||
source_attr = get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN(editor->source_attr)));
|
||||
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);
|
||||
|
||||
relation = get_relation (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->relation)));
|
||||
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);
|
||||
|
||||
strength = get_strength (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->strength)));
|
||||
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
|
||||
strength = get_strength (id);
|
||||
|
||||
constraint = gtk_constraint_new (target, target_attr,
|
||||
relation,
|
||||
@@ -381,9 +336,12 @@ create_constraint (GtkButton *button,
|
||||
static void
|
||||
source_attr_changed (ConstraintEditor *editor)
|
||||
{
|
||||
if (get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->source_attr))) == GTK_CONSTRAINT_ATTRIBUTE_NONE)
|
||||
const char *id;
|
||||
|
||||
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
|
||||
if (strcmp (id, "none") == 0)
|
||||
{
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->source), GTK_INVALID_LIST_POSITION);
|
||||
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);
|
||||
@@ -449,7 +407,7 @@ update_preview (ConstraintEditor *editor)
|
||||
GString *str;
|
||||
const char *name;
|
||||
const char *attr;
|
||||
const char *relation;
|
||||
char *relation;
|
||||
const char *multiplier;
|
||||
const char *constant;
|
||||
double c, m;
|
||||
@@ -459,22 +417,23 @@ update_preview (ConstraintEditor *editor)
|
||||
|
||||
str = g_string_new ("");
|
||||
|
||||
name = gtk_string_object_get_string (GTK_STRING_OBJECT (gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->target))));
|
||||
attr = get_attr_nick (get_attr (gtk_drop_down_get_selected ((GTK_DROP_DOWN (editor->target_attr)))));
|
||||
relation = get_relation_nick (get_relation (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->relation))));
|
||||
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 = get_attr_nick (get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->source_attr))));
|
||||
attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
|
||||
if (strcmp (attr, "none") != 0)
|
||||
{
|
||||
name = gtk_string_object_get_string (GTK_STRING_OBJECT (gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->source))));
|
||||
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);
|
||||
|
||||
@@ -502,18 +461,12 @@ update_preview (ConstraintEditor *editor)
|
||||
static void
|
||||
update_button (ConstraintEditor *editor)
|
||||
{
|
||||
gpointer obj;
|
||||
const char *target;
|
||||
const char *source;
|
||||
GtkConstraintAttribute source_attr = get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->source_attr)));
|
||||
const char *target = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target));
|
||||
const char *source = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source));
|
||||
const char *source_attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr));
|
||||
|
||||
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->target));
|
||||
target = obj ? gtk_string_object_get_string (GTK_STRING_OBJECT (obj)) : NULL;
|
||||
|
||||
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->source));
|
||||
source = obj ? gtk_string_object_get_string (GTK_STRING_OBJECT (obj)) : NULL;
|
||||
|
||||
if (target && (source || (source_attr == GTK_CONSTRAINT_ATTRIBUTE_NONE)))
|
||||
if (target &&
|
||||
(source || (source_attr && get_target_attr (source_attr) == GTK_CONSTRAINT_ATTRIBUTE_NONE)))
|
||||
gtk_widget_set_sensitive (editor->button, TRUE);
|
||||
else
|
||||
gtk_widget_set_sensitive (editor->button, FALSE);
|
||||
@@ -531,7 +484,12 @@ 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)
|
||||
{
|
||||
@@ -539,24 +497,30 @@ constraint_editor_constructed (GObject *object)
|
||||
GtkConstraintAttribute attr;
|
||||
GtkConstraintRelation relation;
|
||||
GtkConstraintStrength strength;
|
||||
const char *nick;
|
||||
char *val;
|
||||
double multiplier;
|
||||
double constant;
|
||||
|
||||
target = gtk_constraint_get_target (editor->constraint);
|
||||
select_target (GTK_DROP_DOWN (editor->target), get_target_name (target));
|
||||
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);
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->target_attr), get_attr_id (attr));
|
||||
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);
|
||||
select_target (GTK_DROP_DOWN (editor->source), get_target_name (target));
|
||||
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);
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->source_attr), get_attr_id (attr));
|
||||
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);
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->relation), get_relation_id (relation));
|
||||
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);
|
||||
@@ -569,16 +533,17 @@ constraint_editor_constructed (GObject *object)
|
||||
g_free (val);
|
||||
|
||||
strength = gtk_constraint_get_strength (editor->constraint);
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (strength));
|
||||
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_drop_down_set_selected (GTK_DROP_DOWN (editor->target_attr), get_attr_id (GTK_CONSTRAINT_ATTRIBUTE_LEFT));
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->source_attr), get_attr_id (GTK_CONSTRAINT_ATTRIBUTE_LEFT));
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->relation), get_relation_id (GTK_CONSTRAINT_RELATION_EQ));
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
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");
|
||||
@@ -642,11 +607,10 @@ 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);
|
||||
|
||||
gtk_widget_dispose_template (GTK_WIDGET (object), CONSTRAINT_EDITOR_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (constraint_editor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
@@ -1,21 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkStringList" id="targets">
|
||||
<items>
|
||||
<item>None</item>
|
||||
<item>Left</item>
|
||||
<item>Right</item>
|
||||
<item>Top</item>
|
||||
<item>Bottom</item>
|
||||
<item>Start</item>
|
||||
<item>End</item>
|
||||
<item>Width</item>
|
||||
<item>Height</item>
|
||||
<item>Center X</item>
|
||||
<item>Center Y</item>
|
||||
<item>Baseline</item>
|
||||
</items>
|
||||
</object>
|
||||
<template class="ConstraintEditor" parent="GtkWidget">
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid">
|
||||
@@ -35,9 +19,9 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDropDown" id="target">
|
||||
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
|
||||
<signal name="notify::selected" handler="update_button" swapped="yes"/>
|
||||
<object class="GtkComboBoxText" id="target">
|
||||
<signal name="changed" handler="update_preview" swapped="yes"/>
|
||||
<signal name="changed" handler="update_button" swapped="yes"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">1</property>
|
||||
@@ -45,9 +29,8 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDropDown" id="target_attr">
|
||||
<property name="model">targets</property>
|
||||
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
|
||||
<object class="GtkComboBoxText" id="target_attr">
|
||||
<signal name="changed" handler="update_preview" swapped="yes"/>
|
||||
<layout>
|
||||
<property name="column">2</property>
|
||||
<property name="row">1</property>
|
||||
@@ -64,17 +47,8 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDropDown" id="relation">
|
||||
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
|
||||
<property name="model">
|
||||
<object class="GtkStringList">
|
||||
<items>
|
||||
<item>≤</item>
|
||||
<item>=</item>
|
||||
<item>≥</item>
|
||||
</items>
|
||||
</object>
|
||||
</property>
|
||||
<object class="GtkComboBoxText" id="relation">
|
||||
<signal name="changed" handler="update_preview" swapped="yes"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">2</property>
|
||||
@@ -91,9 +65,9 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDropDown" id="source">
|
||||
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
|
||||
<signal name="notify::selected" handler="update_button" swapped="yes"/>
|
||||
<object class="GtkComboBoxText" id="source">
|
||||
<signal name="changed" handler="update_preview" swapped="yes"/>
|
||||
<signal name="changed" handler="update_button" swapped="yes"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">3</property>
|
||||
@@ -101,11 +75,10 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDropDown" id="source_attr">
|
||||
<property name="model">targets</property>
|
||||
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
|
||||
<signal name="notify::selected" handler="source_attr_changed" swapped="yes"/>
|
||||
<signal name="notify::selected" handler="update_button" swapped="yes"/>
|
||||
<object class="GtkComboBoxText" id="source_attr">
|
||||
<signal name="changed" handler="update_preview" swapped="yes"/>
|
||||
<signal name="changed" handler="source_attr_changed" swapped="yes"/>
|
||||
<signal name="changed" handler="update_button" swapped="yes"/>
|
||||
<layout>
|
||||
<property name="column">2</property>
|
||||
<property name="row">3</property>
|
||||
@@ -158,17 +131,7 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDropDown" id="strength">
|
||||
<property name="model">
|
||||
<object class="GtkStringList">
|
||||
<items>
|
||||
<item>Weak</item>
|
||||
<item>Medium</item>
|
||||
<item>Strong</item>
|
||||
<item>Required</item>
|
||||
</items>
|
||||
</object>
|
||||
</property>
|
||||
<object class="GtkComboBoxText" id="strength">
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">6</property>
|
||||
|
@@ -57,30 +57,25 @@ static guint signals[LAST_SIGNAL];
|
||||
|
||||
G_DEFINE_TYPE(GuideEditor, guide_editor, GTK_TYPE_WIDGET);
|
||||
|
||||
static GtkConstraintStrength
|
||||
get_strength (unsigned int id)
|
||||
static void
|
||||
guide_strength_combo (GtkWidget *combo)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case 0: return GTK_CONSTRAINT_STRENGTH_WEAK;
|
||||
case 1: return GTK_CONSTRAINT_STRENGTH_MEDIUM;
|
||||
case 2: return GTK_CONSTRAINT_STRENGTH_STRONG;
|
||||
case 3: return GTK_CONSTRAINT_STRENGTH_REQUIRED;
|
||||
default: g_assert_not_reached ();
|
||||
}
|
||||
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 unsigned int
|
||||
get_strength_id (GtkConstraintStrength strength)
|
||||
static GtkConstraintStrength
|
||||
get_strength (const char *id)
|
||||
{
|
||||
switch (strength)
|
||||
{
|
||||
case GTK_CONSTRAINT_STRENGTH_WEAK: return 0;
|
||||
case GTK_CONSTRAINT_STRENGTH_MEDIUM: return 1;
|
||||
case GTK_CONSTRAINT_STRENGTH_STRONG: return 2;
|
||||
case GTK_CONSTRAINT_STRENGTH_REQUIRED: return 3;
|
||||
default: g_assert_not_reached ();
|
||||
}
|
||||
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 *
|
||||
@@ -121,11 +116,11 @@ static void
|
||||
create_guide (GtkButton *button,
|
||||
GuideEditor *editor)
|
||||
{
|
||||
const char *id;
|
||||
int strength;
|
||||
const char *name;
|
||||
int w, h;
|
||||
GtkConstraintGuide *guide;
|
||||
unsigned int id;
|
||||
|
||||
if (editor->guide)
|
||||
guide = g_object_ref (editor->guide);
|
||||
@@ -147,7 +142,7 @@ create_guide (GtkButton *button,
|
||||
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_drop_down_get_selected (GTK_DROP_DOWN (editor->strength));
|
||||
id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength));
|
||||
strength = get_strength (id);
|
||||
gtk_constraint_guide_set_strength (guide, strength);
|
||||
|
||||
@@ -194,9 +189,14 @@ 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)
|
||||
@@ -222,7 +222,8 @@ guide_editor_constructed (GObject *object)
|
||||
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), h);
|
||||
|
||||
strength = gtk_constraint_guide_get_strength (editor->guide);
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (strength));
|
||||
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");
|
||||
}
|
||||
@@ -242,7 +243,7 @@ guide_editor_constructed (GObject *object)
|
||||
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_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (GTK_CONSTRAINT_STRENGTH_MEDIUM));
|
||||
gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "medium");
|
||||
|
||||
gtk_button_set_label (GTK_BUTTON (editor->button), "Create");
|
||||
}
|
||||
@@ -293,10 +294,9 @@ guide_editor_dispose (GObject *object)
|
||||
{
|
||||
GuideEditor *self = (GuideEditor *)object;
|
||||
|
||||
g_clear_pointer (&self->grid, gtk_widget_unparent);
|
||||
g_clear_object (&self->guide);
|
||||
|
||||
gtk_widget_dispose_template (GTK_WIDGET (self), GUIDE_EDITOR_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (guide_editor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
@@ -167,17 +167,7 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDropDown" id="strength">
|
||||
<property name="model">
|
||||
<object class="GtkStringList">
|
||||
<items>
|
||||
<item>Weak</item>
|
||||
<item>Medium</item>
|
||||
<item>Strong</item>
|
||||
<item>Required</item>
|
||||
</items>
|
||||
</object>
|
||||
</property>
|
||||
<object class="GtkComboBoxText" id="strength">
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">4</property>
|
||||
|
@@ -9,7 +9,7 @@ constraint_editor_sources = [
|
||||
|
||||
constraint_editor_resources = gnome.compile_resources('constraint_editor_resources',
|
||||
'constraint-editor.gresource.xml',
|
||||
source_dir: meson.current_source_dir(),
|
||||
source_dir: '.',
|
||||
)
|
||||
|
||||
executable('gtk4-constraint-editor',
|
||||
|
303
demos/font-explorer/fontcolors.c
Normal file
@@ -0,0 +1,303 @@
|
||||
#include "fontcolors.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "rangeedit.h"
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
PROP_PALETTE,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _FontColors
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GtkGrid *label;
|
||||
GtkGrid *grid;
|
||||
Pango2FontDescription *font_desc;
|
||||
GSimpleAction *reset_action;
|
||||
gboolean has_colors;
|
||||
char *palette;
|
||||
GtkCheckButton *default_check;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
};
|
||||
|
||||
struct _FontColorsClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (FontColors, font_colors, GTK_TYPE_WIDGET);
|
||||
|
||||
static Pango2Font *
|
||||
get_font (FontColors *self)
|
||||
{
|
||||
Pango2Context *context;
|
||||
Pango2Font *font;
|
||||
|
||||
context = pango2_context_new_with_font_map (self->font_map);
|
||||
font = pango2_context_load_font (context, self->font_desc);
|
||||
g_object_unref (context);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static void
|
||||
palette_changed (GtkCheckButton *button,
|
||||
FontColors *self)
|
||||
{
|
||||
g_free (self->palette);
|
||||
self->palette = g_strdup ((const char *) g_object_get_data (G_OBJECT (button), "palette"));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PALETTE]);
|
||||
}
|
||||
|
||||
static void
|
||||
update_colors (FontColors *self)
|
||||
{
|
||||
Pango2Font *font;
|
||||
hb_font_t *hb_font;
|
||||
hb_face_t *hb_face;
|
||||
GtkWidget *child;
|
||||
GtkWidget *check;
|
||||
unsigned int n_colors;
|
||||
hb_color_t *colors;
|
||||
GtkWidget *box;
|
||||
|
||||
g_object_ref (self->label);
|
||||
|
||||
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->grid))))
|
||||
gtk_grid_remove (self->grid, child);
|
||||
|
||||
gtk_grid_attach (self->grid, GTK_WIDGET (self->label), 0, -4, 2, 1);
|
||||
g_object_unref (self->label);
|
||||
|
||||
self->default_check = NULL;
|
||||
|
||||
font = get_font (self);
|
||||
hb_font = pango2_font_get_hb_font (font);
|
||||
hb_face = hb_font_get_face (hb_font);
|
||||
|
||||
self->has_colors = hb_ot_color_has_palettes (hb_face);
|
||||
gtk_widget_set_visible (GTK_WIDGET (self), self->has_colors);
|
||||
if (!self->has_colors)
|
||||
{
|
||||
g_simple_action_set_enabled (self->reset_action, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
|
||||
gtk_grid_attach (self->grid, box, 0, -3, 2, 1);
|
||||
|
||||
check = gtk_check_button_new_with_label ("Default");
|
||||
g_object_set_data (G_OBJECT (check), "palette", (gpointer)"default");
|
||||
if (g_strcmp0 ("default", self->palette) == 0)
|
||||
gtk_check_button_set_active (GTK_CHECK_BUTTON (check), TRUE);
|
||||
g_signal_connect (check, "toggled", G_CALLBACK (palette_changed), self);
|
||||
gtk_box_append (GTK_BOX (box), check);
|
||||
self->default_check = GTK_CHECK_BUTTON (check);
|
||||
|
||||
check = gtk_check_button_new_with_label ("Light");
|
||||
g_object_set_data (G_OBJECT (check), "palette", (gpointer)"light");
|
||||
if (g_strcmp0 ("light", self->palette) == 0)
|
||||
gtk_check_button_set_active (GTK_CHECK_BUTTON (check), TRUE);
|
||||
g_signal_connect (check, "toggled", G_CALLBACK (palette_changed), self);
|
||||
gtk_check_button_set_group (GTK_CHECK_BUTTON (check), self->default_check);
|
||||
gtk_box_append (GTK_BOX (box), check);
|
||||
|
||||
check = gtk_check_button_new_with_label ("Dark");
|
||||
g_object_set_data (G_OBJECT (check), "palette", (gpointer)"dark");
|
||||
if (g_strcmp0 ("dark", self->palette) == 0)
|
||||
gtk_check_button_set_active (GTK_CHECK_BUTTON (check), TRUE);
|
||||
g_signal_connect (check, "toggled", G_CALLBACK (palette_changed), self);
|
||||
gtk_check_button_set_group (GTK_CHECK_BUTTON (check), self->default_check);
|
||||
gtk_box_append (GTK_BOX (box), check);
|
||||
|
||||
for (int i = 0; i < hb_ot_color_palette_get_count (hb_face); i++)
|
||||
{
|
||||
char *id = g_strdup_printf ("palette%d", i);
|
||||
char *label = g_strdup_printf ("Palette %d", i);
|
||||
GtkWidget *palette;
|
||||
|
||||
check = gtk_check_button_new_with_label (label);
|
||||
g_object_set_data_full (G_OBJECT (check), "palette", id, g_free);
|
||||
if (g_strcmp0 (id, self->palette) == 0)
|
||||
gtk_check_button_set_active (GTK_CHECK_BUTTON (check), TRUE);
|
||||
g_signal_connect (check, "toggled", G_CALLBACK (palette_changed), self);
|
||||
gtk_check_button_set_group (GTK_CHECK_BUTTON (check), self->default_check);
|
||||
gtk_grid_attach (self->grid, check, 0, i, 1, 1);
|
||||
|
||||
n_colors = hb_ot_color_palette_get_colors (hb_face, i, 0, NULL, NULL);
|
||||
colors = g_new (hb_color_t, n_colors);
|
||||
n_colors = hb_ot_color_palette_get_colors (hb_face, i, 0, &n_colors, colors);
|
||||
|
||||
palette = gtk_grid_new ();
|
||||
gtk_widget_set_valign (palette, GTK_ALIGN_CENTER);
|
||||
gtk_grid_attach (self->grid, palette, 1, i, 1, 1);
|
||||
|
||||
/* HACK - defeat first-child/last-child theming */
|
||||
gtk_grid_attach (GTK_GRID (palette), gtk_picture_new (), -1, 0, 1, 1);
|
||||
|
||||
for (int k = 0; k < n_colors; k++)
|
||||
{
|
||||
GtkWidget *swatch;
|
||||
swatch = g_object_new (g_type_from_name ("GtkColorSwatch"),
|
||||
"rgba", &(GdkRGBA){ hb_color_get_red (colors[k])/255.,
|
||||
hb_color_get_green (colors[k])/255.,
|
||||
hb_color_get_blue (colors[k])/255.,
|
||||
hb_color_get_alpha (colors[k])/255.},
|
||||
"selectable", FALSE,
|
||||
"has-menu", FALSE,
|
||||
"can-drag", FALSE,
|
||||
"width-request", 16,
|
||||
"height-request", 16,
|
||||
NULL);
|
||||
gtk_grid_attach (GTK_GRID (palette), swatch, k % 6, k / 6, 1, 1);
|
||||
}
|
||||
|
||||
/* HACK - defeat first-child/last-child theming */
|
||||
gtk_grid_attach (GTK_GRID (palette), gtk_picture_new (), 6, 0, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
reset (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
FontColors *self)
|
||||
{
|
||||
g_free (self->palette);
|
||||
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
|
||||
if (self->has_colors)
|
||||
gtk_check_button_set_active (self->default_check, TRUE);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PALETTE]);
|
||||
g_simple_action_set_enabled (self->reset_action, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
font_colors_init (FontColors *self)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
|
||||
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
self->reset_action = g_simple_action_new ("reset", NULL);
|
||||
g_simple_action_set_enabled (self->reset_action, FALSE);
|
||||
g_signal_connect (self->reset_action, "activate", G_CALLBACK (reset), self);
|
||||
}
|
||||
|
||||
static void
|
||||
font_colors_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), FONT_COLORS_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (font_colors_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
font_colors_finalize (GObject *object)
|
||||
{
|
||||
FontColors *self = FONT_COLORS (object);
|
||||
|
||||
g_clear_pointer (&self->font_desc, pango2_font_description_free);
|
||||
g_free (self->palette);
|
||||
g_clear_object (&self->font_map);
|
||||
|
||||
G_OBJECT_CLASS (font_colors_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
font_colors_set_property (GObject *object,
|
||||
unsigned int prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FontColors *self = FONT_COLORS (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
pango2_font_description_free (self->font_desc);
|
||||
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_colors (self);
|
||||
}
|
||||
|
||||
static void
|
||||
font_colors_get_property (GObject *object,
|
||||
unsigned int prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FontColors *self = FONT_COLORS (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PALETTE:
|
||||
g_value_set_string (value, self->palette);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
font_colors_class_init (FontColorsClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = font_colors_dispose;
|
||||
object_class->finalize = font_colors_finalize;
|
||||
object_class->get_property = font_colors_get_property;
|
||||
object_class->set_property = font_colors_set_property;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FONT_DESC] =
|
||||
g_param_spec_boxed ("font-desc", "", "",
|
||||
PANGO2_TYPE_FONT_DESCRIPTION,
|
||||
G_PARAM_WRITABLE);
|
||||
|
||||
properties[PROP_PALETTE] =
|
||||
g_param_spec_string ("palette", "", "",
|
||||
PANGO2_COLOR_PALETTE_DEFAULT,
|
||||
G_PARAM_READABLE);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/fontcolors.ui");
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontColors, grid);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontColors, label);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontcolors");
|
||||
}
|
||||
|
||||
GAction *
|
||||
font_colors_get_reset_action (FontColors *self)
|
||||
{
|
||||
return G_ACTION (self->reset_action);
|
||||
}
|
15
demos/font-explorer/fontcolors.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define FONT_COLORS_TYPE (font_colors_get_type ())
|
||||
#define FONT_COLORS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_COLORS_TYPE, FontColors))
|
||||
|
||||
|
||||
typedef struct _FontColors FontColors;
|
||||
typedef struct _FontColorsClass FontColorsClass;
|
||||
|
||||
|
||||
GType font_colors_get_type (void);
|
||||
GAction * font_colors_get_reset_action (FontColors *self);
|
25
demos/font-explorer/fontcolors.ui
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="FontColors" parent="GtkWidget">
|
||||
<property name="layout-manager"><object class="GtkBinLayout"/></property>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid">
|
||||
<child>
|
||||
<object class="GtkLabel" id="label">
|
||||
<property name="label" translatable="yes">Colors</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="xalign">0</property>
|
||||
<style>
|
||||
<class name="heading"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="row">-2</property>
|
||||
<property name="column">0</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
257
demos/font-explorer/fontcontrols.c
Normal file
@@ -0,0 +1,257 @@
|
||||
#include "fontcontrols.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "rangeedit.h"
|
||||
|
||||
enum {
|
||||
PROP_SIZE = 1,
|
||||
PROP_LETTERSPACING,
|
||||
PROP_LINE_HEIGHT,
|
||||
PROP_FOREGROUND,
|
||||
PROP_BACKGROUND,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _FontControls
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GtkAdjustment *size_adjustment;
|
||||
GtkAdjustment *letterspacing_adjustment;
|
||||
GtkAdjustment *line_height_adjustment;
|
||||
GtkColorButton *foreground;
|
||||
GtkColorButton *background;
|
||||
|
||||
GSimpleAction *reset_action;
|
||||
};
|
||||
|
||||
struct _FontControlsClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FontControls, font_controls, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
size_changed (GtkAdjustment *adjustment,
|
||||
FontControls *self)
|
||||
{
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SIZE]);
|
||||
g_simple_action_set_enabled (self->reset_action, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
letterspacing_changed (GtkAdjustment *adjustment,
|
||||
FontControls *self)
|
||||
{
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LETTERSPACING]);
|
||||
g_simple_action_set_enabled (self->reset_action, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
line_height_changed (GtkAdjustment *adjustment,
|
||||
FontControls *self)
|
||||
{
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LINE_HEIGHT]);
|
||||
g_simple_action_set_enabled (self->reset_action, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
color_set (GtkColorButton *button,
|
||||
GParamSpec *pspec,
|
||||
FontControls *self)
|
||||
{
|
||||
if (button == self->foreground)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FOREGROUND]);
|
||||
else
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BACKGROUND]);
|
||||
g_simple_action_set_enabled (self->reset_action, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
swap_colors (GtkButton *button,
|
||||
FontControls *self)
|
||||
{
|
||||
GdkRGBA fg;
|
||||
GdkRGBA bg;
|
||||
|
||||
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (self->foreground), &fg);
|
||||
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (self->background), &bg);
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (self->foreground), &bg);
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (self->background), &fg);
|
||||
}
|
||||
|
||||
static void
|
||||
reset (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
FontControls *self)
|
||||
{
|
||||
gtk_adjustment_set_value (self->size_adjustment, 12.);
|
||||
gtk_adjustment_set_value (self->letterspacing_adjustment, 0.);
|
||||
gtk_adjustment_set_value (self->line_height_adjustment, 1.);
|
||||
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (self->foreground), &(GdkRGBA){0., 0., 0., 1.0 });
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (self->background), &(GdkRGBA){1., 1., 1., 1.0 });
|
||||
|
||||
g_simple_action_set_enabled (self->reset_action, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
font_controls_init (FontControls *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
self->reset_action = g_simple_action_new ("reset", NULL);
|
||||
g_simple_action_set_enabled (self->reset_action, FALSE);
|
||||
g_signal_connect (self->reset_action, "activate", G_CALLBACK (reset), self);
|
||||
}
|
||||
|
||||
static void
|
||||
font_controls_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), FONT_CONTROLS_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (font_controls_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
font_controls_finalize (GObject *object)
|
||||
{
|
||||
//FontControls *self = FONT_CONTROLS (object);
|
||||
|
||||
G_OBJECT_CLASS (font_controls_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
font_controls_set_property (GObject *object,
|
||||
unsigned int prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FontControls *self = FONT_CONTROLS (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SIZE:
|
||||
gtk_adjustment_set_value (self->size_adjustment, g_value_get_float (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
font_controls_get_property (GObject *object,
|
||||
unsigned int prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FontControls *self = FONT_CONTROLS (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SIZE:
|
||||
g_value_set_float (value, gtk_adjustment_get_value (self->size_adjustment));
|
||||
break;
|
||||
|
||||
case PROP_LETTERSPACING:
|
||||
g_value_set_int (value, (int) gtk_adjustment_get_value (self->letterspacing_adjustment));
|
||||
break;
|
||||
|
||||
case PROP_LINE_HEIGHT:
|
||||
g_value_set_float (value, gtk_adjustment_get_value (self->line_height_adjustment));
|
||||
break;
|
||||
|
||||
case PROP_FOREGROUND:
|
||||
{
|
||||
GdkRGBA rgba;
|
||||
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (self->foreground), &rgba);
|
||||
g_value_set_boxed (value, &rgba);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_BACKGROUND:
|
||||
{
|
||||
GdkRGBA rgba;
|
||||
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (self->background), &rgba);
|
||||
g_value_set_boxed (value, &rgba);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
font_controls_class_init (FontControlsClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
g_type_ensure (RANGE_EDIT_TYPE);
|
||||
|
||||
object_class->dispose = font_controls_dispose;
|
||||
object_class->finalize = font_controls_finalize;
|
||||
object_class->get_property = font_controls_get_property;
|
||||
object_class->set_property = font_controls_set_property;
|
||||
|
||||
properties[PROP_SIZE] =
|
||||
g_param_spec_float ("size", "", "",
|
||||
0., 100., 12.,
|
||||
G_PARAM_READABLE);
|
||||
|
||||
properties[PROP_LETTERSPACING] =
|
||||
g_param_spec_int ("letterspacing", "", "",
|
||||
-G_MAXINT, G_MAXINT, 0,
|
||||
G_PARAM_READABLE);
|
||||
|
||||
properties[PROP_LINE_HEIGHT] =
|
||||
g_param_spec_float ("line-height", "", "",
|
||||
0., 100., 1.,
|
||||
G_PARAM_READABLE);
|
||||
|
||||
properties[PROP_FOREGROUND] =
|
||||
g_param_spec_boxed ("foreground", "", "",
|
||||
GDK_TYPE_RGBA,
|
||||
G_PARAM_READABLE);
|
||||
|
||||
properties[PROP_BACKGROUND] =
|
||||
g_param_spec_boxed ("background", "", "",
|
||||
GDK_TYPE_RGBA,
|
||||
G_PARAM_READABLE);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/fontcontrols.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, size_adjustment);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, letterspacing_adjustment);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, line_height_adjustment);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, foreground);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontControls, background);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), size_changed);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), letterspacing_changed);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), line_height_changed);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), color_set);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), swap_colors);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontcontrols");
|
||||
}
|
||||
|
||||
FontControls *
|
||||
font_controls_new (void)
|
||||
{
|
||||
return g_object_new (FONT_CONTROLS_TYPE, NULL);
|
||||
}
|
||||
|
||||
GAction *
|
||||
font_controls_get_reset_action (FontControls *self)
|
||||
{
|
||||
return G_ACTION (self->reset_action);
|
||||
}
|
16
demos/font-explorer/fontcontrols.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define FONT_CONTROLS_TYPE (font_controls_get_type ())
|
||||
#define FONT_CONTROLS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_CONTROLS_TYPE, FontControls))
|
||||
|
||||
|
||||
typedef struct _FontControls FontControls;
|
||||
typedef struct _FontControlsClass FontControlsClass;
|
||||
|
||||
|
||||
GType font_controls_get_type (void);
|
||||
FontControls * font_controls_new (void);
|
||||
GAction * font_controls_get_reset_action (FontControls *self);
|
173
demos/font-explorer/fontcontrols.ui
Normal file
@@ -0,0 +1,173 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="FontControls" parent="GtkWidget">
|
||||
<property name="layout-manager"><object class="GtkGridLayout"/></property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Size</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="RangeEdit">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="width-request">160</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="adjustment">
|
||||
<object class="GtkAdjustment" id="size_adjustment">
|
||||
<property name="lower">7</property>
|
||||
<property name="upper">100</property>
|
||||
<property name="value">14</property>
|
||||
<property name="step_increment">0.5</property>
|
||||
<property name="page_increment">10</property>
|
||||
<signal name="value-changed" handler="size_changed"/>
|
||||
</object>
|
||||
</property>
|
||||
<property name="default-value">12</property>
|
||||
<property name="n-chars">5</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">0</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Letterspacing</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="RangeEdit">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="width-request">160</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="adjustment">
|
||||
<object class="GtkAdjustment" id="letterspacing_adjustment">
|
||||
<property name="lower">-1024</property>
|
||||
<property name="upper">8192</property>
|
||||
<property name="value">0</property>
|
||||
<property name="step_increment">1</property>
|
||||
<property name="page_increment">512</property>
|
||||
<signal name="value-changed" handler="letterspacing_changed"/>
|
||||
</object>
|
||||
</property>
|
||||
<property name="default-value">0</property>
|
||||
<property name="n-chars">5</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">1</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Line Height</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="RangeEdit">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="width-request">160</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="adjustment">
|
||||
<object class="GtkAdjustment" id="line_height_adjustment">
|
||||
<property name="lower">0.75</property>
|
||||
<property name="upper">2.5</property>
|
||||
<property name="value">1.0</property>
|
||||
<property name="step_increment">0.1</property>
|
||||
<property name="page_increment">1</property>
|
||||
<signal name="value-changed" handler="line_height_changed"/>
|
||||
</object>
|
||||
</property>
|
||||
<property name="default-value">1</property>
|
||||
<property name="n-chars">5</property>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">2</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Foreground</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColorButton" id="foreground">
|
||||
<property name="rgba">black</property>
|
||||
<signal name="notify::rgba" handler="color_set"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">3</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Background</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="valign">baseline</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">4</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColorButton" id="background">
|
||||
<property name="rgba">white</property>
|
||||
<signal name="notify::rgba" handler="color_set"/>
|
||||
<layout>
|
||||
<property name="column">1</property>
|
||||
<property name="row">4</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="icon-name">object-flip-vertical-symbolic</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="circular"/>
|
||||
</style>
|
||||
<signal name="clicked" handler="swap_colors"/>
|
||||
<layout>
|
||||
<property name="column">2</property>
|
||||
<property name="row">3</property>
|
||||
<property name="row-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
43
demos/font-explorer/fontexplorer.css
Normal file
@@ -0,0 +1,43 @@
|
||||
box.sidebar {
|
||||
padding: 20px;
|
||||
border-spacing: 20px;
|
||||
}
|
||||
fontcontrols {
|
||||
border-spacing: 10px;
|
||||
}
|
||||
fontvariations > grid {
|
||||
border-spacing: 10px;
|
||||
}
|
||||
fontcolors > grid {
|
||||
border-spacing: 10px;
|
||||
}
|
||||
samplechooser {
|
||||
border-spacing: 10px;
|
||||
}
|
||||
plainview .content {
|
||||
padding: 20px;
|
||||
}
|
||||
waterfallview .content {
|
||||
padding: 20px;
|
||||
}
|
||||
styleview .content {
|
||||
padding: 20px;
|
||||
}
|
||||
glyphsview .content {
|
||||
padding: 20px;
|
||||
}
|
||||
infoview .content {
|
||||
padding: 20px;
|
||||
border-spacing: 10px;
|
||||
}
|
||||
gridview > child {
|
||||
padding: 0;
|
||||
}
|
||||
glyphview {
|
||||
padding: 0;
|
||||
border: 0.6px solid gray;
|
||||
}
|
||||
.viewcontrols {
|
||||
padding: 20px;
|
||||
border-spacing: 10px;
|
||||
}
|
19
demos/font-explorer/fontexplorer.gresource.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gtk/fontexplorer">
|
||||
<file preprocess="xml-stripblanks">fontcolors.ui</file>
|
||||
<file preprocess="xml-stripblanks">fontcontrols.ui</file>
|
||||
<file preprocess="xml-stripblanks">fontexplorerwin.ui</file>
|
||||
<file preprocess="xml-stripblanks">fontfeatures.ui</file>
|
||||
<file preprocess="xml-stripblanks">fontvariations.ui</file>
|
||||
<file preprocess="xml-stripblanks">glyphsview.ui</file>
|
||||
<file preprocess="xml-stripblanks">infoview.ui</file>
|
||||
<file preprocess="xml-stripblanks">plainview.ui</file>
|
||||
<file preprocess="xml-stripblanks">rangeedit.ui</file>
|
||||
<file preprocess="xml-stripblanks">samplechooser.ui</file>
|
||||
<file preprocess="xml-stripblanks">sampleeditor.ui</file>
|
||||
<file preprocess="xml-stripblanks">styleview.ui</file>
|
||||
<file preprocess="xml-stripblanks">waterfallview.ui</file>
|
||||
<file>fontexplorer.css</file>
|
||||
</gresource>
|
||||
</gresources>
|
186
demos/font-explorer/fontexplorerapp.c
Normal file
@@ -0,0 +1,186 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "fontexplorerapp.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "fontexplorerwin.h"
|
||||
|
||||
#include "demo_conf.h"
|
||||
|
||||
struct _FontExplorerApp
|
||||
{
|
||||
GtkApplication parent;
|
||||
};
|
||||
|
||||
struct _FontExplorerAppClass
|
||||
{
|
||||
GtkApplicationClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FontExplorerApp, font_explorer_app, GTK_TYPE_APPLICATION);
|
||||
|
||||
static void
|
||||
font_explorer_app_init (FontExplorerApp *app)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
quit_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer app)
|
||||
{
|
||||
g_application_quit (G_APPLICATION (app));
|
||||
}
|
||||
|
||||
static void
|
||||
inspector_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer app)
|
||||
{
|
||||
gtk_window_set_interactive_debugging (TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
about_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkApplication *app = user_data;
|
||||
const char *authors[] = {
|
||||
"The GTK Team",
|
||||
NULL
|
||||
};
|
||||
char *icon_theme;
|
||||
char *version;
|
||||
GString *s;
|
||||
char *os_name;
|
||||
char *os_version;
|
||||
|
||||
g_object_get (gtk_settings_get_default (),
|
||||
"gtk-icon-theme-name", &icon_theme,
|
||||
NULL);
|
||||
|
||||
s = g_string_new ("");
|
||||
|
||||
os_name = g_get_os_info (G_OS_INFO_KEY_NAME);
|
||||
os_version = g_get_os_info (G_OS_INFO_KEY_VERSION_ID);
|
||||
if (os_name && os_version)
|
||||
g_string_append_printf (s, "OS\t%s %s\n\n", os_name, os_version);
|
||||
g_string_append (s, "System libraries\n");
|
||||
g_string_append_printf (s, "\tGLib\t%d.%d.%d\n",
|
||||
glib_major_version,
|
||||
glib_minor_version,
|
||||
glib_micro_version);
|
||||
g_string_append_printf (s, "\tPango2\t%s\n",
|
||||
pango2_version_string ());
|
||||
g_string_append_printf (s, "\tGTK \t%d.%d.%d\n",
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ());
|
||||
g_string_append_printf (s, "\nIcon theme\n\t%s", icon_theme);
|
||||
version = g_strdup_printf ("%s%s%s\nRunning against GTK %d.%d.%d",
|
||||
PACKAGE_VERSION,
|
||||
g_strcmp0 (PROFILE, "devel") == 0 ? "-" : "",
|
||||
g_strcmp0 (PROFILE, "devel") == 0 ? VCS_TAG : "",
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ());
|
||||
|
||||
gtk_show_about_dialog (GTK_WINDOW (gtk_application_get_active_window (app)),
|
||||
"program-name", g_strcmp0 (PROFILE, "devel") == 0
|
||||
? "GTK Font Explorer (Development)"
|
||||
: "GTK Font Explorer",
|
||||
"version", version,
|
||||
"copyright", "© 1997—2021 The GTK Team",
|
||||
"license-type", GTK_LICENSE_LGPL_2_1,
|
||||
"website", "http://www.gtk.org",
|
||||
"comments", "Program to explore font features",
|
||||
"authors", authors,
|
||||
"logo-icon-name", "org.gtk.FontExplorer",
|
||||
"title", "About GTK Font Explorer",
|
||||
"system-information", s->str,
|
||||
NULL);
|
||||
|
||||
g_string_free (s, TRUE);
|
||||
g_free (version);
|
||||
g_free (icon_theme);
|
||||
g_free (os_name);
|
||||
g_free (os_version);
|
||||
}
|
||||
|
||||
static GActionEntry app_entries[] =
|
||||
{
|
||||
{ "quit", quit_activated, NULL, NULL, NULL },
|
||||
{ "inspector", inspector_activated, NULL, NULL, NULL },
|
||||
{ "about", about_activated, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
font_explorer_app_startup (GApplication *app)
|
||||
{
|
||||
const char *quit_accels[2] = { "<Ctrl>Q", NULL };
|
||||
GtkCssProvider *provider;
|
||||
|
||||
G_APPLICATION_CLASS (font_explorer_app_parent_class)->startup (app);
|
||||
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
||||
app_entries, G_N_ELEMENTS (app_entries),
|
||||
app);
|
||||
gtk_application_set_accels_for_action (GTK_APPLICATION (app),
|
||||
"app.quit",
|
||||
quit_accels);
|
||||
|
||||
provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_resource (provider, "/org/gtk/fontexplorer/fontexplorer.css");
|
||||
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||||
GTK_STYLE_PROVIDER (provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
}
|
||||
|
||||
static void
|
||||
font_explorer_app_activate (GApplication *app)
|
||||
{
|
||||
FontExplorerWindow *win;
|
||||
|
||||
win = font_explorer_window_new (FONT_EXPLORER_APP (app));
|
||||
|
||||
if (g_strcmp0 (PROFILE, "devel") == 0)
|
||||
gtk_widget_add_css_class (GTK_WIDGET (win), "devel");
|
||||
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
font_explorer_app_open (GApplication *app,
|
||||
GFile **files,
|
||||
int n_files,
|
||||
const char *hint)
|
||||
{
|
||||
FontExplorerWindow *win;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_files; i++)
|
||||
{
|
||||
win = font_explorer_window_new (FONT_EXPLORER_APP (app));
|
||||
font_explorer_window_load (win, files[i]);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
font_explorer_app_class_init (FontExplorerAppClass *class)
|
||||
{
|
||||
G_APPLICATION_CLASS (class)->startup = font_explorer_app_startup;
|
||||
G_APPLICATION_CLASS (class)->activate = font_explorer_app_activate;
|
||||
G_APPLICATION_CLASS (class)->open = font_explorer_app_open;
|
||||
}
|
||||
|
||||
FontExplorerApp *
|
||||
font_explorer_app_new (void)
|
||||
{
|
||||
return g_object_new (FONT_EXPLORER_APP_TYPE,
|
||||
"application-id", "org.gtk.FontExplorer",
|
||||
"flags", G_APPLICATION_HANDLES_OPEN,
|
||||
NULL);
|
||||
}
|
15
demos/font-explorer/fontexplorerapp.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define FONT_EXPLORER_APP_TYPE (font_explorer_app_get_type ())
|
||||
#define FONT_EXPLORER_APP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_EXPLORER_APP_TYPE, FontExplorerApp))
|
||||
|
||||
|
||||
typedef struct _FontExplorerApp FontExplorerApp;
|
||||
typedef struct _FontExplorerAppClass FontExplorerAppClass;
|
||||
|
||||
|
||||
GType font_explorer_app_get_type (void);
|
||||
FontExplorerApp * font_explorer_app_new (void);
|
269
demos/font-explorer/fontexplorerwin.c
Normal file
@@ -0,0 +1,269 @@
|
||||
#include "fontexplorerwin.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fontcolors.h"
|
||||
#include "fontcontrols.h"
|
||||
#include "fontexplorerapp.h"
|
||||
#include "fontfeatures.h"
|
||||
#include "fontvariations.h"
|
||||
#include "glyphsview.h"
|
||||
#include "infoview.h"
|
||||
#include "plainview.h"
|
||||
#include "samplechooser.h"
|
||||
#include "sampleeditor.h"
|
||||
#include "styleview.h"
|
||||
#include "waterfallview.h"
|
||||
|
||||
struct _FontExplorerWindow
|
||||
{
|
||||
GtkApplicationWindow parent;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
|
||||
GtkFontButton *fontbutton;
|
||||
GtkLabel *path;
|
||||
FontControls *controls;
|
||||
FontFeatures *features;
|
||||
FontVariations *variations;
|
||||
FontColors *colors;
|
||||
GtkStack *stack;
|
||||
GtkToggleButton *plain_toggle;
|
||||
GtkToggleButton *waterfall_toggle;
|
||||
GtkToggleButton *style_toggle;
|
||||
GtkToggleButton *glyphs_toggle;
|
||||
GtkToggleButton *info_toggle;
|
||||
GtkToggleButton *edit_toggle;
|
||||
};
|
||||
|
||||
struct _FontExplorerWindowClass
|
||||
{
|
||||
GtkApplicationWindowClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
G_DEFINE_TYPE(FontExplorerWindow, font_explorer_window, GTK_TYPE_APPLICATION_WINDOW);
|
||||
|
||||
static void
|
||||
reset (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
FontExplorerWindow *self)
|
||||
{
|
||||
g_action_activate (font_controls_get_reset_action (self->controls), NULL);
|
||||
g_action_activate (font_features_get_reset_action (self->features), NULL);
|
||||
g_action_activate (font_variations_get_reset_action (self->variations), NULL);
|
||||
g_action_activate (font_colors_get_reset_action (self->colors), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
update_reset (GSimpleAction *action,
|
||||
GParamSpec *pspec,
|
||||
FontExplorerWindow *self)
|
||||
{
|
||||
gboolean enabled;
|
||||
GAction *reset_action;
|
||||
|
||||
enabled = g_action_get_enabled (font_controls_get_reset_action (self->controls)) ||
|
||||
g_action_get_enabled (font_features_get_reset_action (self->features)) ||
|
||||
g_action_get_enabled (font_variations_get_reset_action (self->variations)) ||
|
||||
g_action_get_enabled (font_colors_get_reset_action (self->colors));
|
||||
|
||||
reset_action = g_action_map_lookup_action (G_ACTION_MAP (self), "reset");
|
||||
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (reset_action), enabled);
|
||||
}
|
||||
|
||||
static void
|
||||
font_explorer_window_init (FontExplorerWindow *self)
|
||||
{
|
||||
GSimpleAction *reset_action;
|
||||
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
reset_action = g_simple_action_new ("reset", NULL);
|
||||
g_signal_connect (reset_action, "activate", G_CALLBACK (reset), self);
|
||||
g_signal_connect (font_controls_get_reset_action (self->controls),
|
||||
"notify::enabled", G_CALLBACK (update_reset), self);
|
||||
g_signal_connect (font_variations_get_reset_action (self->variations),
|
||||
"notify::enabled", G_CALLBACK (update_reset), self);
|
||||
g_signal_connect (font_colors_get_reset_action (self->colors),
|
||||
"notify::enabled", G_CALLBACK (update_reset), self);
|
||||
g_signal_connect (font_features_get_reset_action (self->features),
|
||||
"notify::enabled", G_CALLBACK (update_reset), self);
|
||||
|
||||
g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (reset_action));
|
||||
update_reset (NULL, NULL, self);
|
||||
}
|
||||
|
||||
static void
|
||||
update_view (GtkToggleButton *button,
|
||||
FontExplorerWindow *self)
|
||||
{
|
||||
if (gtk_toggle_button_get_active (self->edit_toggle))
|
||||
gtk_stack_set_visible_child_name (self->stack, "edit");
|
||||
else if (gtk_toggle_button_get_active (self->plain_toggle))
|
||||
gtk_stack_set_visible_child_name (self->stack, "plain");
|
||||
else if (gtk_toggle_button_get_active (self->waterfall_toggle))
|
||||
gtk_stack_set_visible_child_name (self->stack, "waterfall");
|
||||
else if (gtk_toggle_button_get_active (self->style_toggle))
|
||||
gtk_stack_set_visible_child_name (self->stack, "style");
|
||||
else if (gtk_toggle_button_get_active (self->glyphs_toggle))
|
||||
gtk_stack_set_visible_child_name (self->stack, "glyphs");
|
||||
else if (gtk_toggle_button_get_active (self->info_toggle))
|
||||
gtk_stack_set_visible_child_name (self->stack, "info");
|
||||
}
|
||||
|
||||
static void
|
||||
font_explorer_window_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FontExplorerWindow *self = FONT_EXPLORER_WINDOW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
font_explorer_window_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FontExplorerWindow *self = FONT_EXPLORER_WINDOW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
font_explorer_window_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), FONT_EXPLORER_WINDOW_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (font_explorer_window_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
font_explorer_window_finalize (GObject *object)
|
||||
{
|
||||
FontExplorerWindow *self = FONT_EXPLORER_WINDOW (object);
|
||||
|
||||
g_clear_object (&self->font_map);
|
||||
|
||||
G_OBJECT_CLASS (font_explorer_window_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
font_explorer_window_class_init (FontExplorerWindowClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
g_type_ensure (FONT_COLORS_TYPE);
|
||||
g_type_ensure (FONT_CONTROLS_TYPE);
|
||||
g_type_ensure (FONT_FEATURES_TYPE);
|
||||
g_type_ensure (FONT_VARIATIONS_TYPE);
|
||||
g_type_ensure (GLYPHS_VIEW_TYPE);
|
||||
g_type_ensure (INFO_VIEW_TYPE);
|
||||
g_type_ensure (PLAIN_VIEW_TYPE);
|
||||
g_type_ensure (SAMPLE_CHOOSER_TYPE);
|
||||
g_type_ensure (SAMPLE_EDITOR_TYPE);
|
||||
g_type_ensure (STYLE_VIEW_TYPE);
|
||||
g_type_ensure (WATERFALL_VIEW_TYPE);
|
||||
|
||||
object_class->set_property = font_explorer_window_set_property;
|
||||
object_class->get_property = font_explorer_window_get_property;
|
||||
object_class->dispose = font_explorer_window_dispose;
|
||||
object_class->finalize = font_explorer_window_finalize;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/fontexplorerwin.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, fontbutton);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, path);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, controls);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, variations);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, colors);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, features);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, stack);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, plain_toggle);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, waterfall_toggle);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, style_toggle);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, glyphs_toggle);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, info_toggle);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontExplorerWindow, edit_toggle);
|
||||
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), update_view);
|
||||
}
|
||||
|
||||
FontExplorerWindow *
|
||||
font_explorer_window_new (FontExplorerApp *app)
|
||||
{
|
||||
return g_object_new (FONT_EXPLORER_WINDOW_TYPE, "application", app, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
font_explorer_window_load (FontExplorerWindow *self,
|
||||
GFile *file)
|
||||
{
|
||||
const char *path;
|
||||
Pango2FontMap *map;
|
||||
Pango2HbFace *face;
|
||||
Pango2FontDescription *desc;
|
||||
char *basename;
|
||||
|
||||
path = g_file_peek_path (file);
|
||||
basename = g_path_get_basename (path);
|
||||
|
||||
face = pango2_hb_face_new_from_file (path, 0, -2, NULL, NULL);
|
||||
desc = pango2_font_face_describe (PANGO2_FONT_FACE (face));
|
||||
|
||||
map = pango2_font_map_new ();
|
||||
pango2_font_map_add_face (map, PANGO2_FONT_FACE (face));
|
||||
pango2_font_map_set_fallback (map, pango2_font_map_get_default ());
|
||||
|
||||
g_set_object (&self->font_map, map);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FONT_MAP]);
|
||||
|
||||
g_object_unref (map);
|
||||
|
||||
gtk_font_chooser_set_font_desc (GTK_FONT_CHOOSER (self->fontbutton), desc);
|
||||
|
||||
gtk_widget_hide (GTK_WIDGET (self->fontbutton));
|
||||
gtk_widget_show (GTK_WIDGET (self->path));
|
||||
gtk_label_set_label (self->path, basename);
|
||||
|
||||
pango2_font_description_free (desc);
|
||||
g_free (basename);
|
||||
}
|
18
demos/font-explorer/fontexplorerwin.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "fontexplorerapp.h"
|
||||
|
||||
|
||||
#define FONT_EXPLORER_WINDOW_TYPE (font_explorer_window_get_type ())
|
||||
#define FONT_EXPLORER_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_EXPLORER_WINDOW_TYPE, FontExplorerWindow))
|
||||
|
||||
|
||||
typedef struct _FontExplorerWindow FontExplorerWindow;
|
||||
typedef struct _FontExplorerWindowClass FontExplorerWindowClass;
|
||||
|
||||
|
||||
GType font_explorer_window_get_type (void);
|
||||
FontExplorerWindow * font_explorer_window_new (FontExplorerApp *app);
|
||||
void font_explorer_window_load (FontExplorerWindow *self,
|
||||
GFile *file);
|
252
demos/font-explorer/fontexplorerwin.ui
Normal file
@@ -0,0 +1,252 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<menu id="gear_menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Inspector</attribute>
|
||||
<attribute name="action">app.inspector</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_About GTK Font Explorer</attribute>
|
||||
<attribute name="action">app.about</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
<template class="FontExplorerWindow" parent="GtkApplicationWindow">
|
||||
<property name="title" translatable="yes">Font Explorer</property>
|
||||
<property name="default-width">1024</property>
|
||||
<property name="default-height">768</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<child>
|
||||
<object class="GtkButton" id="reset">
|
||||
<property name="receives-default">1</property>
|
||||
<property name="tooltip-text">Reset</property>
|
||||
<property name="icon-name">view-refresh-symbolic</property>
|
||||
<property name="action-name">win.reset</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="title">
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">horizontal</property>
|
||||
<style>
|
||||
<class name="linked"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="plain_toggle">
|
||||
<property name="label">Plain</property>
|
||||
<property name="active">1</property>
|
||||
<signal name="toggled" handler="update_view"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="waterfall_toggle">
|
||||
<property name="label">Waterfall</property>
|
||||
<property name="group">plain_toggle</property>
|
||||
<signal name="toggled" handler="update_view"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="style_toggle">
|
||||
<property name="label">Styles</property>
|
||||
<property name="group">plain_toggle</property>
|
||||
<property name="sensitive" bind-source="styleview" bind-property="has-styles" bind-flags="sync-create"/>
|
||||
<signal name="toggled" handler="update_view"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="glyphs_toggle">
|
||||
<property name="label">Glyphs</property>
|
||||
<property name="group">plain_toggle</property>
|
||||
<signal name="toggled" handler="update_view"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="info_toggle">
|
||||
<property name="label">Info</property>
|
||||
<property name="group">plain_toggle</property>
|
||||
<signal name="toggled" handler="update_view"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkMenuButton" id="gear_menu_button">
|
||||
<property name="focus-on-click">0</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="menu-model">gear_menu</property>
|
||||
<property name="icon-name">open-menu-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkToggleButton" id="edit_toggle">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="icon-name">document-edit-symbolic</property>
|
||||
<property name="tooltip-text" translatable="yes">Edit the sample</property>
|
||||
<signal name="toggled" handler="update_view"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<style>
|
||||
<class name="sidebar"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkFontButton" id="fontbutton">
|
||||
<property name="level">family|style</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="path">
|
||||
<property name="visible">0</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="FontControls" id="controls">
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="SampleChooser" id="samplechooser"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="FontVariations" id="variations">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="FontFeatures" id="features">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
<property name="language" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="FontColors" id="colors">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="hexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">plain</property>
|
||||
<property name="child">
|
||||
<object class="PlainView">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
<property name="size" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="letterspacing" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="line-height" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="foreground" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="background" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="sample-text" bind-source="sampleeditor" bind-flags="sync-create"/>
|
||||
<property name="features" bind-source="features" bind-flags="sync-create"/>
|
||||
<property name="variations" bind-source="variations" bind-flags="sync-create"/>
|
||||
<property name="palette" bind-source="colors" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">waterfall</property>
|
||||
<property name="child">
|
||||
<object class="WaterfallView">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
<property name="size" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="letterspacing" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="line-height" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="foreground" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="background" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="sample-text" bind-source="sampleeditor" bind-flags="sync-create"/>
|
||||
<property name="features" bind-source="features" bind-flags="sync-create"/>
|
||||
<property name="variations" bind-source="variations" bind-flags="sync-create"/>
|
||||
<property name="palette" bind-source="colors" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">style</property>
|
||||
<property name="child">
|
||||
<object class="StyleView" id="styleview">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
<property name="size" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="letterspacing" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="line-height" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="foreground" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="background" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="sample-text" bind-source="sampleeditor" bind-flags="sync-create"/>
|
||||
<property name="features" bind-source="features" bind-flags="sync-create"/>
|
||||
<property name="variations" bind-source="variations" bind-flags="sync-create"/>
|
||||
<property name="palette" bind-source="colors" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">glyphs</property>
|
||||
<property name="child">
|
||||
<object class="GlyphsView">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
<property name="variations" bind-source="variations" bind-flags="sync-create"/>
|
||||
<property name="palette" bind-source="colors" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">info</property>
|
||||
<property name="child">
|
||||
<object class="InfoView">
|
||||
<property name="font-map" bind-source="FontExplorerWindow" bind-flags="sync-create"/>
|
||||
<property name="font-desc" bind-source="fontbutton" bind-flags="sync-create"/>
|
||||
<property name="size" bind-source="controls" bind-flags="sync-create"/>
|
||||
<property name="variations" bind-source="variations" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">edit</property>
|
||||
<property name="child">
|
||||
<object class="SampleEditor" id="sampleeditor">
|
||||
<property name="sample-text" bind-source="samplechooser" bind-flags="sync-create"/>
|
||||
<property name="editing" bind-source="edit_toggle" bind-property="active" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
744
demos/font-explorer/fontfeatures.c
Normal file
@@ -0,0 +1,744 @@
|
||||
#include "fontfeatures.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "open-type-layout.h"
|
||||
#include "language-names.h"
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
PROP_LANGUAGE,
|
||||
PROP_FEATURES,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
typedef struct {
|
||||
unsigned int tag;
|
||||
const char *name;
|
||||
GtkWidget *feat;
|
||||
} FeatureItem;
|
||||
|
||||
struct _FontFeatures
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GtkGrid *label;
|
||||
GtkGrid *grid;
|
||||
Pango2FontDescription *font_desc;
|
||||
GSimpleAction *reset_action;
|
||||
Pango2Language *lang;
|
||||
GList *feature_items;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
};
|
||||
|
||||
struct _FontFeaturesClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FontFeatures, font_features, GTK_TYPE_WIDGET);
|
||||
|
||||
static Pango2Font *
|
||||
get_font (FontFeatures *self)
|
||||
{
|
||||
Pango2Context *context;
|
||||
Pango2Font *font;
|
||||
|
||||
context = pango2_context_new_with_font_map (self->font_map);
|
||||
font = pango2_context_load_font (context, self->font_desc);
|
||||
g_object_unref (context);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_ssNN (const char *buf)
|
||||
{
|
||||
return g_str_has_prefix (buf, "ss") && g_ascii_isdigit (buf[2]) && g_ascii_isdigit (buf[3]);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_cvNN (const char *buf)
|
||||
{
|
||||
return g_str_has_prefix (buf, "cv") && g_ascii_isdigit (buf[2]) && g_ascii_isdigit (buf[3]);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_feature_display_name (unsigned int tag)
|
||||
{
|
||||
int i;
|
||||
static char buf[5] = { 0, };
|
||||
|
||||
if (tag == HB_TAG ('x', 'x', 'x', 'x'))
|
||||
return g_strdup (_("Default"));
|
||||
|
||||
hb_tag_to_string (tag, buf);
|
||||
if (is_ssNN (buf))
|
||||
{
|
||||
int num = (buf[2] - '0') * 10 + (buf[3] - '0');
|
||||
return g_strdup_printf (g_dpgettext2 (NULL, "OpenType layout", "Stylistic Set %d"), num);
|
||||
}
|
||||
else if (is_cvNN (buf))
|
||||
{
|
||||
int num = (buf[2] - '0') * 10 + (buf[3] - '0');
|
||||
return g_strdup_printf (g_dpgettext2 (NULL, "OpenType layout", "Character Variant %d"), num);
|
||||
}
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (open_type_layout_features); i++)
|
||||
{
|
||||
if (tag == open_type_layout_features[i].tag)
|
||||
return g_strdup (g_dpgettext2 (NULL, "OpenType layout", open_type_layout_features[i].name));
|
||||
}
|
||||
|
||||
g_warning ("unknown OpenType layout feature tag: %s", buf);
|
||||
|
||||
return g_strdup (buf);
|
||||
}
|
||||
|
||||
static void
|
||||
update_feature_label (FontFeatures *self,
|
||||
FeatureItem *item,
|
||||
hb_font_t *hb_font,
|
||||
hb_tag_t script_tag,
|
||||
hb_tag_t lang_tag)
|
||||
{
|
||||
hb_face_t *hb_face;
|
||||
unsigned int script_index, lang_index, feature_index;
|
||||
hb_ot_name_id_t id;
|
||||
unsigned int len;
|
||||
char *label;
|
||||
char name[5] = { 0, };
|
||||
|
||||
hb_face = hb_font_get_face (hb_font);
|
||||
|
||||
hb_tag_to_string (item->tag, name);
|
||||
if (!is_ssNN (name) && !is_cvNN (name))
|
||||
return;
|
||||
|
||||
hb_ot_layout_table_find_script (hb_face, HB_OT_TAG_GSUB, script_tag, &script_index);
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
hb_ot_layout_script_find_language (hb_face, HB_OT_TAG_GSUB, script_index, lang_tag, &lang_index);
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
if (hb_ot_layout_language_find_feature (hb_face, HB_OT_TAG_GSUB, script_index, lang_index, item->tag, &feature_index) &&
|
||||
hb_ot_layout_feature_get_name_ids (hb_face, HB_OT_TAG_GSUB, feature_index, &id, NULL, NULL, NULL, NULL))
|
||||
{
|
||||
len = hb_ot_name_get_utf8 (hb_face, id, HB_LANGUAGE_INVALID, NULL, NULL);
|
||||
len++;
|
||||
label = g_new (char, len);
|
||||
hb_ot_name_get_utf8 (hb_face, id, HB_LANGUAGE_INVALID, &len, label);
|
||||
|
||||
gtk_check_button_set_label (GTK_CHECK_BUTTON (item->feat), label);
|
||||
|
||||
g_free (label);
|
||||
}
|
||||
else
|
||||
{
|
||||
label = get_feature_display_name (item->tag);
|
||||
gtk_check_button_set_label (GTK_CHECK_BUTTON (item->feat), label);
|
||||
g_free (label);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_inconsistent (GtkCheckButton *button,
|
||||
gboolean inconsistent)
|
||||
{
|
||||
gtk_check_button_set_inconsistent (GTK_CHECK_BUTTON (button), inconsistent);
|
||||
gtk_widget_set_opacity (gtk_widget_get_first_child (GTK_WIDGET (button)), inconsistent ? 0.0 : 1.0);
|
||||
}
|
||||
|
||||
static void
|
||||
find_language_and_script (FontFeatures *self,
|
||||
hb_face_t *hb_face,
|
||||
hb_tag_t *lang_tag,
|
||||
hb_tag_t *script_tag)
|
||||
{
|
||||
int i, j, k;
|
||||
hb_tag_t scripts[80];
|
||||
unsigned int n_scripts;
|
||||
unsigned int count;
|
||||
hb_tag_t table[2] = { HB_OT_TAG_GSUB, HB_OT_TAG_GPOS };
|
||||
hb_language_t lang;
|
||||
const char *langname, *p;
|
||||
|
||||
langname = pango2_language_to_string (self->lang);
|
||||
|
||||
p = strchr (langname, '-');
|
||||
lang = hb_language_from_string (langname, p ? p - langname : -1);
|
||||
|
||||
n_scripts = 0;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
count = G_N_ELEMENTS (scripts);
|
||||
hb_ot_layout_table_get_script_tags (hb_face, table[i], n_scripts, &count, scripts);
|
||||
n_scripts += count;
|
||||
}
|
||||
|
||||
for (j = 0; j < n_scripts; j++)
|
||||
{
|
||||
hb_tag_t languages[80];
|
||||
unsigned int n_languages;
|
||||
|
||||
n_languages = 0;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
count = G_N_ELEMENTS (languages);
|
||||
hb_ot_layout_script_get_language_tags (hb_face, table[i], j, n_languages, &count, languages);
|
||||
n_languages += count;
|
||||
}
|
||||
|
||||
for (k = 0; k < n_languages; k++)
|
||||
{
|
||||
if (lang == hb_ot_tag_to_language (languages[k]))
|
||||
{
|
||||
*script_tag = scripts[j];
|
||||
*lang_tag = languages[k];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*lang_tag = HB_OT_TAG_DEFAULT_LANGUAGE;
|
||||
*script_tag = HB_OT_TAG_DEFAULT_SCRIPT;
|
||||
}
|
||||
|
||||
static void
|
||||
hide_feature_maybe (FeatureItem *item,
|
||||
gboolean has_feature)
|
||||
{
|
||||
gtk_widget_set_visible (item->feat, has_feature);
|
||||
if (has_feature)
|
||||
gtk_widget_set_visible (gtk_widget_get_parent (item->feat), TRUE);
|
||||
}
|
||||
|
||||
/* Make features insensitive if the font/langsys does not have them,
|
||||
* and reset all others to their initial value
|
||||
*/
|
||||
static void
|
||||
update_features (FontFeatures *self)
|
||||
{
|
||||
guint script_index, lang_index;
|
||||
hb_tag_t lang_tag;
|
||||
hb_tag_t script_tag;
|
||||
Pango2Font *font;
|
||||
hb_font_t *hb_font;
|
||||
hb_face_t *hb_face;
|
||||
|
||||
font = get_font (self);
|
||||
hb_font = pango2_font_get_hb_font (font);
|
||||
hb_face = hb_font_get_face (hb_font);
|
||||
|
||||
{
|
||||
hb_tag_t table[2] = { HB_OT_TAG_GSUB, HB_OT_TAG_GPOS };
|
||||
hb_tag_t features[256];
|
||||
unsigned int count;
|
||||
unsigned int n_features = 0;
|
||||
|
||||
find_language_and_script (self, hb_face, &lang_tag, &script_tag);
|
||||
|
||||
/* Collect all features */
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
hb_ot_layout_table_find_script (hb_face,
|
||||
table[i],
|
||||
script_tag,
|
||||
&script_index);
|
||||
hb_ot_layout_script_select_language (hb_face,
|
||||
table[i],
|
||||
script_index,
|
||||
1,
|
||||
&lang_tag,
|
||||
&lang_index);
|
||||
|
||||
count = G_N_ELEMENTS (features);
|
||||
hb_ot_layout_language_get_feature_tags (hb_face,
|
||||
table[i],
|
||||
script_index,
|
||||
lang_index,
|
||||
n_features,
|
||||
&count,
|
||||
features);
|
||||
n_features += count;
|
||||
}
|
||||
|
||||
/* Update all the features */
|
||||
for (GList *l = self->feature_items; l; l = l->next)
|
||||
{
|
||||
FeatureItem *item = l->data;
|
||||
gboolean has_feature = FALSE;
|
||||
|
||||
for (int j = 0; j < n_features; j++)
|
||||
{
|
||||
if (item->tag == features[j])
|
||||
{
|
||||
has_feature = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
update_feature_label (self, item, hb_font, script_tag, lang_tag);
|
||||
|
||||
hide_feature_maybe (item, has_feature);
|
||||
|
||||
if (GTK_IS_CHECK_BUTTON (item->feat))
|
||||
{
|
||||
GtkWidget *def = GTK_WIDGET (g_object_get_data (G_OBJECT (item->feat), "default"));
|
||||
if (def)
|
||||
{
|
||||
gtk_widget_show (def);
|
||||
gtk_widget_show (gtk_widget_get_parent (def));
|
||||
gtk_check_button_set_active (GTK_CHECK_BUTTON (def), TRUE);
|
||||
}
|
||||
else
|
||||
set_inconsistent (GTK_CHECK_BUTTON (item->feat), TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide empty groups */
|
||||
for (GList *l = self->feature_items; l; l = l->next)
|
||||
{
|
||||
FeatureItem *item = l->data;
|
||||
GtkWidget *box;
|
||||
|
||||
box = gtk_widget_get_parent (item->feat);
|
||||
if (gtk_widget_get_visible (box))
|
||||
{
|
||||
GtkWidget *c;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
for (c = gtk_widget_get_first_child (box); c; c = gtk_widget_get_next_sibling (c))
|
||||
{
|
||||
if (gtk_widget_get_visible (c))
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 1)
|
||||
gtk_widget_hide (box);
|
||||
else if (count == 2 &&
|
||||
item->tag == HB_TAG ('x', 'x', 'x', 'x'))
|
||||
gtk_widget_hide (box);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
script_changed (GtkComboBox *combo,
|
||||
FontFeatures *self)
|
||||
{
|
||||
update_features (self);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_features (FontFeatures *self)
|
||||
{
|
||||
GString *s;
|
||||
char buf[128];
|
||||
|
||||
s = g_string_new ("");
|
||||
|
||||
for (GList *l = self->feature_items; l; l = l->next)
|
||||
{
|
||||
FeatureItem *item = l->data;
|
||||
|
||||
if (!gtk_widget_is_sensitive (item->feat))
|
||||
continue;
|
||||
|
||||
if (GTK_IS_CHECK_BUTTON (item->feat) && g_object_get_data (G_OBJECT (item->feat), "default"))
|
||||
{
|
||||
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (item->feat)) &&
|
||||
item->tag != HB_TAG ('x', 'x', 'x', 'x'))
|
||||
{
|
||||
hb_feature_to_string (&(hb_feature_t) { item->tag, 1, 0, -1 }, buf, sizeof (buf));
|
||||
if (s->len > 0)
|
||||
g_string_append_c (s, ',');
|
||||
g_string_append (s, buf);
|
||||
}
|
||||
}
|
||||
else if (GTK_IS_CHECK_BUTTON (item->feat))
|
||||
{
|
||||
guint32 value;
|
||||
|
||||
if (gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (item->feat)))
|
||||
continue;
|
||||
|
||||
value = gtk_check_button_get_active (GTK_CHECK_BUTTON (item->feat));
|
||||
hb_feature_to_string (&(hb_feature_t) { item->tag, value, 0, -1 }, buf, sizeof (buf));
|
||||
if (s->len > 0)
|
||||
g_string_append_c (s, ',');
|
||||
g_string_append (s, buf);
|
||||
}
|
||||
}
|
||||
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
update_display (FontFeatures *self)
|
||||
{
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FEATURES]);
|
||||
g_simple_action_set_enabled (self->reset_action, TRUE);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
make_title_label (const char *title)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new (title);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
||||
g_object_set (label, "margin-top", 10, "margin-bottom", 10, NULL);
|
||||
gtk_widget_add_css_class (label, "heading");
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
static void
|
||||
feat_toggled_cb (GtkCheckButton *check_button,
|
||||
gpointer data)
|
||||
{
|
||||
set_inconsistent (check_button, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
feat_pressed (GtkGestureClick *gesture,
|
||||
int n_press,
|
||||
double x,
|
||||
double y,
|
||||
GtkWidget *feat)
|
||||
{
|
||||
const guint button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
|
||||
|
||||
if (button == GDK_BUTTON_PRIMARY)
|
||||
{
|
||||
g_signal_handlers_block_by_func (feat, feat_pressed, NULL);
|
||||
|
||||
if (gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (feat)))
|
||||
{
|
||||
set_inconsistent (GTK_CHECK_BUTTON (feat), FALSE);
|
||||
gtk_check_button_set_active (GTK_CHECK_BUTTON (feat), TRUE);
|
||||
}
|
||||
|
||||
g_signal_handlers_unblock_by_func (feat, feat_pressed, NULL);
|
||||
}
|
||||
else if (button == GDK_BUTTON_SECONDARY)
|
||||
{
|
||||
gboolean inconsistent = gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (feat));
|
||||
set_inconsistent (GTK_CHECK_BUTTON (feat), !inconsistent);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_check_group (FontFeatures *self,
|
||||
const char *title,
|
||||
const char **tags,
|
||||
unsigned int n_tags,
|
||||
int row)
|
||||
{
|
||||
GtkWidget *group;
|
||||
int i;
|
||||
|
||||
group = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_halign (group, GTK_ALIGN_START);
|
||||
|
||||
gtk_box_append (GTK_BOX (group), make_title_label (title));
|
||||
|
||||
for (i = 0; i < n_tags; i++)
|
||||
{
|
||||
unsigned int tag;
|
||||
GtkWidget *feat;
|
||||
FeatureItem *item;
|
||||
GtkGesture *gesture;
|
||||
char *name;
|
||||
|
||||
tag = hb_tag_from_string (tags[i], -1);
|
||||
|
||||
name = get_feature_display_name (tag);
|
||||
feat = gtk_check_button_new_with_label (name);
|
||||
g_free (name);
|
||||
set_inconsistent (GTK_CHECK_BUTTON (feat), TRUE);
|
||||
g_signal_connect_swapped (feat, "notify::active", G_CALLBACK (update_display), self);
|
||||
g_signal_connect_swapped (feat, "notify::inconsistent", G_CALLBACK (update_display), self);
|
||||
g_signal_connect (feat, "toggled", G_CALLBACK (feat_toggled_cb), NULL);
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
|
||||
g_signal_connect (gesture, "pressed", G_CALLBACK (feat_pressed), feat);
|
||||
gtk_widget_add_controller (feat, GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
gtk_box_append (GTK_BOX (group), feat);
|
||||
|
||||
item = g_new (FeatureItem, 1);
|
||||
item->name = tags[i];
|
||||
item->tag = tag;
|
||||
item->feat = feat;
|
||||
|
||||
self->feature_items = g_list_prepend (self->feature_items, item);
|
||||
}
|
||||
|
||||
gtk_grid_attach (self->grid, group, 0, row, 2, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
add_radio_group (FontFeatures *self,
|
||||
const char *title,
|
||||
const char **tags,
|
||||
unsigned int n_tags,
|
||||
int row)
|
||||
{
|
||||
GtkWidget *group;
|
||||
int i;
|
||||
GtkWidget *group_button = NULL;
|
||||
|
||||
group = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_widget_set_halign (group, GTK_ALIGN_START);
|
||||
|
||||
gtk_box_append (GTK_BOX (group), make_title_label (title));
|
||||
|
||||
for (i = 0; i < n_tags; i++)
|
||||
{
|
||||
unsigned int tag;
|
||||
GtkWidget *feat;
|
||||
FeatureItem *item;
|
||||
char *name;
|
||||
|
||||
tag = hb_tag_from_string (tags[i], -1);
|
||||
name = get_feature_display_name (tag);
|
||||
feat = gtk_check_button_new_with_label (name ? name : _("Default"));
|
||||
g_free (name);
|
||||
if (group_button == NULL)
|
||||
group_button = feat;
|
||||
else
|
||||
gtk_check_button_set_group (GTK_CHECK_BUTTON (feat), GTK_CHECK_BUTTON (group_button));
|
||||
g_signal_connect_swapped (feat, "notify::active", G_CALLBACK (update_display), self);
|
||||
g_object_set_data (G_OBJECT (feat), "default", group_button);
|
||||
|
||||
gtk_box_append (GTK_BOX (group), feat);
|
||||
|
||||
item = g_new (FeatureItem, 1);
|
||||
item->name = tags[i];
|
||||
item->tag = tag;
|
||||
item->feat = feat;
|
||||
|
||||
self->feature_items = g_list_prepend (self->feature_items, item);
|
||||
}
|
||||
|
||||
gtk_grid_attach (self->grid, group, 0, row, 2, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_features (FontFeatures *self)
|
||||
{
|
||||
const char *kerning[] = { "kern" };
|
||||
const char *ligatures[] = { "liga", "dlig", "hlig", "clig", "rlig" };
|
||||
const char *letter_case[] = {
|
||||
"smcp", "c2sc", "pcap", "c2pc", "unic", "cpsp", "case"
|
||||
};
|
||||
const char *number_case[] = { "xxxx", "lnum", "onum" };
|
||||
const char *number_spacing[] = { "xxxx", "pnum", "tnum" };
|
||||
const char *fractions[] = { "xxxx", "frac", "afrc" };
|
||||
const char *num_extras[] = { "zero", "nalt", "sinf" };
|
||||
const char *char_alt[] = {
|
||||
"swsh", "cswh", "locl", "calt", "falt", "hist",
|
||||
"salt", "jalt", "titl", "rand", "subs", "sups",
|
||||
"ordn", "ltra", "ltrm", "rtla", "rtlm", "rclt"
|
||||
};
|
||||
const char *pos_alt[] = {
|
||||
"init", "medi", "med2", "fina", "fin2", "fin3", "isol"
|
||||
};
|
||||
const char *width_var[] = {
|
||||
"fwid", "hwid", "halt", "pwid", "palt", "twid", "qwid"
|
||||
};
|
||||
const char *style_alt[] = {
|
||||
"ss01", "ss02", "ss03", "ss04", "ss05", "ss06",
|
||||
"ss07", "ss08", "ss09", "ss10", "ss11", "ss12",
|
||||
"ss13", "ss14", "ss15", "ss16", "ss17", "ss18",
|
||||
"ss19", "ss20"
|
||||
};
|
||||
const char *char_var[] = {
|
||||
"cv01", "cv02", "cv03", "cv04", "cv05", "cv06",
|
||||
"cv07", "cv08", "cv09", "cv10", "cv11", "cv12",
|
||||
"cv13", "cv14", "cv15", "cv16", "cv17", "cv18",
|
||||
"cv19", "cv20"
|
||||
};
|
||||
const char *math[] = { "dtls", "flac", "mgrk", "ssty" };
|
||||
const char *bounds[] = { "opbd", "lfbd", "rtbd" };
|
||||
int row = 0;
|
||||
|
||||
add_check_group (self, _("Kerning"), kerning, G_N_ELEMENTS (kerning), row++);
|
||||
add_check_group (self, _("Ligatures"), ligatures, G_N_ELEMENTS (ligatures), row++);
|
||||
add_check_group (self, _("Letter Case"), letter_case, G_N_ELEMENTS (letter_case), row++);
|
||||
add_radio_group (self, _("Number Case"), number_case, G_N_ELEMENTS (number_case), row++);
|
||||
add_radio_group (self, _("Number Spacing"), number_spacing, G_N_ELEMENTS (number_spacing), row++);
|
||||
add_radio_group (self, _("Fractions"), fractions, G_N_ELEMENTS (fractions), row++);
|
||||
add_check_group (self, _("Numeric Extras"), num_extras, G_N_ELEMENTS (num_extras), row++);
|
||||
add_check_group (self, _("Character Alternatives"), char_alt, G_N_ELEMENTS (char_alt), row++);
|
||||
add_check_group (self, _("Positional Alternatives"), pos_alt, G_N_ELEMENTS (pos_alt), row++);
|
||||
add_check_group (self, _("Width Variants"), width_var, G_N_ELEMENTS (width_var), row++);
|
||||
add_check_group (self, _("Alternative Stylistic Sets"), style_alt, G_N_ELEMENTS (style_alt), row++);
|
||||
add_check_group (self, _("Character Variants"), char_var, G_N_ELEMENTS (char_var), row++);
|
||||
add_check_group (self, _("Mathematical"), math, G_N_ELEMENTS (math), row++);
|
||||
add_check_group (self, _("Optical Bounds"), bounds, G_N_ELEMENTS (bounds), row++);
|
||||
|
||||
self->feature_items = g_list_reverse (self->feature_items);
|
||||
}
|
||||
|
||||
static void
|
||||
reset (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
FontFeatures *self)
|
||||
{
|
||||
update_features (self);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FEATURES]);
|
||||
g_simple_action_set_enabled (self->reset_action, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
font_features_init (FontFeatures *self)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
self->font_desc = pango2_font_description_from_string ("sans 12");
|
||||
self->lang = pango2_language_get_default ();
|
||||
|
||||
setup_features (self);
|
||||
|
||||
self->reset_action = g_simple_action_new ("reset", NULL);
|
||||
g_simple_action_set_enabled (self->reset_action, FALSE);
|
||||
g_signal_connect (self->reset_action, "activate", G_CALLBACK (reset), self);
|
||||
}
|
||||
|
||||
static void
|
||||
font_features_dispose (GObject *object)
|
||||
{
|
||||
FontFeatures *self = FONT_FEATURES (object);
|
||||
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), FONT_FEATURES_TYPE);
|
||||
|
||||
g_list_free_full (self->feature_items, g_free);
|
||||
|
||||
G_OBJECT_CLASS (font_features_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
font_features_finalize (GObject *object)
|
||||
{
|
||||
FontFeatures *self = FONT_FEATURES (object);
|
||||
|
||||
g_clear_pointer (&self->font_desc, pango2_font_description_free);
|
||||
g_clear_object (&self->font_map);
|
||||
|
||||
G_OBJECT_CLASS (font_features_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
font_features_set_property (GObject *object,
|
||||
unsigned int prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FontFeatures *self = FONT_FEATURES (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
pango2_font_description_free (self->font_desc);
|
||||
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_LANGUAGE:
|
||||
self->lang = pango2_language_from_string (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_features (self);
|
||||
}
|
||||
|
||||
static void
|
||||
font_features_get_property (GObject *object,
|
||||
unsigned int prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FontFeatures *self = FONT_FEATURES (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
case PROP_FEATURES:
|
||||
g_value_take_string (value, get_features (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
font_features_class_init (FontFeaturesClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = font_features_dispose;
|
||||
object_class->finalize = font_features_finalize;
|
||||
object_class->get_property = font_features_get_property;
|
||||
object_class->set_property = font_features_set_property;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FONT_DESC] =
|
||||
g_param_spec_boxed ("font-desc", "", "",
|
||||
PANGO2_TYPE_FONT_DESCRIPTION,
|
||||
G_PARAM_WRITABLE);
|
||||
|
||||
properties[PROP_LANGUAGE] =
|
||||
g_param_spec_string ("language", "", "",
|
||||
"en",
|
||||
G_PARAM_WRITABLE);
|
||||
|
||||
properties[PROP_FEATURES] =
|
||||
g_param_spec_string ("features", "", "",
|
||||
"",
|
||||
G_PARAM_READABLE);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/fontfeatures.ui");
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontFeatures, grid);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontFeatures, label);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), script_changed);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontfeatures");
|
||||
}
|
||||
|
||||
GAction *
|
||||
font_features_get_reset_action (FontFeatures *self)
|
||||
{
|
||||
return G_ACTION (self->reset_action);
|
||||
}
|
15
demos/font-explorer/fontfeatures.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define FONT_FEATURES_TYPE (font_features_get_type ())
|
||||
#define FONT_FEATURES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_FEATURES_TYPE, FontFeatures))
|
||||
|
||||
|
||||
typedef struct _FontFeatures FontFeatures;
|
||||
typedef struct _FontFeaturesClass FontFeaturesClass;
|
||||
|
||||
|
||||
GType font_features_get_type (void);
|
||||
GAction * font_features_get_reset_action (FontFeatures *self);
|
25
demos/font-explorer/fontfeatures.ui
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="FontFeatures" parent="GtkWidget">
|
||||
<property name="layout-manager"><object class="GtkBinLayout"/></property>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid">
|
||||
<child>
|
||||
<object class="GtkLabel" id="label">
|
||||
<property name="label" translatable="yes">Features</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="xalign">0</property>
|
||||
<style>
|
||||
<class name="heading"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="row">-1</property>
|
||||
<property name="column">0</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
508
demos/font-explorer/fontvariations.c
Normal file
@@ -0,0 +1,508 @@
|
||||
#include "fontvariations.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "rangeedit.h"
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
PROP_VARIATIONS,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _FontVariations
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GtkGrid *label;
|
||||
GtkGrid *grid;
|
||||
Pango2FontDescription *font_desc;
|
||||
GSimpleAction *reset_action;
|
||||
gboolean has_variations;
|
||||
|
||||
GtkWidget *instance_combo;
|
||||
GHashTable *axes;
|
||||
GHashTable *instances;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
};
|
||||
|
||||
struct _FontVariationsClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FontVariations, font_variations, GTK_TYPE_WIDGET);
|
||||
|
||||
static Pango2Font *
|
||||
get_font (FontVariations *self)
|
||||
{
|
||||
Pango2Context *context;
|
||||
Pango2Font *font;
|
||||
|
||||
context = pango2_context_new_with_font_map (self->font_map);
|
||||
font = pango2_context_load_font (context, self->font_desc);
|
||||
g_object_unref (context);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
guint32 tag;
|
||||
GtkAdjustment *adjustment;
|
||||
double default_value;
|
||||
} Axis;
|
||||
|
||||
static guint
|
||||
axes_hash (gconstpointer v)
|
||||
{
|
||||
const Axis *p = v;
|
||||
|
||||
return p->tag;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
axes_equal (gconstpointer v1, gconstpointer v2)
|
||||
{
|
||||
const Axis *p1 = v1;
|
||||
const Axis *p2 = v2;
|
||||
|
||||
return p1->tag == p2->tag;
|
||||
}
|
||||
|
||||
static void
|
||||
unset_instance (GtkAdjustment *adjustment,
|
||||
FontVariations *self)
|
||||
{
|
||||
if (self->instance_combo)
|
||||
gtk_combo_box_set_active (GTK_COMBO_BOX (self->instance_combo), 0);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VARIATIONS]);
|
||||
g_simple_action_set_enabled (self->reset_action, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
add_axis (FontVariations *self,
|
||||
hb_face_t *hb_face,
|
||||
hb_ot_var_axis_info_t *ax,
|
||||
int i)
|
||||
{
|
||||
GtkWidget *axis_label;
|
||||
GtkWidget *axis_scale;
|
||||
GtkAdjustment *adjustment;
|
||||
Axis *axis;
|
||||
char name[20];
|
||||
unsigned int name_len = 20;
|
||||
|
||||
hb_ot_name_get_utf8 (hb_face, ax->name_id, HB_LANGUAGE_INVALID, &name_len, name);
|
||||
|
||||
axis_label = gtk_label_new (name);
|
||||
gtk_widget_set_halign (axis_label, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (axis_label, GTK_ALIGN_BASELINE);
|
||||
gtk_grid_attach (self->grid, axis_label, 0, i, 1, 1);
|
||||
adjustment = gtk_adjustment_new (ax->default_value, ax->min_value, ax->max_value,
|
||||
1.0, 10.0, 0.0);
|
||||
axis_scale = g_object_new (RANGE_EDIT_TYPE,
|
||||
"adjustment", adjustment,
|
||||
"default-value", ax->default_value,
|
||||
"n-chars", 5,
|
||||
"hexpand", TRUE,
|
||||
"halign", GTK_ALIGN_FILL,
|
||||
"valign", GTK_ALIGN_BASELINE,
|
||||
NULL);
|
||||
gtk_grid_attach (self->grid, axis_scale, 1, i, 1, 1);
|
||||
|
||||
axis = g_new0 (Axis, 1);
|
||||
axis->tag = ax->tag;
|
||||
axis->adjustment = adjustment;
|
||||
axis->default_value = ax->default_value;
|
||||
g_hash_table_add (self->axes, axis);
|
||||
|
||||
g_signal_connect (adjustment, "value-changed", G_CALLBACK (unset_instance), self);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
unsigned int index;
|
||||
} Instance;
|
||||
|
||||
static guint
|
||||
instance_hash (gconstpointer v)
|
||||
{
|
||||
const Instance *p = v;
|
||||
|
||||
return g_str_hash (p->name);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
instance_equal (gconstpointer v1, gconstpointer v2)
|
||||
{
|
||||
const Instance *p1 = v1;
|
||||
const Instance *p2 = v2;
|
||||
|
||||
return g_str_equal (p1->name, p2->name);
|
||||
}
|
||||
|
||||
static void
|
||||
free_instance (gpointer data)
|
||||
{
|
||||
Instance *instance = data;
|
||||
|
||||
g_free (instance->name);
|
||||
g_free (instance);
|
||||
}
|
||||
|
||||
static void
|
||||
add_instance (FontVariations *self,
|
||||
hb_face_t *face,
|
||||
unsigned int index,
|
||||
GtkWidget *combo,
|
||||
int pos)
|
||||
{
|
||||
Instance *instance;
|
||||
hb_ot_name_id_t name_id;
|
||||
char name[20];
|
||||
unsigned int name_len = 20;
|
||||
|
||||
instance = g_new0 (Instance, 1);
|
||||
|
||||
name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, index);
|
||||
hb_ot_name_get_utf8 (face, name_id, HB_LANGUAGE_INVALID, &name_len, name);
|
||||
|
||||
instance->name = g_strdup (name);
|
||||
instance->index = index;
|
||||
|
||||
g_hash_table_add (self->instances, instance);
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), instance->name);
|
||||
}
|
||||
|
||||
static void
|
||||
instance_changed (GtkComboBox *combo,
|
||||
FontVariations *self)
|
||||
{
|
||||
char *text;
|
||||
Instance *instance;
|
||||
Instance ikey;
|
||||
int i;
|
||||
unsigned int coords_length;
|
||||
float *coords = NULL;
|
||||
hb_ot_var_axis_info_t *ai = NULL;
|
||||
unsigned int n_axes;
|
||||
Pango2Font *font = NULL;
|
||||
hb_font_t *hb_font;
|
||||
hb_face_t *hb_face;
|
||||
|
||||
text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (combo));
|
||||
if (text[0] == '\0')
|
||||
goto out;
|
||||
|
||||
ikey.name = text;
|
||||
instance = g_hash_table_lookup (self->instances, &ikey);
|
||||
if (!instance)
|
||||
{
|
||||
g_print ("did not find instance %s\n", text);
|
||||
goto out;
|
||||
}
|
||||
|
||||
font = get_font (self);
|
||||
hb_font = pango2_font_get_hb_font (font);
|
||||
hb_face = hb_font_get_face (hb_font);
|
||||
|
||||
n_axes = hb_ot_var_get_axis_infos (hb_face, 0, NULL, NULL);
|
||||
ai = g_new (hb_ot_var_axis_info_t, n_axes);
|
||||
hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, ai);
|
||||
|
||||
coords = g_new (float, n_axes);
|
||||
hb_ot_var_named_instance_get_design_coords (hb_face,
|
||||
instance->index,
|
||||
&coords_length,
|
||||
coords);
|
||||
|
||||
for (i = 0; i < n_axes; i++)
|
||||
{
|
||||
Axis *axis;
|
||||
Axis akey;
|
||||
double value;
|
||||
|
||||
value = coords[ai[i].axis_index];
|
||||
|
||||
akey.tag = ai[i].tag;
|
||||
axis = g_hash_table_lookup (self->axes, &akey);
|
||||
if (axis)
|
||||
{
|
||||
g_signal_handlers_block_by_func (axis->adjustment, unset_instance, self);
|
||||
gtk_adjustment_set_value (axis->adjustment, value);
|
||||
g_signal_handlers_unblock_by_func (axis->adjustment, unset_instance, self);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VARIATIONS]);
|
||||
g_simple_action_set_enabled (self->reset_action, TRUE);
|
||||
|
||||
out:
|
||||
g_free (text);
|
||||
g_clear_object (&font);
|
||||
g_free (ai);
|
||||
g_free (coords);
|
||||
}
|
||||
|
||||
static void
|
||||
update_variations (FontVariations *self)
|
||||
{
|
||||
GtkWidget *child;
|
||||
Pango2Font *font;
|
||||
hb_font_t *hb_font;
|
||||
hb_face_t *hb_face;
|
||||
unsigned int n_axes;
|
||||
hb_ot_var_axis_info_t *ai = NULL;
|
||||
int i;
|
||||
|
||||
font = get_font (self);
|
||||
hb_font = pango2_font_get_hb_font (font);
|
||||
hb_face = hb_font_get_face (hb_font);
|
||||
|
||||
g_object_ref (self->label);
|
||||
|
||||
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->grid))))
|
||||
gtk_grid_remove (self->grid, child);
|
||||
|
||||
gtk_grid_attach (self->grid, GTK_WIDGET (self->label), 0, -2, 2, 1);
|
||||
g_object_unref (self->label);
|
||||
|
||||
self->instance_combo = NULL;
|
||||
g_hash_table_remove_all (self->axes);
|
||||
g_hash_table_remove_all (self->instances);
|
||||
|
||||
n_axes = hb_ot_var_get_axis_infos (hb_face, 0, NULL, NULL);
|
||||
self->has_variations = n_axes > 0;
|
||||
gtk_widget_set_visible (GTK_WIDGET (self), self->has_variations);
|
||||
if (!self->has_variations)
|
||||
{
|
||||
g_simple_action_set_enabled (self->reset_action, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (hb_ot_var_get_named_instance_count (hb_face) > 0)
|
||||
{
|
||||
GtkWidget *label;
|
||||
GtkWidget *combo;
|
||||
|
||||
label = gtk_label_new ("Instance");
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
|
||||
gtk_grid_attach (self->grid, label, 0, -1, 1, 1);
|
||||
|
||||
combo = gtk_combo_box_text_new ();
|
||||
gtk_widget_set_halign (combo, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (combo, GTK_ALIGN_BASELINE);
|
||||
gtk_widget_set_hexpand (combo, TRUE);
|
||||
|
||||
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "");
|
||||
|
||||
for (i = 0; i < hb_ot_var_get_named_instance_count (hb_face); i++)
|
||||
add_instance (self, hb_face, i, combo, i);
|
||||
|
||||
gtk_grid_attach (GTK_GRID (self->grid), combo, 1, -1, 1, 1);
|
||||
g_signal_connect (combo, "changed", G_CALLBACK (instance_changed), self);
|
||||
self->instance_combo = combo;
|
||||
}
|
||||
|
||||
ai = g_new (hb_ot_var_axis_info_t, n_axes);
|
||||
hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, ai);
|
||||
for (i = 0; i < n_axes; i++)
|
||||
add_axis (self, hb_face, &ai[i], i);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VARIATIONS]);
|
||||
|
||||
g_clear_object (&font);
|
||||
g_free (ai);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_variations (FontVariations *self)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
Axis *axis;
|
||||
char buf[G_ASCII_DTOSTR_BUF_SIZE];
|
||||
const char *sep = "";
|
||||
GString *s;
|
||||
|
||||
if (!self->has_variations)
|
||||
return g_strdup ("");
|
||||
|
||||
s = g_string_new ("");
|
||||
|
||||
g_hash_table_iter_init (&iter, self->axes);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *)NULL, (gpointer *)&axis))
|
||||
{
|
||||
char tag[5];
|
||||
double value;
|
||||
|
||||
hb_tag_to_string (axis->tag, tag);
|
||||
tag[4] = '\0';
|
||||
value = gtk_adjustment_get_value (axis->adjustment);
|
||||
|
||||
g_string_append_printf (s, "%s%s=%s", sep, tag, g_ascii_dtostr (buf, sizeof (buf), value));
|
||||
sep = ",";
|
||||
}
|
||||
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
reset (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
FontVariations *self)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
Axis *axis;
|
||||
|
||||
if (self->instance_combo)
|
||||
gtk_combo_box_set_active (GTK_COMBO_BOX (self->instance_combo), 0);
|
||||
|
||||
g_hash_table_iter_init (&iter, self->axes);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *)NULL, (gpointer *)&axis))
|
||||
{
|
||||
g_signal_handlers_block_by_func (axis->adjustment, unset_instance, self);
|
||||
gtk_adjustment_set_value (axis->adjustment, axis->default_value);
|
||||
g_signal_handlers_unblock_by_func (axis->adjustment, unset_instance, self);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VARIATIONS]);
|
||||
g_simple_action_set_enabled (self->reset_action, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
font_variations_init (FontVariations *self)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
self->reset_action = g_simple_action_new ("reset", NULL);
|
||||
g_simple_action_set_enabled (self->reset_action, FALSE);
|
||||
g_signal_connect (self->reset_action, "activate", G_CALLBACK (reset), self);
|
||||
|
||||
self->instances = g_hash_table_new_full (instance_hash, instance_equal,
|
||||
NULL, free_instance);
|
||||
self->axes = g_hash_table_new_full (axes_hash, axes_equal,
|
||||
NULL, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
font_variations_dispose (GObject *object)
|
||||
{
|
||||
FontVariations *self = FONT_VARIATIONS (object);
|
||||
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), FONT_VARIATIONS_TYPE);
|
||||
|
||||
g_hash_table_unref (self->instances);
|
||||
g_hash_table_unref (self->axes);
|
||||
|
||||
G_OBJECT_CLASS (font_variations_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
font_variations_finalize (GObject *object)
|
||||
{
|
||||
FontVariations *self = FONT_VARIATIONS (object);
|
||||
|
||||
g_clear_pointer (&self->font_desc, pango2_font_description_free);
|
||||
g_clear_object (&self->font_map);
|
||||
|
||||
G_OBJECT_CLASS (font_variations_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
font_variations_set_property (GObject *object,
|
||||
unsigned int prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FontVariations *self = FONT_VARIATIONS (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
pango2_font_description_free (self->font_desc);
|
||||
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_variations (self);
|
||||
}
|
||||
|
||||
static void
|
||||
font_variations_get_property (GObject *object,
|
||||
unsigned int prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FontVariations *self = FONT_VARIATIONS (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
case PROP_VARIATIONS:
|
||||
g_value_take_string (value, get_variations (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
font_variations_class_init (FontVariationsClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = font_variations_dispose;
|
||||
object_class->finalize = font_variations_finalize;
|
||||
object_class->get_property = font_variations_get_property;
|
||||
object_class->set_property = font_variations_set_property;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FONT_DESC] =
|
||||
g_param_spec_boxed ("font-desc", "", "",
|
||||
PANGO2_TYPE_FONT_DESCRIPTION,
|
||||
G_PARAM_WRITABLE);
|
||||
|
||||
properties[PROP_VARIATIONS] =
|
||||
g_param_spec_string ("variations", "", "",
|
||||
"",
|
||||
G_PARAM_READABLE);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/fontvariations.ui");
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontVariations, grid);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), FontVariations, label);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "fontvariations");
|
||||
}
|
||||
|
||||
GAction *
|
||||
font_variations_get_reset_action (FontVariations *self)
|
||||
{
|
||||
return G_ACTION (self->reset_action);
|
||||
}
|
15
demos/font-explorer/fontvariations.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define FONT_VARIATIONS_TYPE (font_variations_get_type ())
|
||||
#define FONT_VARIATIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FONT_VARIATIONS_TYPE, FontVariations))
|
||||
|
||||
|
||||
typedef struct _FontVariations FontVariations;
|
||||
typedef struct _FontVariationsClass FontVariationsClass;
|
||||
|
||||
|
||||
GType font_variations_get_type (void);
|
||||
GAction * font_variations_get_reset_action (FontVariations *self);
|
25
demos/font-explorer/fontvariations.ui
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="FontVariations" parent="GtkWidget">
|
||||
<property name="layout-manager"><object class="GtkBinLayout"/></property>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid">
|
||||
<child>
|
||||
<object class="GtkLabel" id="label">
|
||||
<property name="label" translatable="yes">Variations</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="xalign">0</property>
|
||||
<style>
|
||||
<class name="heading"/>
|
||||
</style>
|
||||
<layout>
|
||||
<property name="row">-2</property>
|
||||
<property name="column">0</property>
|
||||
<property name="column-span">2</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
56
demos/font-explorer/glyphitem.c
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "glyphitem.h"
|
||||
|
||||
struct _GlyphItem {
|
||||
GObject parent;
|
||||
Pango2Font *font;
|
||||
hb_codepoint_t glyph;
|
||||
};
|
||||
|
||||
struct _GlyphItemClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GlyphItem, glyph_item, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
glyph_item_init (GlyphItem *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_item_finalize (GObject *object)
|
||||
{
|
||||
GlyphItem *item = GLYPH_ITEM (object);
|
||||
|
||||
g_object_unref (item->font);
|
||||
|
||||
G_OBJECT_CLASS (glyph_item_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_item_class_init (GlyphItemClass *class)
|
||||
{
|
||||
G_OBJECT_CLASS (class)->finalize = glyph_item_finalize;
|
||||
}
|
||||
|
||||
GlyphItem *
|
||||
glyph_item_new (Pango2Font *font,
|
||||
hb_codepoint_t glyph)
|
||||
{
|
||||
GlyphItem *item = g_object_new (GLYPH_ITEM_TYPE, NULL);
|
||||
item->font = g_object_ref (font);
|
||||
item->glyph = glyph;
|
||||
return item;
|
||||
}
|
||||
|
||||
Pango2Font *
|
||||
glyph_item_get_font (GlyphItem *item)
|
||||
{
|
||||
return item->font;
|
||||
}
|
||||
|
||||
hb_codepoint_t
|
||||
glyph_item_get_glyph (GlyphItem *item)
|
||||
{
|
||||
return item->glyph;
|
||||
}
|
17
demos/font-explorer/glyphitem.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define GLYPH_ITEM_TYPE (glyph_item_get_type ())
|
||||
#define GLYPH_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPH_ITEM_TYPE, GlyphItem))
|
||||
|
||||
|
||||
typedef struct _GlyphItem GlyphItem;
|
||||
typedef struct _GlyphItemClass GlyphItemClass;
|
||||
|
||||
|
||||
GType glyph_item_get_type (void);
|
||||
GlyphItem * glyph_item_new (Pango2Font *font,
|
||||
hb_codepoint_t glyph);
|
||||
hb_codepoint_t glyph_item_get_glyph (GlyphItem *item);
|
||||
Pango2Font * glyph_item_get_font (GlyphItem *item);
|
97
demos/font-explorer/glyphmodel.c
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "glyphmodel.h"
|
||||
|
||||
#include "glyphitem.h"
|
||||
|
||||
struct _GlyphModel {
|
||||
GObject parent;
|
||||
Pango2Font *font;
|
||||
unsigned int num_glyphs;
|
||||
GlyphItem **glyphs;
|
||||
};
|
||||
|
||||
struct _GlyphModelClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static GType
|
||||
glyph_model_get_item_type (GListModel *model)
|
||||
{
|
||||
return GLYPH_ITEM_TYPE;
|
||||
}
|
||||
|
||||
static guint
|
||||
glyph_model_get_n_items (GListModel *model)
|
||||
{
|
||||
GlyphModel *self = GLYPH_MODEL (model);
|
||||
|
||||
return self->num_glyphs;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
glyph_model_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
GlyphModel *self = GLYPH_MODEL (model);
|
||||
|
||||
if (position >= self->num_glyphs)
|
||||
return NULL;
|
||||
|
||||
if (self->glyphs[position] == NULL)
|
||||
self->glyphs[position] = glyph_item_new (self->font, position);
|
||||
|
||||
return g_object_ref (self->glyphs[position]);
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_model_list_model_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = glyph_model_get_item_type;
|
||||
iface->get_n_items = glyph_model_get_n_items;
|
||||
iface->get_item = glyph_model_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GlyphModel, glyph_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, glyph_model_list_model_init))
|
||||
|
||||
static void
|
||||
glyph_model_init (GlyphModel *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_model_finalize (GObject *object)
|
||||
{
|
||||
GlyphModel *self = GLYPH_MODEL (object);
|
||||
|
||||
g_object_unref (self->font);
|
||||
for (int i = 0; i < self->num_glyphs; i++)
|
||||
{
|
||||
if (self->glyphs[i])
|
||||
g_object_unref (self->glyphs[i]);
|
||||
}
|
||||
g_free (self->glyphs);
|
||||
|
||||
G_OBJECT_CLASS (glyph_model_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_model_class_init (GlyphModelClass *class)
|
||||
{
|
||||
G_OBJECT_CLASS (class)->finalize = glyph_model_finalize;
|
||||
}
|
||||
|
||||
GlyphModel *
|
||||
glyph_model_new (Pango2Font *font)
|
||||
{
|
||||
GlyphModel *self;
|
||||
hb_face_t *hb_face;
|
||||
|
||||
self = g_object_new (GLYPH_MODEL_TYPE, NULL);
|
||||
|
||||
self->font = g_object_ref (font);
|
||||
hb_face = pango2_hb_face_get_hb_face (PANGO2_HB_FACE (pango2_font_get_face (font)));
|
||||
self->num_glyphs = hb_face_get_glyph_count (hb_face);
|
||||
self->glyphs = g_new0 (GlyphItem *, self->num_glyphs);
|
||||
|
||||
return self;
|
||||
}
|
14
demos/font-explorer/glyphmodel.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define GLYPH_MODEL_TYPE (glyph_model_get_type ())
|
||||
#define GLYPH_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPH_MODEL_TYPE, GlyphModel))
|
||||
|
||||
|
||||
typedef struct _GlyphModel GlyphModel;
|
||||
typedef struct _GlyphModelClass GlyphModelClass;
|
||||
|
||||
|
||||
GType glyph_model_get_type (void);
|
||||
GlyphModel * glyph_model_new (Pango2Font *font);
|
239
demos/font-explorer/glyphsview.c
Normal file
@@ -0,0 +1,239 @@
|
||||
#include "glyphsview.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "glyphitem.h"
|
||||
#include "glyphmodel.h"
|
||||
#include "glyphview.h"
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
PROP_VARIATIONS,
|
||||
PROP_PALETTE,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _GlyphsView
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
GtkGridView *glyphs;
|
||||
|
||||
Pango2FontDescription *font_desc;
|
||||
char *variations;
|
||||
char *palette;
|
||||
GQuark palette_quark;
|
||||
};
|
||||
|
||||
struct _GlyphsViewClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(GlyphsView, glyphs_view, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
glyphs_view_init (GlyphsView *self)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
self->font_desc = pango2_font_description_from_string ("sans 12");
|
||||
self->variations = g_strdup ("");
|
||||
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
|
||||
self->palette_quark = g_quark_from_string (self->palette);
|
||||
|
||||
gtk_widget_set_layout_manager (GTK_WIDGET (self),
|
||||
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
|
||||
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
glyphs_view_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), GLYPHS_VIEW_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (glyphs_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
glyphs_view_finalize (GObject *object)
|
||||
{
|
||||
GlyphsView *self = GLYPHS_VIEW (object);
|
||||
|
||||
g_clear_object (&self->font_map);
|
||||
pango2_font_description_free (self->font_desc);
|
||||
g_free (self->variations);
|
||||
g_free (self->palette);
|
||||
|
||||
G_OBJECT_CLASS (glyphs_view_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static Pango2Font *
|
||||
get_font (GlyphsView *self,
|
||||
int size)
|
||||
{
|
||||
Pango2Context *context;
|
||||
Pango2FontDescription *desc;
|
||||
Pango2Font *font;
|
||||
|
||||
context = pango2_context_new_with_font_map (self->font_map);
|
||||
desc = pango2_font_description_copy_static (self->font_desc);
|
||||
pango2_font_description_set_variations (desc, self->variations);
|
||||
pango2_font_description_set_size (desc, size);
|
||||
font = pango2_context_load_font (context, desc);
|
||||
pango2_font_description_free (desc);
|
||||
g_object_unref (context);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static void
|
||||
update_glyph_model (GlyphsView *self)
|
||||
{
|
||||
Pango2Font *font = get_font (self, 60 * PANGO2_SCALE);
|
||||
GlyphModel *gm;
|
||||
GtkSelectionModel *model;
|
||||
|
||||
gm = glyph_model_new (font);
|
||||
model = GTK_SELECTION_MODEL (gtk_no_selection_new (G_LIST_MODEL (gm)));
|
||||
gtk_grid_view_set_model (self->glyphs, model);
|
||||
g_object_unref (model);
|
||||
g_object_unref (font);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_glyph (GtkSignalListItemFactory *factory,
|
||||
GObject *listitem)
|
||||
{
|
||||
gtk_list_item_set_child (GTK_LIST_ITEM (listitem), GTK_WIDGET (glyph_view_new ()));
|
||||
}
|
||||
|
||||
static void
|
||||
bind_glyph (GtkSignalListItemFactory *factory,
|
||||
GObject *listitem,
|
||||
GlyphsView *self)
|
||||
{
|
||||
GlyphView *view;
|
||||
GObject *item;
|
||||
|
||||
view = GLYPH_VIEW (gtk_list_item_get_child (GTK_LIST_ITEM (listitem)));
|
||||
item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem));
|
||||
glyph_view_set_font (view, glyph_item_get_font (GLYPH_ITEM (item)));
|
||||
glyph_view_set_glyph (view, glyph_item_get_glyph (GLYPH_ITEM (item)));
|
||||
glyph_view_set_palette (view, self->palette_quark);
|
||||
}
|
||||
|
||||
static void
|
||||
glyphs_view_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GlyphsView *self = GLYPHS_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
pango2_font_description_free (self->font_desc);
|
||||
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_VARIATIONS:
|
||||
g_free (self->variations);
|
||||
self->variations = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_PALETTE:
|
||||
g_free (self->palette);
|
||||
self->palette = g_strdup (g_value_get_string (value));
|
||||
self->palette_quark = g_quark_from_string (self->palette);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_glyph_model (self);
|
||||
}
|
||||
|
||||
static void
|
||||
glyphs_view_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GlyphsView *self = GLYPHS_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
g_value_set_boxed (value, self->font_desc);
|
||||
break;
|
||||
|
||||
case PROP_VARIATIONS:
|
||||
g_value_set_string (value, self->variations);
|
||||
break;
|
||||
|
||||
case PROP_PALETTE:
|
||||
g_value_set_string (value, self->palette);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glyphs_view_class_init (GlyphsViewClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = glyphs_view_dispose;
|
||||
object_class->finalize = glyphs_view_finalize;
|
||||
object_class->get_property = glyphs_view_get_property;
|
||||
object_class->set_property = glyphs_view_set_property;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FONT_DESC] =
|
||||
g_param_spec_boxed ("font-desc", "", "",
|
||||
PANGO2_TYPE_FONT_DESCRIPTION,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_VARIATIONS] =
|
||||
g_param_spec_string ("variations", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_PALETTE] =
|
||||
g_param_spec_string ("palette", "", "",
|
||||
PANGO2_COLOR_PALETTE_DEFAULT,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/glyphsview.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), GlyphsView, glyphs);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), setup_glyph);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), bind_glyph);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "glyphsview");
|
||||
}
|
14
demos/font-explorer/glyphsview.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define GLYPHS_VIEW_TYPE (glyphs_view_get_type ())
|
||||
#define GLYPHS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPHS_VIEW_TYPE, GlyphsView))
|
||||
|
||||
|
||||
typedef struct _GlyphsView GlyphsView;
|
||||
typedef struct _GlyphsViewClass GlyphsViewClass;
|
||||
|
||||
|
||||
GType glyphs_view_get_type (void);
|
29
demos/font-explorer/glyphsview.ui
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GlyphsView" parent="GtkWidget">
|
||||
<style>
|
||||
<class name="view"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="vscrollbar-policy">automatic</property>
|
||||
<child>
|
||||
<object class="GtkGridView" id="glyphs">
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_glyph"/>
|
||||
<signal name="bind" handler="bind_glyph"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
321
demos/font-explorer/glyphview.c
Normal file
@@ -0,0 +1,321 @@
|
||||
#include "glyphview.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
struct _GlyphView
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
Pango2Font *font;
|
||||
GQuark palette;
|
||||
int palette_index;
|
||||
hb_codepoint_t glyph;
|
||||
int n_layers;
|
||||
int layer;
|
||||
};
|
||||
|
||||
struct _GlyphViewClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(GlyphView, glyph_view, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
click_cb (GtkGestureClick *gesture,
|
||||
int n_press,
|
||||
double x,
|
||||
double y,
|
||||
GlyphView *self)
|
||||
{
|
||||
if (self->n_layers == 0)
|
||||
return;
|
||||
|
||||
self->layer++;
|
||||
|
||||
if (self->layer == self->n_layers)
|
||||
self->layer = -1;
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_view_init (GlyphView *self)
|
||||
{
|
||||
GtkGesture *click;
|
||||
|
||||
self->n_layers = 0;
|
||||
self->layer = -1;
|
||||
|
||||
click = gtk_gesture_click_new ();
|
||||
g_signal_connect (click, "pressed", G_CALLBACK (click_cb), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (click));
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_view_dispose (GObject *object)
|
||||
{
|
||||
GlyphView *self = GLYPH_VIEW (object);
|
||||
|
||||
g_clear_object (&self->font);
|
||||
|
||||
G_OBJECT_CLASS (glyph_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_view_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GlyphView *self = GLYPH_VIEW (widget);
|
||||
Pango2GlyphString *glyphs;
|
||||
Pango2Rectangle ink, logical;
|
||||
cairo_t *cr;
|
||||
int width, height;
|
||||
char name[80];
|
||||
|
||||
pango2_font_get_glyph_extents (self->font, self->glyph, &ink, &logical);
|
||||
|
||||
width = gtk_widget_get_width (widget);
|
||||
height = gtk_widget_get_height (widget);
|
||||
|
||||
cr = gtk_snapshot_append_cairo (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
|
||||
glyphs = pango2_glyph_string_new ();
|
||||
pango2_glyph_string_set_size (glyphs, 1);
|
||||
|
||||
glyphs->glyphs[0].geometry.width = ink.width;
|
||||
glyphs->glyphs[0].geometry.x_offset = ink.x;
|
||||
glyphs->glyphs[0].geometry.y_offset = -ink.y;
|
||||
|
||||
if (self->layer == -1)
|
||||
{
|
||||
glyphs->glyphs[0].glyph = self->glyph;
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
hb_face_t *face = hb_font_get_face (pango2_font_get_hb_font (self->font));
|
||||
hb_ot_color_layer_t *layers;
|
||||
unsigned int count;
|
||||
|
||||
layers = g_newa (hb_ot_color_layer_t, self->n_layers);
|
||||
count = self->n_layers;
|
||||
hb_ot_color_glyph_get_layers (face,
|
||||
self->glyph,
|
||||
0,
|
||||
&count,
|
||||
layers);
|
||||
glyphs->glyphs[0].glyph = layers[self->layer].glyph;
|
||||
if (layers[self->layer].color_index == 0xffff)
|
||||
{
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
hb_color_t *colors;
|
||||
unsigned int n_colors;
|
||||
hb_color_t color;
|
||||
|
||||
n_colors = hb_ot_color_palette_get_colors (face,
|
||||
self->palette_index,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
colors = g_newa (hb_color_t, n_colors);
|
||||
hb_ot_color_palette_get_colors (face,
|
||||
self->palette_index,
|
||||
0,
|
||||
&n_colors,
|
||||
colors);
|
||||
color = colors[layers[self->layer].color_index];
|
||||
cairo_set_source_rgba (cr, hb_color_get_red (color)/255.,
|
||||
hb_color_get_green (color)/255.,
|
||||
hb_color_get_blue (color)/255.,
|
||||
hb_color_get_alpha (color)/255.);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_move_to (cr, (width - logical.width/1024.)/2, (height - logical.height/1024.)/2);
|
||||
pango2_cairo_show_color_glyph_string (cr, self->font, self->palette, glyphs);
|
||||
|
||||
{
|
||||
Pango2Layout *layout;
|
||||
Pango2FontDescription *desc;
|
||||
char gid[20];
|
||||
hb_font_t *hb_font;
|
||||
hb_face_t *hb_face;
|
||||
|
||||
g_snprintf (gid, sizeof (gid), "%d", self->glyph);
|
||||
layout = gtk_widget_create_pango_layout (widget, gid);
|
||||
desc = pango2_font_description_from_string ("Cantarell 8");
|
||||
pango2_layout_set_font_description (layout, desc);
|
||||
pango2_font_description_free (desc);
|
||||
|
||||
gtk_snapshot_save (snapshot);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (5, 5));
|
||||
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,0.7});
|
||||
gtk_snapshot_restore (snapshot);
|
||||
|
||||
hb_font = pango2_font_get_hb_font (self->font);
|
||||
hb_face = hb_font_get_face (hb_font);
|
||||
|
||||
if (hb_ot_layout_has_glyph_classes (hb_face))
|
||||
{
|
||||
hb_ot_layout_glyph_class_t class;
|
||||
const char *class_names[] = {
|
||||
NULL, "Base", "Ligature", "Mark", "Component"
|
||||
};
|
||||
int w, h;
|
||||
|
||||
class = hb_ot_layout_get_glyph_class (hb_face, self->glyph);
|
||||
|
||||
if (class != HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED)
|
||||
{
|
||||
pango2_layout_set_text (layout, class_names[class], -1);
|
||||
pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
|
||||
|
||||
gtk_snapshot_save (snapshot);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width - w/1024. - 5, 5));
|
||||
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,.7});
|
||||
gtk_snapshot_restore (snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
if (hb_font_get_glyph_name (hb_font, self->glyph, name, sizeof (name)))
|
||||
{
|
||||
int w, h;
|
||||
|
||||
pango2_layout_set_text (layout, name, -1);
|
||||
pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
|
||||
|
||||
gtk_snapshot_save (snapshot);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (5, height - h/1024. - 5));
|
||||
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,.7});
|
||||
gtk_snapshot_restore (snapshot);
|
||||
}
|
||||
|
||||
if (self->n_layers > 0)
|
||||
{
|
||||
char buf[128];
|
||||
int w, h;
|
||||
|
||||
if (self->layer == -1)
|
||||
g_snprintf (buf, sizeof (buf), "%d Layers", self->n_layers);
|
||||
else
|
||||
g_snprintf (buf, sizeof (buf), "Layer %d", self->layer);
|
||||
|
||||
pango2_layout_set_text (layout, buf, -1);
|
||||
pango2_lines_get_size (pango2_layout_get_lines (layout), &w, &h);
|
||||
|
||||
gtk_snapshot_save (snapshot);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (width - w/1024. - 5, height - h/1024. - 5));
|
||||
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA){ 0.,0.,0.,.7});
|
||||
gtk_snapshot_restore (snapshot);
|
||||
}
|
||||
|
||||
g_object_unref (layout);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_view_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GlyphView *self = GLYPH_VIEW (widget);
|
||||
Pango2Rectangle ink, logical;
|
||||
|
||||
pango2_font_get_glyph_extents (self->font, self->glyph, &ink, &logical);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
*minimum = *natural = 2 * logical.width / PANGO2_SCALE;
|
||||
else
|
||||
*minimum = *natural = 2 * logical.height / PANGO2_SCALE;
|
||||
}
|
||||
|
||||
static void
|
||||
glyph_view_class_init (GlyphViewClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
object_class->dispose = glyph_view_dispose;
|
||||
widget_class->snapshot = glyph_view_snapshot;
|
||||
widget_class->measure = glyph_view_measure;
|
||||
|
||||
gtk_widget_class_set_css_name (widget_class, "glyphview");
|
||||
}
|
||||
|
||||
GlyphView *
|
||||
glyph_view_new (void)
|
||||
{
|
||||
return g_object_new (GLYPH_VIEW_TYPE, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
glyph_view_set_font (GlyphView *self,
|
||||
Pango2Font *font)
|
||||
{
|
||||
if (g_set_object (&self->font, font))
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
find_palette_index_by_flag (hb_face_t *hbface,
|
||||
hb_ot_color_palette_flags_t flag)
|
||||
{
|
||||
unsigned int n_palettes;
|
||||
|
||||
n_palettes = hb_ot_color_palette_get_count (hbface);
|
||||
for (unsigned int i = 0; i < n_palettes; i++)
|
||||
{
|
||||
if (hb_ot_color_palette_get_flags (hbface, i) & flag)
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
glyph_view_set_palette (GlyphView *self,
|
||||
GQuark palette)
|
||||
{
|
||||
if (self->palette == palette)
|
||||
return;
|
||||
|
||||
self->palette = palette;
|
||||
|
||||
if (palette == g_quark_from_string (PANGO2_COLOR_PALETTE_DEFAULT))
|
||||
self->palette_index = 0;
|
||||
else if (palette == g_quark_from_string (PANGO2_COLOR_PALETTE_LIGHT))
|
||||
self->palette_index = find_palette_index_by_flag (hb_font_get_face (pango2_font_get_hb_font (self->font)), HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND);
|
||||
else if (palette == g_quark_from_string (PANGO2_COLOR_PALETTE_DARK))
|
||||
self->palette_index = find_palette_index_by_flag (hb_font_get_face (pango2_font_get_hb_font (self->font)), HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND);
|
||||
else
|
||||
{
|
||||
const char *str = g_quark_to_string (palette);
|
||||
char *endp;
|
||||
if (g_str_has_prefix (str, "palette"))
|
||||
self->palette_index = g_ascii_strtoll (str + strlen ("palette"), &endp, 10);
|
||||
}
|
||||
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
void
|
||||
glyph_view_set_glyph (GlyphView *self,
|
||||
hb_codepoint_t glyph)
|
||||
{
|
||||
if (self->glyph == glyph)
|
||||
return;
|
||||
|
||||
self->glyph = glyph;
|
||||
self->n_layers = hb_ot_color_glyph_get_layers (hb_font_get_face (pango2_font_get_hb_font (self->font)), glyph, 0, NULL, NULL);
|
||||
self->layer = -1;
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self));
|
||||
}
|
21
demos/font-explorer/glyphview.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define GLYPH_VIEW_TYPE (glyph_view_get_type ())
|
||||
#define GLYPH_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLYPH_VIEW_TYPE, GlyphView))
|
||||
|
||||
|
||||
typedef struct _GlyphView GlyphView;
|
||||
typedef struct _GlyphViewClass GlyphViewClass;
|
||||
|
||||
|
||||
GType glyph_view_get_type (void);
|
||||
GlyphView * glyph_view_new (void);
|
||||
void glyph_view_set_font (GlyphView *view,
|
||||
Pango2Font *font);
|
||||
void glyph_view_set_palette (GlyphView *view,
|
||||
GQuark palette);
|
||||
void glyph_view_set_glyph (GlyphView *view,
|
||||
hb_codepoint_t glyph);
|
423
demos/font-explorer/infoview.c
Normal file
@@ -0,0 +1,423 @@
|
||||
#include "infoview.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
PROP_SIZE,
|
||||
PROP_VARIATIONS,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _InfoView
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GtkGrid *info;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
Pango2FontDescription *font_desc;
|
||||
float size;
|
||||
char *variations;
|
||||
};
|
||||
|
||||
struct _InfoViewClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(InfoView, info_view, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
info_view_init (InfoView *self)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
self->font_desc = pango2_font_description_from_string ("sans 12");
|
||||
self->size = 12.;
|
||||
self->variations = g_strdup ("");
|
||||
|
||||
gtk_widget_set_layout_manager (GTK_WIDGET (self),
|
||||
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
info_view_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), INFO_VIEW_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (info_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
info_view_finalize (GObject *object)
|
||||
{
|
||||
InfoView *self = INFO_VIEW (object);
|
||||
|
||||
g_clear_object (&self->font_map);
|
||||
pango2_font_description_free (self->font_desc);
|
||||
g_free (self->variations);
|
||||
|
||||
G_OBJECT_CLASS (info_view_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static Pango2Font *
|
||||
get_font (InfoView *self,
|
||||
int size)
|
||||
{
|
||||
Pango2Context *context;
|
||||
Pango2FontDescription *desc;
|
||||
Pango2Font *font;
|
||||
|
||||
context = pango2_context_new_with_font_map (self->font_map);
|
||||
desc = pango2_font_description_copy_static (self->font_desc);
|
||||
pango2_font_description_set_variations (desc, self->variations);
|
||||
pango2_font_description_set_size (desc, size);
|
||||
font = pango2_context_load_font (context, desc);
|
||||
pango2_font_description_free (desc);
|
||||
g_object_unref (context);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
make_title_label (const char *title)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new (title);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
||||
g_object_set (label, "margin-top", 10, "margin-bottom", 10, NULL);
|
||||
gtk_widget_add_css_class (label, "heading");
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
static void
|
||||
add_misc_line (InfoView *self,
|
||||
const char *title,
|
||||
const char *value,
|
||||
int row)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new (title);
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (label, GTK_ALIGN_START);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
||||
gtk_widget_set_hexpand (label, TRUE);
|
||||
gtk_grid_attach (self->info, label, 0, row, 1, 1);
|
||||
|
||||
label = gtk_label_new (value);
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_END);
|
||||
gtk_widget_set_valign (label, GTK_ALIGN_START);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 1);
|
||||
gtk_label_set_wrap (GTK_LABEL (label), TRUE);
|
||||
gtk_label_set_width_chars (GTK_LABEL (label), 40);
|
||||
gtk_label_set_max_width_chars (GTK_LABEL (label), 40);
|
||||
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
|
||||
gtk_grid_attach (self->info, label, 1, row, 1, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
add_info_line (InfoView *self,
|
||||
hb_face_t *face,
|
||||
hb_ot_name_id_t name_id,
|
||||
const char *title,
|
||||
int row)
|
||||
{
|
||||
char info[256];
|
||||
unsigned int len = sizeof (info);
|
||||
|
||||
if (hb_ot_name_get_utf8 (face, name_id, HB_LANGUAGE_INVALID, &len, info) > 0)
|
||||
add_misc_line (self, title, info, row);
|
||||
}
|
||||
|
||||
static void
|
||||
add_metrics_line (InfoView *self,
|
||||
hb_font_t *font,
|
||||
hb_ot_metrics_tag_t metrics_tag,
|
||||
const char *title,
|
||||
int row)
|
||||
{
|
||||
hb_position_t pos;
|
||||
|
||||
if (hb_ot_metrics_get_position (font, metrics_tag, &pos))
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
g_snprintf (buf, sizeof (buf), "%d", pos);
|
||||
add_misc_line (self, title, buf, row);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_style_line (InfoView *self,
|
||||
hb_font_t *font,
|
||||
hb_style_tag_t style_tag,
|
||||
const char *title,
|
||||
int row)
|
||||
{
|
||||
float value;
|
||||
char buf[16];
|
||||
|
||||
value = hb_style_get_value (font, style_tag);
|
||||
g_snprintf (buf, sizeof (buf), "%.2f", value);
|
||||
add_misc_line (self, title, buf, row);
|
||||
}
|
||||
|
||||
static void
|
||||
update_info (InfoView *self)
|
||||
{
|
||||
GtkWidget *child;
|
||||
int size = pango2_font_description_get_size (self->font_desc);
|
||||
Pango2Font *pango_font = get_font (self, MAX (size, 10 * PANGO2_SCALE));
|
||||
hb_font_t *font1 = pango2_font_get_hb_font (pango_font);
|
||||
hb_face_t *face = hb_font_get_face (font1);
|
||||
hb_font_t *font = hb_font_create_sub_font (font1);
|
||||
int row = 0;
|
||||
char buf[128];
|
||||
unsigned int count;
|
||||
GString *s;
|
||||
hb_tag_t *tables;
|
||||
const char *path;
|
||||
|
||||
hb_font_set_scale (font, hb_face_get_upem (face), hb_face_get_upem (face));
|
||||
|
||||
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->info))) != NULL)
|
||||
gtk_widget_unparent (child);
|
||||
|
||||
gtk_grid_attach (self->info, make_title_label ("General Info"), 0, row++, 2, 1);
|
||||
|
||||
path = pango2_hb_face_get_file (PANGO2_HB_FACE (pango2_font_get_face (pango_font)));
|
||||
if (path)
|
||||
add_misc_line (self, "File ", path, row++);
|
||||
|
||||
add_info_line (self, face, HB_OT_NAME_ID_FONT_FAMILY, "Font Family Name", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_FONT_SUBFAMILY, "Font Subfamily Name", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_UNIQUE_ID, "Unique Font Identifier", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_FULL_NAME, "Full Name", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_VERSION_STRING, "Version", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_POSTSCRIPT_NAME, "Postscript Name", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY, "Typographic Family Name", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY, "Typographic Subfamily Name", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_MANUFACTURER, "Vendor ID", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_DESIGNER, "Designer", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_DESCRIPTION, "Description", row++);
|
||||
add_info_line (self, face, HB_OT_NAME_ID_COPYRIGHT, "Copyright", row++);
|
||||
|
||||
gtk_grid_attach (self->info, make_title_label ("Metrics"), 0, row++, 2, 1);
|
||||
g_snprintf (buf, sizeof (buf), "%d", hb_face_get_upem (face));
|
||||
add_misc_line (self, "Units per Em", buf, row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, "Ascender", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, "Descender", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, "Line Gap", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE, "Caret Rise", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN, "Caret Run", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET, "Caret Offset", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_X_HEIGHT, "x Height", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_CAP_HEIGHT, "Cap Height", row++);
|
||||
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_SIZE, "Strikeout Size", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_OFFSET, "Strikeout Offset", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_SIZE, "Underline Size", row++);
|
||||
add_metrics_line (self, font, HB_OT_METRICS_TAG_STRIKEOUT_OFFSET, "Underline Offset", row++);
|
||||
|
||||
gtk_grid_attach (self->info, make_title_label ("Style"), 0, row++, 2, 1);
|
||||
|
||||
add_style_line (self, font, HB_STYLE_TAG_ITALIC, "Italic", row++);
|
||||
add_style_line (self, font, HB_STYLE_TAG_OPTICAL_SIZE, "Optical Size", row++);
|
||||
add_style_line (self, font, HB_STYLE_TAG_SLANT_ANGLE, "Slant Angle", row++);
|
||||
add_style_line (self, font, HB_STYLE_TAG_WIDTH, "Width", row++);
|
||||
add_style_line (self, font, HB_STYLE_TAG_WEIGHT, "Weight", row++);
|
||||
|
||||
gtk_grid_attach (self->info, make_title_label ("Miscellaneous"), 0, row++, 2, 1);
|
||||
|
||||
count = hb_face_get_glyph_count (face);
|
||||
g_snprintf (buf, sizeof (buf), "%d", count);
|
||||
add_misc_line (self, "Glyph Count", buf, row++);
|
||||
|
||||
if (hb_ot_var_get_axis_count (face) > 0)
|
||||
{
|
||||
s = g_string_new ("");
|
||||
hb_ot_var_axis_info_t *axes;
|
||||
|
||||
axes = g_newa (hb_ot_var_axis_info_t, hb_ot_var_get_axis_count (face));
|
||||
count = hb_ot_var_get_axis_count (face);
|
||||
hb_ot_var_get_axis_infos (face, 0, &count, axes);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
char name[256];
|
||||
unsigned int len;
|
||||
|
||||
len = sizeof (buf);
|
||||
hb_ot_name_get_utf8 (face, axes[i].name_id, HB_LANGUAGE_INVALID, &len, name);
|
||||
if (s->len > 0)
|
||||
g_string_append (s, ", ");
|
||||
g_string_append (s, name);
|
||||
}
|
||||
add_misc_line (self, "Axes", s->str, row++);
|
||||
g_string_free (s, TRUE);
|
||||
}
|
||||
|
||||
if (hb_ot_var_get_named_instance_count (face) > 0)
|
||||
{
|
||||
s = g_string_new ("");
|
||||
for (int i = 0; i < hb_ot_var_get_named_instance_count (face); i++)
|
||||
{
|
||||
hb_ot_name_id_t name_id;
|
||||
char name[256];
|
||||
unsigned int len;
|
||||
|
||||
name_id = hb_ot_var_named_instance_get_subfamily_name_id (face, i);
|
||||
len = sizeof (buf);
|
||||
hb_ot_name_get_utf8 (face, name_id, HB_LANGUAGE_INVALID, &len, name);
|
||||
if (s->len > 0)
|
||||
g_string_append (s, ", ");
|
||||
g_string_append (s, name);
|
||||
}
|
||||
add_misc_line (self, "Named Instances", s->str, row++);
|
||||
g_string_free (s, TRUE);
|
||||
}
|
||||
|
||||
s = g_string_new ("");
|
||||
count = hb_face_get_table_tags (face, 0, NULL, NULL);
|
||||
tables = g_newa (hb_tag_t, count);
|
||||
hb_face_get_table_tags (face, 0, &count, tables);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
memset (buf, 0, sizeof (buf));
|
||||
hb_tag_to_string (tables[i], buf);
|
||||
if (s->len > 0)
|
||||
g_string_append (s, ", ");
|
||||
g_string_append (s, buf);
|
||||
}
|
||||
add_misc_line (self, "Tables", s->str, row++);
|
||||
g_string_free (s, TRUE);
|
||||
|
||||
s = g_string_new ("");
|
||||
if (hb_ot_color_has_palettes (face))
|
||||
g_string_append_printf (s, "%s", "Palettes");
|
||||
if (hb_ot_color_has_layers (face))
|
||||
g_string_append_printf (s, "%s%s", s->len > 0 ? ", " : "", "Layers");
|
||||
if (hb_ot_color_has_svg (face))
|
||||
g_string_append_printf (s, "%s%s", s->len > 0 ? ", " : "", "SVG");
|
||||
if (hb_ot_color_has_png (face))
|
||||
g_string_append_printf (s, "%s%s", s->len > 0 ? ", " : "", "PNG");
|
||||
if (s->len > 0)
|
||||
add_misc_line (self, "Color", s->str, row++);
|
||||
g_string_free (s, TRUE);
|
||||
|
||||
hb_font_destroy (font);
|
||||
}
|
||||
|
||||
static void
|
||||
info_view_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
InfoView *self = INFO_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
pango2_font_description_free (self->font_desc);
|
||||
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
self->size = g_value_get_float (value);
|
||||
break;
|
||||
|
||||
case PROP_VARIATIONS:
|
||||
g_free (self->variations);
|
||||
self->variations = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_info (self);
|
||||
}
|
||||
|
||||
static void
|
||||
info_view_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
InfoView *self = INFO_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
g_value_set_boxed (value, self->font_desc);
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
g_value_set_float (value, self->size);
|
||||
break;
|
||||
|
||||
case PROP_VARIATIONS:
|
||||
g_value_set_string (value, self->variations);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
info_view_class_init (InfoViewClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = info_view_dispose;
|
||||
object_class->finalize = info_view_finalize;
|
||||
object_class->get_property = info_view_get_property;
|
||||
object_class->set_property = info_view_set_property;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FONT_DESC] =
|
||||
g_param_spec_boxed ("font-desc", "", "",
|
||||
PANGO2_TYPE_FONT_DESCRIPTION,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_SIZE] =
|
||||
g_param_spec_float ("size", "", "",
|
||||
0., 100., 12.,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_VARIATIONS] =
|
||||
g_param_spec_string ("variations", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/infoview.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), InfoView, info);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "infoview");
|
||||
}
|
14
demos/font-explorer/infoview.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define INFO_VIEW_TYPE (info_view_get_type ())
|
||||
#define INFO_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INFO_VIEW_TYPE, InfoView))
|
||||
|
||||
|
||||
typedef struct _InfoView InfoView;
|
||||
typedef struct _InfoViewClass InfoViewClass;
|
||||
|
||||
|
||||
GType info_view_get_type (void);
|
23
demos/font-explorer/infoview.ui
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="InfoView" parent="GtkWidget">
|
||||
<style>
|
||||
<class name="view"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="vscrollbar-policy">automatic</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkGrid" id="info">
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
334
demos/font-explorer/language-names.c
Normal file
@@ -0,0 +1,334 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "language-names.h"
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#else
|
||||
#ifndef ISO_CODES_PREFIX
|
||||
#define ISO_CODES_PREFIX "/usr"
|
||||
#endif
|
||||
|
||||
#define ISO_CODES_DATADIR ISO_CODES_PREFIX "/share/xml/iso-codes"
|
||||
#define ISO_CODES_LOCALESDIR ISO_CODES_PREFIX "/share/locale"
|
||||
#endif
|
||||
|
||||
static GHashTable *language_map;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
/* if we are using native Windows use native Windows API for language names */
|
||||
static BOOL CALLBACK
|
||||
get_win32_all_locales_scripts (LPWSTR locale_w, DWORD flags, LPARAM param)
|
||||
{
|
||||
wchar_t *langname_w = NULL;
|
||||
wchar_t locale_abbrev_w[9];
|
||||
gchar *langname, *locale_abbrev, *locale, *p;
|
||||
gint i;
|
||||
const LCTYPE iso639_lctypes[] = { LOCALE_SISO639LANGNAME, LOCALE_SISO639LANGNAME2 };
|
||||
GHashTable *ht_scripts_langs = (GHashTable *) param;
|
||||
Pango2Language *lang;
|
||||
|
||||
gint langname_size, locale_abbrev_size;
|
||||
langname_size = GetLocaleInfoEx (locale_w, LOCALE_SLOCALIZEDDISPLAYNAME, langname_w, 0);
|
||||
if (langname_size == 0)
|
||||
return FALSE;
|
||||
|
||||
langname_w = g_new0 (wchar_t, langname_size);
|
||||
|
||||
if (langname_size == 0)
|
||||
return FALSE;
|
||||
|
||||
GetLocaleInfoEx (locale_w, LOCALE_SLOCALIZEDDISPLAYNAME, langname_w, langname_size);
|
||||
langname = g_utf16_to_utf8 (langname_w, -1, NULL, NULL, NULL);
|
||||
locale = g_utf16_to_utf8 (locale_w, -1, NULL, NULL, NULL);
|
||||
p = strchr (locale, '-');
|
||||
lang = pango2_language_from_string (locale);
|
||||
if (g_hash_table_lookup (ht_scripts_langs, lang) == NULL)
|
||||
g_hash_table_insert (ht_scripts_langs, lang, langname);
|
||||
|
||||
/*
|
||||
* Track 3+-letter ISO639-2/3 language codes as well (these have a max length of 9 including terminating NUL)
|
||||
* ISO639-2: iso639_lctypes[0] = LOCALE_SISO639LANGNAME
|
||||
* ISO639-3: iso639_lctypes[1] = LOCALE_SISO639LANGNAME2
|
||||
*/
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
locale_abbrev_size = GetLocaleInfoEx (locale_w, iso639_lctypes[i], locale_abbrev_w, 0);
|
||||
if (locale_abbrev_size > 0)
|
||||
{
|
||||
GetLocaleInfoEx (locale_w, iso639_lctypes[i], locale_abbrev_w, locale_abbrev_size);
|
||||
|
||||
locale_abbrev = g_utf16_to_utf8 (locale_abbrev_w, -1, NULL, NULL, NULL);
|
||||
lang = pango2_language_from_string (locale_abbrev);
|
||||
if (g_hash_table_lookup (ht_scripts_langs, lang) == NULL)
|
||||
g_hash_table_insert (ht_scripts_langs, lang, langname);
|
||||
|
||||
g_free (locale_abbrev);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (locale);
|
||||
g_free (langname_w);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#else /* non-Windows */
|
||||
|
||||
static char *
|
||||
get_first_item_in_semicolon_list (const char *list)
|
||||
{
|
||||
char **items;
|
||||
char *item;
|
||||
|
||||
items = g_strsplit (list, "; ", 2);
|
||||
|
||||
item = g_strdup (items[0]);
|
||||
g_strfreev (items);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static char *
|
||||
capitalize_utf8_string (const char *str)
|
||||
{
|
||||
char first[8] = { 0 };
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
g_unichar_to_utf8 (g_unichar_totitle (g_utf8_get_char (str)), first);
|
||||
|
||||
return g_strconcat (first, g_utf8_offset_to_pointer (str, 1), NULL);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_display_name (const char *language)
|
||||
{
|
||||
const char *translated;
|
||||
char *tmp;
|
||||
char *name;
|
||||
|
||||
translated = dgettext ("iso_639", language);
|
||||
|
||||
tmp = get_first_item_in_semicolon_list (translated);
|
||||
name = capitalize_utf8_string (tmp);
|
||||
g_free (tmp);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static void
|
||||
languages_parse_start_tag (GMarkupParseContext *ctx,
|
||||
const char *element_name,
|
||||
const char **attr_names,
|
||||
const char **attr_values,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
const char *ccode_longB;
|
||||
const char *ccode_longT;
|
||||
const char *ccode;
|
||||
const char *ccode_id;
|
||||
const char *lang_name;
|
||||
char *display_name;
|
||||
const char *long_names[] = {
|
||||
"Dogri",
|
||||
"Greek, Modern",
|
||||
"Interlingua",
|
||||
"Konkani",
|
||||
"Tonga",
|
||||
"Turkish, Ottoman",
|
||||
};
|
||||
int i;
|
||||
|
||||
if (!(g_str_equal (element_name, "iso_639_entry") ||
|
||||
g_str_equal (element_name, "iso_639_3_entry")) ||
|
||||
attr_names == NULL ||
|
||||
attr_values == NULL)
|
||||
return;
|
||||
|
||||
ccode = NULL;
|
||||
ccode_longB = NULL;
|
||||
ccode_longT = NULL;
|
||||
ccode_id = NULL;
|
||||
lang_name = NULL;
|
||||
|
||||
while (*attr_names && *attr_values)
|
||||
{
|
||||
if (g_str_equal (*attr_names, "iso_639_1_code"))
|
||||
{
|
||||
if (**attr_values)
|
||||
{
|
||||
if (strlen (*attr_values) != 2)
|
||||
return;
|
||||
ccode = *attr_values;
|
||||
}
|
||||
}
|
||||
else if (g_str_equal (*attr_names, "iso_639_2B_code"))
|
||||
{
|
||||
if (**attr_values)
|
||||
{
|
||||
if (strlen (*attr_values) != 3)
|
||||
return;
|
||||
ccode_longB = *attr_values;
|
||||
}
|
||||
}
|
||||
else if (g_str_equal (*attr_names, "iso_639_2T_code"))
|
||||
{
|
||||
if (**attr_values)
|
||||
{
|
||||
if (strlen (*attr_values) != 3)
|
||||
return;
|
||||
ccode_longT = *attr_values;
|
||||
}
|
||||
}
|
||||
else if (g_str_equal (*attr_names, "id"))
|
||||
{
|
||||
if (**attr_values)
|
||||
{
|
||||
if (strlen (*attr_values) != 2 &&
|
||||
strlen (*attr_values) != 3)
|
||||
return;
|
||||
ccode_id = *attr_values;
|
||||
}
|
||||
}
|
||||
else if (g_str_equal (*attr_names, "name"))
|
||||
{
|
||||
lang_name = *attr_values;
|
||||
}
|
||||
|
||||
++attr_names;
|
||||
++attr_values;
|
||||
}
|
||||
|
||||
if (lang_name == NULL)
|
||||
return;
|
||||
|
||||
display_name = get_display_name (lang_name);
|
||||
|
||||
/* Fix up some egregious names */
|
||||
for (i = 0; i < G_N_ELEMENTS (long_names); i++)
|
||||
{
|
||||
if (g_str_has_prefix (display_name, long_names[i]))
|
||||
display_name[strlen (long_names[i])] = '\0';
|
||||
}
|
||||
|
||||
|
||||
if (ccode != NULL)
|
||||
g_hash_table_insert (language_map,
|
||||
pango2_language_from_string (ccode),
|
||||
g_strdup (display_name));
|
||||
|
||||
if (ccode_longB != NULL)
|
||||
g_hash_table_insert (language_map,
|
||||
pango2_language_from_string (ccode_longB),
|
||||
g_strdup (display_name));
|
||||
|
||||
if (ccode_longT != NULL)
|
||||
g_hash_table_insert (language_map,
|
||||
pango2_language_from_string (ccode_longT),
|
||||
g_strdup (display_name));
|
||||
|
||||
if (ccode_id != NULL)
|
||||
g_hash_table_insert (language_map,
|
||||
pango2_language_from_string (ccode_id),
|
||||
g_strdup (display_name));
|
||||
|
||||
g_free (display_name);
|
||||
}
|
||||
|
||||
static void
|
||||
languages_variant_init (const char *variant)
|
||||
{
|
||||
gboolean res;
|
||||
gsize buf_len;
|
||||
char *buf;
|
||||
char *filename;
|
||||
GError *error;
|
||||
|
||||
bindtextdomain (variant, ISO_CODES_LOCALESDIR);
|
||||
bind_textdomain_codeset (variant, "UTF-8");
|
||||
|
||||
error = NULL;
|
||||
filename = g_strconcat (ISO_CODES_DATADIR, "/", variant, ".xml", NULL);
|
||||
res = g_file_get_contents (filename, &buf, &buf_len, &error);
|
||||
if (res)
|
||||
{
|
||||
GMarkupParseContext *ctx = NULL;
|
||||
GMarkupParser parser = { languages_parse_start_tag, NULL, NULL, NULL, NULL };
|
||||
|
||||
ctx = g_markup_parse_context_new (&parser, 0, NULL, NULL);
|
||||
|
||||
res = g_markup_parse_context_parse (ctx, buf, buf_len, &error);
|
||||
g_free (ctx);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
g_warning ("Failed to parse '%s': %s\n", filename, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Failed to load '%s': %s\n", filename, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
g_free (buf);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
languages_init (void)
|
||||
{
|
||||
if (language_map)
|
||||
return;
|
||||
|
||||
language_map = g_hash_table_new_full (NULL, NULL, NULL, g_free);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
g_return_if_fail (EnumSystemLocalesEx (&get_win32_all_locales_scripts, LOCALE_ALL, (LPARAM) language_map, NULL));
|
||||
#else
|
||||
languages_variant_init ("iso_639");
|
||||
languages_variant_init ("iso_639_3");
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
get_language_name (Pango2Language *language)
|
||||
{
|
||||
languages_init ();
|
||||
|
||||
return (const char *) g_hash_table_lookup (language_map, language);
|
||||
}
|
||||
|
||||
const char *
|
||||
get_language_name_for_tag (guint32 tag)
|
||||
{
|
||||
hb_language_t lang;
|
||||
const char *s;
|
||||
|
||||
lang = hb_ot_tag_to_language (tag);
|
||||
s = hb_language_to_string (lang);
|
||||
|
||||
return get_language_name (pango2_language_from_string (s));
|
||||
}
|
13
demos/font-explorer/language-names.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef LANGUAGE_NAMES_H
|
||||
#define LANGUAGE_NAMES_H
|
||||
|
||||
#include <pango2/pango.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
const char * get_language_name (Pango2Language *language);
|
||||
const char * get_language_name_for_tag (guint32 tag);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
9
demos/font-explorer/main.c
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <fontexplorerapp.h>
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
return g_application_run (G_APPLICATION (font_explorer_app_new ()), argc, argv);
|
||||
}
|
35
demos/font-explorer/meson.build
Normal file
@@ -0,0 +1,35 @@
|
||||
fontexplorer_sources = [
|
||||
'fontcolors.c',
|
||||
'fontcontrols.c',
|
||||
'fontexplorerapp.c',
|
||||
'fontexplorerwin.c',
|
||||
'fontfeatures.c',
|
||||
'fontvariations.c',
|
||||
'glyphitem.c',
|
||||
'glyphmodel.c',
|
||||
'glyphsview.c',
|
||||
'glyphview.c',
|
||||
'infoview.c',
|
||||
'language-names.c',
|
||||
'main.c',
|
||||
'plainview.c',
|
||||
'rangeedit.c',
|
||||
'samplechooser.c',
|
||||
'sampleeditor.c',
|
||||
'styleview.c',
|
||||
'waterfallview.c',
|
||||
]
|
||||
|
||||
fontexplorer_resources = gnome.compile_resources('fontexplorer_resources',
|
||||
'fontexplorer.gresource.xml',
|
||||
source_dir: '.',
|
||||
)
|
||||
|
||||
executable('gtk4-font-explorer',
|
||||
sources: [fontexplorer_sources, fontexplorer_resources],
|
||||
c_args: common_cflags,
|
||||
dependencies: [ libgtk_dep, demo_conf_h ],
|
||||
include_directories: confinc,
|
||||
link_args: extra_demo_ldflags,
|
||||
install: true,
|
||||
)
|
343
demos/font-explorer/plainview.c
Normal file
@@ -0,0 +1,343 @@
|
||||
#include "plainview.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "glyphitem.h"
|
||||
#include "glyphmodel.h"
|
||||
#include "glyphview.h"
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
PROP_SIZE,
|
||||
PROP_LETTERSPACING,
|
||||
PROP_LINE_HEIGHT,
|
||||
PROP_FOREGROUND,
|
||||
PROP_BACKGROUND,
|
||||
PROP_VARIATIONS,
|
||||
PROP_FEATURES,
|
||||
PROP_PALETTE,
|
||||
PROP_SAMPLE_TEXT,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _PlainView
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GtkLabel *content;
|
||||
GtkScrolledWindow *swin;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
Pango2FontDescription *font_desc;
|
||||
float size;
|
||||
char *variations;
|
||||
char *features;
|
||||
char *palette;
|
||||
GQuark palette_quark;
|
||||
int letterspacing;
|
||||
float line_height;
|
||||
GdkRGBA foreground;
|
||||
GdkRGBA background;
|
||||
GtkCssProvider *bg_provider;
|
||||
char *sample_text;
|
||||
};
|
||||
|
||||
struct _PlainViewClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(PlainView, plain_view, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
plain_view_init (PlainView *self)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
self->font_desc = pango2_font_description_from_string ("sans 12");
|
||||
self->size = 12.;
|
||||
self->letterspacing = 0;
|
||||
self->line_height = 1.;
|
||||
self->variations = g_strdup ("");
|
||||
self->features = g_strdup ("");
|
||||
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
|
||||
self->palette_quark = g_quark_from_string (self->palette);
|
||||
self->foreground = (GdkRGBA){0., 0., 0., 1. };
|
||||
self->background = (GdkRGBA){1., 1., 1., 1. };
|
||||
self->sample_text = g_strdup ("Some sample text is better than other sample text");
|
||||
|
||||
gtk_widget_set_layout_manager (GTK_WIDGET (self),
|
||||
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
self->bg_provider = gtk_css_provider_new ();
|
||||
gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (self->content)),
|
||||
GTK_STYLE_PROVIDER (self->bg_provider), 800);
|
||||
}
|
||||
|
||||
static void
|
||||
plain_view_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), PLAIN_VIEW_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (plain_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
plain_view_finalize (GObject *object)
|
||||
{
|
||||
PlainView *self = PLAIN_VIEW (object);
|
||||
|
||||
g_clear_object (&self->font_map);
|
||||
pango2_font_description_free (self->font_desc);
|
||||
g_free (self->variations);
|
||||
g_free (self->features);
|
||||
g_free (self->palette);
|
||||
|
||||
G_OBJECT_CLASS (plain_view_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
update_view (PlainView *self)
|
||||
{
|
||||
Pango2FontDescription *desc;
|
||||
Pango2AttrList *attrs;
|
||||
char *fg, *bg, *css;
|
||||
|
||||
desc = pango2_font_description_copy_static (self->font_desc);
|
||||
pango2_font_description_set_size (desc, 12 * PANGO2_SCALE);
|
||||
pango2_font_description_set_variations (desc, self->variations);
|
||||
|
||||
attrs = pango2_attr_list_new ();
|
||||
pango2_attr_list_insert (attrs, pango2_attr_font_desc_new (desc));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_size_new (self->size * PANGO2_SCALE));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_letter_spacing_new (self->letterspacing));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_line_height_new (self->line_height));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_foreground_new (&(Pango2Color){65535 * self->foreground.red,
|
||||
65535 * self->foreground.green,
|
||||
65535 * self->foreground.blue,
|
||||
65535 * self->foreground.alpha}));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_font_features_new (self->features));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_palette_new (self->palette));
|
||||
|
||||
pango2_font_description_free (desc);
|
||||
|
||||
gtk_label_set_label (self->content, self->sample_text);
|
||||
gtk_label_set_attributes (self->content, attrs);
|
||||
|
||||
pango2_attr_list_unref (attrs);
|
||||
|
||||
fg = gdk_rgba_to_string (&self->foreground);
|
||||
bg = gdk_rgba_to_string (&self->background);
|
||||
css = g_strdup_printf (".content { caret-color: %s; background-color: %s; }", fg, bg);
|
||||
gtk_css_provider_load_from_data (self->bg_provider, css, strlen (css));
|
||||
g_free (css);
|
||||
g_free (fg);
|
||||
g_free (bg);
|
||||
}
|
||||
|
||||
static void
|
||||
plain_view_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PlainView *self = PLAIN_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
gtk_widget_set_font_map (GTK_WIDGET (self->content), self->font_map);
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
pango2_font_description_free (self->font_desc);
|
||||
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
self->size = g_value_get_float (value);
|
||||
break;
|
||||
|
||||
case PROP_LETTERSPACING:
|
||||
self->letterspacing = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_LINE_HEIGHT:
|
||||
self->line_height = g_value_get_float (value);
|
||||
break;
|
||||
|
||||
case PROP_FOREGROUND:
|
||||
self->foreground = *(GdkRGBA *)g_value_get_boxed (value);
|
||||
break;
|
||||
|
||||
case PROP_BACKGROUND:
|
||||
self->background = *(GdkRGBA *)g_value_get_boxed (value);
|
||||
break;
|
||||
|
||||
case PROP_VARIATIONS:
|
||||
g_free (self->variations);
|
||||
self->variations = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_FEATURES:
|
||||
g_free (self->features);
|
||||
self->features = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_PALETTE:
|
||||
g_free (self->palette);
|
||||
self->palette = g_strdup (g_value_get_string (value));
|
||||
self->palette_quark = g_quark_from_string (self->palette);
|
||||
break;
|
||||
|
||||
case PROP_SAMPLE_TEXT:
|
||||
g_free (self->sample_text);
|
||||
self->sample_text = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_view (self);
|
||||
}
|
||||
|
||||
static void
|
||||
plain_view_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PlainView *self = PLAIN_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
g_value_set_boxed (value, self->font_desc);
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
g_value_set_float (value, self->size);
|
||||
break;
|
||||
|
||||
case PROP_LETTERSPACING:
|
||||
g_value_set_int (value, self->letterspacing);
|
||||
break;
|
||||
|
||||
case PROP_LINE_HEIGHT:
|
||||
g_value_set_float (value, self->line_height);
|
||||
break;
|
||||
|
||||
case PROP_FOREGROUND:
|
||||
g_value_set_boxed (value, &self->foreground);
|
||||
break;
|
||||
|
||||
case PROP_BACKGROUND:
|
||||
g_value_set_boxed (value, &self->background);
|
||||
break;
|
||||
|
||||
case PROP_VARIATIONS:
|
||||
g_value_set_string (value, self->variations);
|
||||
break;
|
||||
|
||||
case PROP_FEATURES:
|
||||
g_value_set_string (value, self->features);
|
||||
break;
|
||||
|
||||
case PROP_PALETTE:
|
||||
g_value_set_string (value, self->palette);
|
||||
break;
|
||||
|
||||
case PROP_SAMPLE_TEXT:
|
||||
g_value_set_string (value, self->sample_text);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
plain_view_class_init (PlainViewClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = plain_view_dispose;
|
||||
object_class->finalize = plain_view_finalize;
|
||||
object_class->get_property = plain_view_get_property;
|
||||
object_class->set_property = plain_view_set_property;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FONT_DESC] =
|
||||
g_param_spec_boxed ("font-desc", "", "",
|
||||
PANGO2_TYPE_FONT_DESCRIPTION,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_SIZE] =
|
||||
g_param_spec_float ("size", "", "",
|
||||
0., 100., 12.,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_LETTERSPACING] =
|
||||
g_param_spec_int ("letterspacing", "", "",
|
||||
-G_MAXINT, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_LINE_HEIGHT] =
|
||||
g_param_spec_float ("line-height", "", "",
|
||||
0., 100., 1.,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FOREGROUND] =
|
||||
g_param_spec_boxed ("foreground", "", "",
|
||||
GDK_TYPE_RGBA,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_BACKGROUND] =
|
||||
g_param_spec_boxed ("background", "", "",
|
||||
GDK_TYPE_RGBA,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_VARIATIONS] =
|
||||
g_param_spec_string ("variations", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FEATURES] =
|
||||
g_param_spec_string ("features", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_PALETTE] =
|
||||
g_param_spec_string ("palette", "", "",
|
||||
PANGO2_COLOR_PALETTE_DEFAULT,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_SAMPLE_TEXT] =
|
||||
g_param_spec_string ("sample-text", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/plainview.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), PlainView, swin);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), PlainView, content);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "plainview");
|
||||
}
|
14
demos/font-explorer/plainview.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define PLAIN_VIEW_TYPE (plain_view_get_type ())
|
||||
#define PLAIN_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLAIN_VIEW_TYPE, PlainView))
|
||||
|
||||
|
||||
typedef struct _PlainView PlainView;
|
||||
typedef struct _PlainViewClass PlainViewClass;
|
||||
|
||||
|
||||
GType plain_view_get_type (void);
|
32
demos/font-explorer/plainview.ui
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="PlainView" parent="GtkWidget">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="swin">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="vscrollbar-policy">automatic</property>
|
||||
<style>
|
||||
<class name="view"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkLabel" id="content">
|
||||
<property name="label">Content</property>
|
||||
<property name="wrap">1</property>
|
||||
<property name="wrap-mode">word-char</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<property name="halign">fill</property>
|
||||
<property name="valign">fill</property>
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
174
demos/font-explorer/rangeedit.c
Normal file
@@ -0,0 +1,174 @@
|
||||
#include "rangeedit.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
enum {
|
||||
PROP_ADJUSTMENT = 1,
|
||||
PROP_DEFAULT_VALUE,
|
||||
PROP_N_CHARS,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _RangeEdit
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GtkAdjustment *adjustment;
|
||||
GtkScale *scale;
|
||||
GtkEntry *entry;
|
||||
double default_value;
|
||||
int n_chars;
|
||||
};
|
||||
|
||||
struct _RangeEditClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (RangeEdit, range_edit, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
range_edit_init (RangeEdit *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
range_edit_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), RANGE_EDIT_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (range_edit_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
range_edit_get_property (GObject *object,
|
||||
unsigned int prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
RangeEdit *self = RANGE_EDIT (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ADJUSTMENT:
|
||||
g_value_set_object (value, self->adjustment);
|
||||
break;
|
||||
|
||||
case PROP_DEFAULT_VALUE:
|
||||
g_value_set_double (value, self->default_value);
|
||||
break;
|
||||
|
||||
case PROP_N_CHARS:
|
||||
g_value_set_int (value, self->n_chars);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
adjustment_changed (GtkAdjustment *adjustment,
|
||||
RangeEdit *self)
|
||||
{
|
||||
char *str;
|
||||
|
||||
str = g_strdup_printf ("%.1f", gtk_adjustment_get_value (adjustment));
|
||||
gtk_editable_set_text (GTK_EDITABLE (self->entry), str);
|
||||
g_free (str);
|
||||
}
|
||||
|
||||
static void
|
||||
range_edit_set_property (GObject *object,
|
||||
unsigned int prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
RangeEdit *self = RANGE_EDIT (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ADJUSTMENT:
|
||||
g_set_object (&self->adjustment, g_value_get_object (value));
|
||||
g_signal_connect (self->adjustment, "value-changed", G_CALLBACK (adjustment_changed), self);
|
||||
adjustment_changed (self->adjustment, self);
|
||||
break;
|
||||
|
||||
case PROP_DEFAULT_VALUE:
|
||||
self->default_value = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_N_CHARS:
|
||||
self->n_chars = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
range_edit_constructed (GObject *object)
|
||||
{
|
||||
RangeEdit *self = RANGE_EDIT (object);
|
||||
|
||||
gtk_scale_add_mark (self->scale, self->default_value, GTK_POS_TOP, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
entry_activated (GtkEntry *entry,
|
||||
RangeEdit *self)
|
||||
{
|
||||
double value;
|
||||
char *err = NULL;
|
||||
|
||||
value = g_strtod (gtk_editable_get_text (GTK_EDITABLE (entry)), &err);
|
||||
if (err != NULL)
|
||||
gtk_adjustment_set_value (self->adjustment, value);
|
||||
}
|
||||
|
||||
static void
|
||||
range_edit_class_init (RangeEditClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = range_edit_dispose;
|
||||
object_class->get_property = range_edit_get_property;
|
||||
object_class->set_property = range_edit_set_property;
|
||||
object_class->constructed = range_edit_constructed;
|
||||
|
||||
properties[PROP_ADJUSTMENT] =
|
||||
g_param_spec_object ("adjustment", "", "",
|
||||
GTK_TYPE_ADJUSTMENT,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
properties[PROP_DEFAULT_VALUE] =
|
||||
g_param_spec_double ("default-value", "", "",
|
||||
-G_MAXDOUBLE, G_MAXDOUBLE, 0.,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
properties[PROP_N_CHARS] =
|
||||
g_param_spec_int ("n-chars", "", "",
|
||||
0, G_MAXINT, 10,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/rangeedit.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), RangeEdit, scale);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), RangeEdit, entry);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), entry_activated);
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "rangeedit");
|
||||
}
|
||||
|
||||
RangeEdit *
|
||||
range_edit_new (void)
|
||||
{
|
||||
return g_object_new (RANGE_EDIT_TYPE, NULL);
|
||||
}
|
15
demos/font-explorer/rangeedit.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define RANGE_EDIT_TYPE (range_edit_get_type ())
|
||||
#define RANGE_EDIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RANGE_EDIT_TYPE, RangeEdit))
|
||||
|
||||
|
||||
typedef struct _RangeEdit RangeEdit;
|
||||
typedef struct _RangeEditClass RangeEditClass;
|
||||
|
||||
|
||||
GType range_edit_get_type (void);
|
||||
RangeEdit * range_edit_new (void);
|
24
demos/font-explorer/rangeedit.ui
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="RangeEdit" parent="GtkWidget">
|
||||
<property name="layout-manager">
|
||||
<object class="GtkBoxLayout">
|
||||
<property name="spacing">10</property>
|
||||
</object>
|
||||
</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="scale">
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="adjustment" bind-source="RangeEdit" bind-flags="sync-create"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="entry">
|
||||
<property name="width-chars" bind-source="RangeEdit" bind-property="n-chars" bind-flags="sync-create"/>
|
||||
<property name="max-width-chars" bind-source="RangeEdit" bind-property="n-chars" bind-flags="sync-create"/>
|
||||
<signal name="activate" handler="entry_activated"/>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
163
demos/font-explorer/samplechooser.c
Normal file
@@ -0,0 +1,163 @@
|
||||
#include "samplechooser.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
enum {
|
||||
PROP_SAMPLE_TEXT = 1,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _SampleChooser
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
int sample;
|
||||
const char *sample_text;
|
||||
};
|
||||
|
||||
struct _SampleChooserClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(SampleChooser, sample_chooser, GTK_TYPE_WIDGET);
|
||||
|
||||
static const char *pangrams[] = {
|
||||
"The quick brown fox jumps over the lazy dog.",
|
||||
"Waltz, bad nymph, for quick jigs vex.",
|
||||
"Quick zephyrs blow, vexing daft Jim.",
|
||||
"Crazy Fredrick bought many very exquisite opal jewels.",
|
||||
"Jaded zombies acted quaintly but kept driving their oxen forward.",
|
||||
};
|
||||
|
||||
static const char *paragraphs[] = {
|
||||
"Grumpy wizards make toxic brew for the evil Queen and Jack. A quick movement of the enemy will jeopardize six gunboats. The job of waxing linoleum frequently peeves chintzy kids. My girl wove six dozen plaid jackets before she quit. Twelve ziggurats quickly jumped a finch box.",
|
||||
" Разъяренный чтец эгоистично бьёт пятью жердями шустрого фехтовальщика. Наш банк вчера же выплатил Ф.Я. Эйхгольду комиссию за ценные вещи. Эх, чужак, общий съём цен шляп (юфть) – вдрызг! В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!",
|
||||
"Τάχιστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός",
|
||||
};
|
||||
|
||||
static const char *alphabets[] = {
|
||||
"abcdefghijklmnopqrstuvwxyz",
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
"0123456789",
|
||||
"!@#$%^&*()?",
|
||||
};
|
||||
|
||||
static const char *titles[] = {
|
||||
"From My Cold Dead Hands",
|
||||
"From Afar Upon the Back of a Tiger",
|
||||
"Spontaneous Apple Creation",
|
||||
"Big Bizness (Screwed & Chopped)",
|
||||
"Pizza Shop Extended",
|
||||
"Good News & Bad News",
|
||||
};
|
||||
|
||||
static void
|
||||
next_pangram (GtkButton *button,
|
||||
SampleChooser *self)
|
||||
{
|
||||
self->sample++;
|
||||
self->sample_text = pangrams[self->sample % G_N_ELEMENTS (pangrams)];
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
|
||||
}
|
||||
|
||||
static void
|
||||
next_paragraph (GtkButton *button,
|
||||
SampleChooser *self)
|
||||
{
|
||||
self->sample++;
|
||||
self->sample_text = paragraphs[self->sample % G_N_ELEMENTS (paragraphs)];
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
|
||||
}
|
||||
|
||||
static void
|
||||
next_alphabet (GtkButton *button,
|
||||
SampleChooser *self)
|
||||
{
|
||||
self->sample++;
|
||||
self->sample_text = alphabets[self->sample % G_N_ELEMENTS (alphabets)];
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
|
||||
}
|
||||
|
||||
static void
|
||||
next_title (GtkButton *button,
|
||||
SampleChooser *self)
|
||||
{
|
||||
self->sample++;
|
||||
self->sample_text = titles[self->sample % G_N_ELEMENTS (titles)];
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
|
||||
}
|
||||
|
||||
static void
|
||||
sample_chooser_init (SampleChooser *self)
|
||||
{
|
||||
self->sample_text = "Boring sample text";
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
sample_chooser_dispose (GObject *object)
|
||||
{
|
||||
GtkWidget *child;
|
||||
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), SAMPLE_CHOOSER_TYPE);
|
||||
|
||||
while ((child = gtk_widget_get_first_child (GTK_WIDGET (object))) != NULL)
|
||||
gtk_widget_unparent (child);
|
||||
|
||||
G_OBJECT_CLASS (sample_chooser_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sample_chooser_get_property (GObject *object,
|
||||
unsigned int prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SampleChooser *self = SAMPLE_CHOOSER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SAMPLE_TEXT:
|
||||
g_value_set_string (value, self->sample_text);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sample_chooser_class_init (SampleChooserClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = sample_chooser_dispose;
|
||||
object_class->get_property = sample_chooser_get_property;
|
||||
|
||||
properties[PROP_SAMPLE_TEXT] =
|
||||
g_param_spec_string ("sample-text", "", "",
|
||||
"",
|
||||
G_PARAM_READABLE);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/samplechooser.ui");
|
||||
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), next_pangram);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), next_paragraph);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), next_alphabet);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), next_title);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "samplechooser");
|
||||
}
|
||||
|
||||
SampleChooser *
|
||||
sample_chooser_new (void)
|
||||
{
|
||||
return g_object_new (SAMPLE_CHOOSER_TYPE, NULL);
|
||||
}
|
15
demos/font-explorer/samplechooser.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define SAMPLE_CHOOSER_TYPE (sample_chooser_get_type ())
|
||||
#define SAMPLE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SAMPLE_CHOOSER_TYPE, SampleChooser))
|
||||
|
||||
|
||||
typedef struct _SampleChooser SampleChooser;
|
||||
typedef struct _SampleChooserClass SampleChooserClass;
|
||||
|
||||
|
||||
GType sample_chooser_get_type (void);
|
||||
SampleChooser * sample_chooser_new (void);
|
46
demos/font-explorer/samplechooser.ui
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="SampleChooser" parent="GtkWidget">
|
||||
<property name="layout-manager"><object class="GtkGridLayout"/></property>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="label">Pangram</property>
|
||||
<signal name="clicked" handler="next_pangram"/>
|
||||
<layout>
|
||||
<property name="row">0</property>
|
||||
<property name="column">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="label">Paragraph</property>
|
||||
<signal name="clicked" handler="next_paragraph"/>
|
||||
<layout>
|
||||
<property name="row">0</property>
|
||||
<property name="column">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="label">Alphabet</property>
|
||||
<signal name="clicked" handler="next_alphabet"/>
|
||||
<layout>
|
||||
<property name="row">1</property>
|
||||
<property name="column">0</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="label">Title</property>
|
||||
<signal name="clicked" handler="next_title"/>
|
||||
<layout>
|
||||
<property name="row">1</property>
|
||||
<property name="column">1</property>
|
||||
</layout>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
162
demos/font-explorer/sampleeditor.c
Normal file
@@ -0,0 +1,162 @@
|
||||
#include "sampleeditor.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
enum {
|
||||
PROP_SAMPLE_TEXT = 1,
|
||||
PROP_EDITING,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _SampleEditor
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GtkTextView *edit;
|
||||
char *sample_text;
|
||||
gboolean editing;
|
||||
};
|
||||
|
||||
struct _SampleEditorClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(SampleEditor, sample_editor, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
sample_editor_init (SampleEditor *self)
|
||||
{
|
||||
self->sample_text = g_strdup ("Some sample text is better than other sample text");
|
||||
self->editing = FALSE;
|
||||
|
||||
gtk_widget_set_layout_manager (GTK_WIDGET (self),
|
||||
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
sample_editor_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), SAMPLE_EDITOR_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (sample_editor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
sample_editor_finalize (GObject *object)
|
||||
{
|
||||
SampleEditor *self = SAMPLE_EDITOR (object);
|
||||
|
||||
g_free (self->sample_text);
|
||||
|
||||
G_OBJECT_CLASS (sample_editor_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
update_editing (SampleEditor *self,
|
||||
gboolean editing)
|
||||
{
|
||||
GtkTextBuffer *buffer;
|
||||
|
||||
if (self->editing == editing)
|
||||
return;
|
||||
|
||||
self->editing = editing;
|
||||
|
||||
buffer = gtk_text_view_get_buffer (self->edit);
|
||||
|
||||
if (self->editing)
|
||||
{
|
||||
gtk_text_buffer_set_text (buffer, self->sample_text, -1);
|
||||
gtk_widget_grab_focus (GTK_WIDGET (self->edit));
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkTextIter start, end;
|
||||
|
||||
g_free (self->sample_text);
|
||||
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
||||
self->sample_text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SAMPLE_TEXT]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sample_editor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SampleEditor *self = SAMPLE_EDITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SAMPLE_TEXT:
|
||||
g_free (self->sample_text);
|
||||
self->sample_text = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_EDITING:
|
||||
update_editing (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sample_editor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
SampleEditor *self = SAMPLE_EDITOR (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SAMPLE_TEXT:
|
||||
g_value_set_string (value, self->sample_text);
|
||||
break;
|
||||
|
||||
case PROP_EDITING:
|
||||
g_value_set_boolean (value, self->editing);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sample_editor_class_init (SampleEditorClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = sample_editor_dispose;
|
||||
object_class->finalize = sample_editor_finalize;
|
||||
object_class->get_property = sample_editor_get_property;
|
||||
object_class->set_property = sample_editor_set_property;
|
||||
|
||||
properties[PROP_SAMPLE_TEXT] =
|
||||
g_param_spec_string ("sample-text", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_EDITING] =
|
||||
g_param_spec_boolean ("editing", "", "",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/sampleeditor.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), SampleEditor, edit);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "sampleeditor");
|
||||
}
|
14
demos/font-explorer/sampleeditor.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define SAMPLE_EDITOR_TYPE (sample_editor_get_type ())
|
||||
#define SAMPLE_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SAMPLE_EDITOR_TYPE, SampleEditor))
|
||||
|
||||
|
||||
typedef struct _SampleEditor SampleEditor;
|
||||
typedef struct _SampleEditorClass SampleEditorClass;
|
||||
|
||||
|
||||
GType sample_editor_get_type (void);
|
25
demos/font-explorer/sampleeditor.ui
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="SampleEditor" parent="GtkWidget">
|
||||
<style>
|
||||
<class name="view"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<property name="vscrollbar-policy">automatic</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkTextView" id="edit">
|
||||
<property name="wrap-mode">word-char</property>
|
||||
<property name="left-margin">20</property>
|
||||
<property name="right-margin">20</property>
|
||||
<property name="top-margin">20</property>
|
||||
<property name="bottom-margin">20</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
506
demos/font-explorer/styleview.c
Normal file
@@ -0,0 +1,506 @@
|
||||
#include "styleview.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "glyphitem.h"
|
||||
#include "glyphmodel.h"
|
||||
#include "glyphview.h"
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
PROP_SIZE,
|
||||
PROP_LETTERSPACING,
|
||||
PROP_LINE_HEIGHT,
|
||||
PROP_FOREGROUND,
|
||||
PROP_BACKGROUND,
|
||||
PROP_VARIATIONS,
|
||||
PROP_FEATURES,
|
||||
PROP_PALETTE,
|
||||
PROP_SAMPLE_TEXT,
|
||||
PROP_HAS_STYLES,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _StyleView
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GtkLabel *content;
|
||||
GtkScrolledWindow *swin;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
Pango2FontDescription *font_desc;
|
||||
float size;
|
||||
char *variations;
|
||||
char *features;
|
||||
char *palette;
|
||||
GQuark palette_quark;
|
||||
int letterspacing;
|
||||
float line_height;
|
||||
GdkRGBA foreground;
|
||||
GdkRGBA background;
|
||||
GtkCssProvider *bg_provider;
|
||||
char *sample_text;
|
||||
gboolean has_styles;
|
||||
};
|
||||
|
||||
struct _StyleViewClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(StyleView, style_view, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
style_view_init (StyleView *self)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
self->font_desc = pango2_font_description_from_string ("sans 12");
|
||||
self->size = 12.;
|
||||
self->letterspacing = 0;
|
||||
self->line_height = 1.;
|
||||
self->variations = g_strdup ("");
|
||||
self->features = g_strdup ("");
|
||||
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
|
||||
self->palette_quark = g_quark_from_string (self->palette);
|
||||
self->foreground = (GdkRGBA){0., 0., 0., 1. };
|
||||
self->background = (GdkRGBA){1., 1., 1., 1. };
|
||||
self->sample_text = g_strdup ("Some sample text is better than other sample text");
|
||||
self->has_styles = FALSE;
|
||||
|
||||
gtk_widget_set_layout_manager (GTK_WIDGET (self),
|
||||
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
self->bg_provider = gtk_css_provider_new ();
|
||||
gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (self->content)),
|
||||
GTK_STYLE_PROVIDER (self->bg_provider), 800);
|
||||
}
|
||||
|
||||
static void
|
||||
style_view_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), STYLE_VIEW_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (style_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
style_view_finalize (GObject *object)
|
||||
{
|
||||
StyleView *self = STYLE_VIEW (object);
|
||||
|
||||
g_clear_object (&self->font_map);
|
||||
pango2_font_description_free (self->font_desc);
|
||||
g_free (self->variations);
|
||||
g_free (self->features);
|
||||
g_free (self->palette);
|
||||
|
||||
G_OBJECT_CLASS (style_view_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static Pango2Font *
|
||||
get_font (StyleView *self)
|
||||
{
|
||||
Pango2Context *context;
|
||||
Pango2FontDescription *desc;
|
||||
Pango2Font *font;
|
||||
|
||||
context = pango2_context_new_with_font_map (self->font_map);
|
||||
desc = pango2_font_description_copy_static (self->font_desc);
|
||||
pango2_font_description_set_variations (desc, self->variations);
|
||||
pango2_font_description_set_size (desc, self->size * PANGO2_SCALE);
|
||||
font = pango2_context_load_font (context, desc);
|
||||
pango2_font_description_free (desc);
|
||||
g_object_unref (context);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static void
|
||||
update_has_styles (StyleView *self)
|
||||
{
|
||||
Pango2Font *font = get_font (self);
|
||||
hb_face_t *hb_face = hb_font_get_face (pango2_font_get_hb_font (font));
|
||||
gboolean has_styles;
|
||||
|
||||
has_styles = hb_ot_var_get_named_instance_count (hb_face) > 0;
|
||||
g_object_unref (font);
|
||||
|
||||
if (self->has_styles == has_styles)
|
||||
return;
|
||||
|
||||
self->has_styles = has_styles;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HAS_STYLES]);
|
||||
}
|
||||
|
||||
static int
|
||||
measure_names (Pango2Context *context,
|
||||
hb_face_t *hb_face)
|
||||
{
|
||||
Pango2Layout *layout;
|
||||
Pango2FontDescription *desc;
|
||||
GString *str;
|
||||
int width, height;
|
||||
|
||||
layout = pango2_layout_new (context);
|
||||
|
||||
desc = pango2_font_description_from_string ("Cantarell Regular 12");
|
||||
pango2_layout_set_font_description (layout, desc);
|
||||
pango2_font_description_free (desc);
|
||||
|
||||
str = g_string_new ("");
|
||||
|
||||
for (int i = 0; i < hb_ot_var_get_named_instance_count (hb_face); i++)
|
||||
{
|
||||
hb_ot_name_id_t name_id;
|
||||
char name[20];
|
||||
unsigned int name_len = 20;
|
||||
|
||||
name_id = hb_ot_var_named_instance_get_subfamily_name_id (hb_face, i);
|
||||
hb_ot_name_get_utf8 (hb_face, name_id, HB_LANGUAGE_INVALID, &name_len, name);
|
||||
g_string_append_printf (str, " %s\n", name);
|
||||
}
|
||||
|
||||
pango2_layout_set_text (layout, str->str, -1);
|
||||
pango2_lines_get_size (pango2_layout_get_lines (layout), &width, &height);
|
||||
|
||||
g_string_free (str, TRUE);
|
||||
|
||||
g_object_unref (layout);
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
static void
|
||||
update_view (StyleView *self)
|
||||
{
|
||||
Pango2FontDescription *desc;
|
||||
Pango2AttrList *attrs;
|
||||
char *fg, *bg, *css;
|
||||
GString *str;
|
||||
int start, end, text_len;
|
||||
Pango2Font *font = get_font (self);
|
||||
hb_face_t *hb_face = hb_font_get_face (pango2_font_get_hb_font (font));
|
||||
unsigned int n_axes;
|
||||
float *coords = NULL;
|
||||
hb_ot_var_axis_info_t *axes;
|
||||
Pango2FontDescription *label_desc;
|
||||
Pango2TabArray *tabs;
|
||||
int width;
|
||||
|
||||
desc = pango2_font_description_copy_static (self->font_desc);
|
||||
pango2_font_description_set_variations (desc, self->variations);
|
||||
pango2_font_description_set_size (desc, self->size * PANGO2_SCALE);
|
||||
|
||||
attrs = pango2_attr_list_new ();
|
||||
pango2_attr_list_insert (attrs, pango2_attr_font_desc_new (desc));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_letter_spacing_new (self->letterspacing));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_line_height_new (self->line_height));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_foreground_new (&(Pango2Color){65535 * self->foreground.red,
|
||||
65535 * self->foreground.green,
|
||||
65535 * self->foreground.blue,
|
||||
65535 * self->foreground.alpha}));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_font_features_new (self->features));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_palette_new (self->palette));
|
||||
|
||||
str = g_string_new ("");
|
||||
start = 0;
|
||||
text_len = strlen (self->sample_text);
|
||||
|
||||
n_axes = hb_ot_var_get_axis_count (hb_face);
|
||||
axes = g_newa (hb_ot_var_axis_info_t, n_axes);
|
||||
hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, axes);
|
||||
coords = g_newa (float, n_axes);
|
||||
|
||||
label_desc = pango2_font_description_from_string ("Cantarell Regular 12");
|
||||
|
||||
width = measure_names (gtk_widget_get_pango_context (GTK_WIDGET (self->content)), hb_face);
|
||||
|
||||
tabs = pango2_tab_array_new (1, PANGO2_TAB_POSITIONS_DEFAULT);
|
||||
pango2_tab_array_set_tab (tabs, 0, PANGO2_TAB_LEFT, width);
|
||||
gtk_label_set_tabs (self->content, tabs);
|
||||
pango2_tab_array_free (tabs);
|
||||
|
||||
for (int i = 0; i < hb_ot_var_get_named_instance_count (hb_face); i++)
|
||||
{
|
||||
unsigned int n_coords = n_axes;
|
||||
Pango2Attribute *attr;
|
||||
GString *variations;
|
||||
hb_ot_name_id_t name_id;
|
||||
char name[20];
|
||||
unsigned int name_len = 20;
|
||||
|
||||
name_id = hb_ot_var_named_instance_get_subfamily_name_id (hb_face, i);
|
||||
hb_ot_name_get_utf8 (hb_face, name_id, HB_LANGUAGE_INVALID, &name_len, name);
|
||||
|
||||
g_string_append_printf (str, "%s\t", name);
|
||||
end = str->len;
|
||||
|
||||
attr = pango2_attr_font_desc_new (label_desc);
|
||||
pango2_attribute_set_range (attr, start, end);
|
||||
pango2_attr_list_insert (attrs, attr);
|
||||
start = end;
|
||||
|
||||
hb_ot_var_named_instance_get_design_coords (hb_face, i, &n_coords, coords);
|
||||
variations = g_string_new ("");
|
||||
for (int j = 0; j < n_axes; j++)
|
||||
{
|
||||
char buf[5] = { 0, };
|
||||
|
||||
if (variations->len > 0)
|
||||
g_string_append_c (variations, ',');
|
||||
hb_tag_to_string (axes[j].tag, buf);
|
||||
g_string_append_printf (variations, "%s=%f", buf, coords[j]);
|
||||
}
|
||||
|
||||
g_string_append (str, self->sample_text);
|
||||
g_string_append (str, "
"); /* Unicode line separator */
|
||||
end = start + text_len + strlen ("
");
|
||||
|
||||
pango2_font_description_set_variations (desc, variations->str);
|
||||
g_string_free (variations, TRUE);
|
||||
|
||||
attr = pango2_attr_font_desc_new (desc);
|
||||
pango2_attribute_set_range (attr, start, end);
|
||||
pango2_attr_list_insert (attrs, attr);
|
||||
start = end;
|
||||
}
|
||||
|
||||
pango2_font_description_free (label_desc);
|
||||
|
||||
gtk_label_set_text (self->content, str->str);
|
||||
gtk_label_set_attributes (self->content, attrs);
|
||||
g_string_free (str, TRUE);
|
||||
|
||||
pango2_attr_list_unref (attrs);
|
||||
pango2_font_description_free (desc);
|
||||
|
||||
fg = gdk_rgba_to_string (&self->foreground);
|
||||
bg = gdk_rgba_to_string (&self->background);
|
||||
css = g_strdup_printf (".content { caret-color: %s; background-color: %s; }", fg, bg);
|
||||
gtk_css_provider_load_from_data (self->bg_provider, css, strlen (css));
|
||||
g_free (css);
|
||||
g_free (fg);
|
||||
g_free (bg);
|
||||
|
||||
g_object_unref (font);
|
||||
}
|
||||
|
||||
static void
|
||||
style_view_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StyleView *self = STYLE_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
gtk_widget_set_font_map (GTK_WIDGET (self->content), self->font_map);
|
||||
update_has_styles (self);
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
pango2_font_description_free (self->font_desc);
|
||||
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
|
||||
update_has_styles (self);
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
self->size = g_value_get_float (value);
|
||||
break;
|
||||
|
||||
case PROP_LETTERSPACING:
|
||||
self->letterspacing = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_LINE_HEIGHT:
|
||||
self->line_height = g_value_get_float (value);
|
||||
break;
|
||||
|
||||
case PROP_FOREGROUND:
|
||||
self->foreground = *(GdkRGBA *)g_value_get_boxed (value);
|
||||
break;
|
||||
|
||||
case PROP_BACKGROUND:
|
||||
self->background = *(GdkRGBA *)g_value_get_boxed (value);
|
||||
break;
|
||||
|
||||
case PROP_VARIATIONS:
|
||||
g_free (self->variations);
|
||||
self->variations = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_FEATURES:
|
||||
g_free (self->features);
|
||||
self->features = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_PALETTE:
|
||||
g_free (self->palette);
|
||||
self->palette = g_strdup (g_value_get_string (value));
|
||||
self->palette_quark = g_quark_from_string (self->palette);
|
||||
break;
|
||||
|
||||
case PROP_SAMPLE_TEXT:
|
||||
g_free (self->sample_text);
|
||||
self->sample_text = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_view (self);
|
||||
}
|
||||
|
||||
static void
|
||||
style_view_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StyleView *self = STYLE_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
g_value_set_boxed (value, self->font_desc);
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
g_value_set_float (value, self->size);
|
||||
break;
|
||||
|
||||
case PROP_LETTERSPACING:
|
||||
g_value_set_int (value, self->letterspacing);
|
||||
break;
|
||||
|
||||
case PROP_LINE_HEIGHT:
|
||||
g_value_set_float (value, self->line_height);
|
||||
break;
|
||||
|
||||
case PROP_FOREGROUND:
|
||||
g_value_set_boxed (value, &self->foreground);
|
||||
break;
|
||||
|
||||
case PROP_BACKGROUND:
|
||||
g_value_set_boxed (value, &self->background);
|
||||
break;
|
||||
|
||||
case PROP_VARIATIONS:
|
||||
g_value_set_string (value, self->variations);
|
||||
break;
|
||||
|
||||
case PROP_FEATURES:
|
||||
g_value_set_string (value, self->features);
|
||||
break;
|
||||
|
||||
case PROP_PALETTE:
|
||||
g_value_set_string (value, self->palette);
|
||||
break;
|
||||
|
||||
case PROP_SAMPLE_TEXT:
|
||||
g_value_set_string (value, self->sample_text);
|
||||
break;
|
||||
|
||||
case PROP_HAS_STYLES:
|
||||
g_value_set_boolean (value, self->has_styles);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
style_view_class_init (StyleViewClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = style_view_dispose;
|
||||
object_class->finalize = style_view_finalize;
|
||||
object_class->get_property = style_view_get_property;
|
||||
object_class->set_property = style_view_set_property;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FONT_DESC] =
|
||||
g_param_spec_boxed ("font-desc", "", "",
|
||||
PANGO2_TYPE_FONT_DESCRIPTION,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_SIZE] =
|
||||
g_param_spec_float ("size", "", "",
|
||||
0., 100., 12.,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_LETTERSPACING] =
|
||||
g_param_spec_int ("letterspacing", "", "",
|
||||
-G_MAXINT, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_LINE_HEIGHT] =
|
||||
g_param_spec_float ("line-height", "", "",
|
||||
0., 100., 1.,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FOREGROUND] =
|
||||
g_param_spec_boxed ("foreground", "", "",
|
||||
GDK_TYPE_RGBA,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_BACKGROUND] =
|
||||
g_param_spec_boxed ("background", "", "",
|
||||
GDK_TYPE_RGBA,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_VARIATIONS] =
|
||||
g_param_spec_string ("variations", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FEATURES] =
|
||||
g_param_spec_string ("features", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_PALETTE] =
|
||||
g_param_spec_string ("palette", "", "",
|
||||
PANGO2_COLOR_PALETTE_DEFAULT,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_SAMPLE_TEXT] =
|
||||
g_param_spec_string ("sample-text", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_HAS_STYLES] =
|
||||
g_param_spec_boolean ("has-styles", "", "",
|
||||
FALSE,
|
||||
G_PARAM_READABLE);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/styleview.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), StyleView, swin);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), StyleView, content);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "styleview");
|
||||
}
|
14
demos/font-explorer/styleview.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define STYLE_VIEW_TYPE (style_view_get_type ())
|
||||
#define STYLE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STYLE_VIEW_TYPE, StyleView))
|
||||
|
||||
|
||||
typedef struct _StyleView StyleView;
|
||||
typedef struct _StyleViewClass StyleViewClass;
|
||||
|
||||
|
||||
GType style_view_get_type (void);
|
31
demos/font-explorer/styleview.ui
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="StyleView" parent="GtkWidget">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<style>
|
||||
<class name="view"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="swin">
|
||||
<property name="hscrollbar-policy">automatic</property>
|
||||
<property name="vscrollbar-policy">automatic</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="content">
|
||||
<property name="label">Content</property>
|
||||
<property name="wrap">0</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<property name="halign">fill</property>
|
||||
<property name="valign">fill</property>
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
401
demos/font-explorer/waterfallview.c
Normal file
@@ -0,0 +1,401 @@
|
||||
#include "waterfallview.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <hb-ot.h>
|
||||
|
||||
#include "glyphitem.h"
|
||||
#include "glyphmodel.h"
|
||||
#include "glyphview.h"
|
||||
|
||||
enum {
|
||||
PROP_FONT_MAP = 1,
|
||||
PROP_FONT_DESC,
|
||||
PROP_SIZE,
|
||||
PROP_LETTERSPACING,
|
||||
PROP_LINE_HEIGHT,
|
||||
PROP_FOREGROUND,
|
||||
PROP_BACKGROUND,
|
||||
PROP_VARIATIONS,
|
||||
PROP_FEATURES,
|
||||
PROP_PALETTE,
|
||||
PROP_SAMPLE_TEXT,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _WaterfallView
|
||||
{
|
||||
GtkWidget parent;
|
||||
|
||||
GtkLabel *content;
|
||||
GtkScrolledWindow *swin;
|
||||
|
||||
Pango2FontMap *font_map;
|
||||
Pango2FontDescription *font_desc;
|
||||
float size;
|
||||
char *variations;
|
||||
char *features;
|
||||
char *palette;
|
||||
GQuark palette_quark;
|
||||
int letterspacing;
|
||||
float line_height;
|
||||
GdkRGBA foreground;
|
||||
GdkRGBA background;
|
||||
GtkCssProvider *bg_provider;
|
||||
char *sample_text;
|
||||
};
|
||||
|
||||
struct _WaterfallViewClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(WaterfallView, waterfall_view, GTK_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
waterfall_view_init (WaterfallView *self)
|
||||
{
|
||||
self->font_map = g_object_ref (pango2_font_map_get_default ());
|
||||
self->font_desc = pango2_font_description_from_string ("sans 12");
|
||||
self->size = 12.;
|
||||
self->letterspacing = 0;
|
||||
self->line_height = 1.;
|
||||
self->variations = g_strdup ("");
|
||||
self->features = g_strdup ("");
|
||||
self->palette = g_strdup (PANGO2_COLOR_PALETTE_DEFAULT);
|
||||
self->palette_quark = g_quark_from_string (self->palette);
|
||||
self->foreground = (GdkRGBA){0., 0., 0., 1. };
|
||||
self->background = (GdkRGBA){1., 1., 1., 1. };
|
||||
self->sample_text = g_strdup ("Some sample text is better than other sample text");
|
||||
|
||||
gtk_widget_set_layout_manager (GTK_WIDGET (self),
|
||||
gtk_box_layout_new (GTK_ORIENTATION_VERTICAL));
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
self->bg_provider = gtk_css_provider_new ();
|
||||
gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (self->content)),
|
||||
GTK_STYLE_PROVIDER (self->bg_provider), 800);
|
||||
}
|
||||
|
||||
static void
|
||||
waterfall_view_dispose (GObject *object)
|
||||
{
|
||||
gtk_widget_clear_template (GTK_WIDGET (object), WATERFALL_VIEW_TYPE);
|
||||
|
||||
G_OBJECT_CLASS (waterfall_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
waterfall_view_finalize (GObject *object)
|
||||
{
|
||||
WaterfallView *self = WATERFALL_VIEW (object);
|
||||
|
||||
g_clear_object (&self->font_map);
|
||||
pango2_font_description_free (self->font_desc);
|
||||
g_free (self->variations);
|
||||
g_free (self->features);
|
||||
g_free (self->palette);
|
||||
|
||||
G_OBJECT_CLASS (waterfall_view_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
update_view (WaterfallView *self)
|
||||
{
|
||||
Pango2FontDescription *desc;
|
||||
Pango2AttrList *attrs;
|
||||
char *fg, *bg, *css;
|
||||
GString *str;
|
||||
int sizes[] = { 7, 8, 9, 10, 12, 14, 16, 20, 24, 30, 40, 50, 60, 70, 90, 120 };
|
||||
int start, end, text_len;
|
||||
Pango2TabArray *tabs;
|
||||
|
||||
desc = pango2_font_description_copy_static (self->font_desc);
|
||||
pango2_font_description_set_size (desc, 12 * PANGO2_SCALE);
|
||||
pango2_font_description_set_variations (desc, self->variations);
|
||||
|
||||
attrs = pango2_attr_list_new ();
|
||||
pango2_attr_list_insert (attrs, pango2_attr_font_desc_new (desc));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_size_new (self->size * PANGO2_SCALE));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_line_height_new (self->line_height));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_letter_spacing_new (self->letterspacing));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_foreground_new (&(Pango2Color){65535 * self->foreground.red,
|
||||
65535 * self->foreground.green,
|
||||
65535 * self->foreground.blue,
|
||||
65535 * self->foreground.alpha}));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_font_features_new (self->features));
|
||||
pango2_attr_list_insert (attrs, pango2_attr_palette_new (self->palette));
|
||||
|
||||
pango2_font_description_free (desc);
|
||||
|
||||
tabs = pango2_tab_array_new (2, PANGO2_TAB_POSITIONS_SPACES);
|
||||
pango2_tab_array_set_tab (tabs, 0, PANGO2_TAB_RIGHT, 5);
|
||||
pango2_tab_array_set_tab (tabs, 1, PANGO2_TAB_LEFT, 8);
|
||||
|
||||
gtk_label_set_tabs (self->content, tabs);
|
||||
pango2_tab_array_free (tabs);
|
||||
|
||||
str = g_string_new ("");
|
||||
start = 0;
|
||||
text_len = strlen (self->sample_text);
|
||||
for (int i = 0; i < G_N_ELEMENTS (sizes); i++)
|
||||
{
|
||||
Pango2Attribute *attr;
|
||||
|
||||
g_string_append_printf (str, "\t%d\t", sizes[i]);
|
||||
|
||||
end = str->len;
|
||||
|
||||
attr = pango2_attr_family_new ("Cantarell");
|
||||
pango2_attribute_set_range (attr, start, end);
|
||||
pango2_attr_list_insert (attrs, attr);
|
||||
|
||||
attr = pango2_attr_weight_new (PANGO2_WEIGHT_NORMAL);
|
||||
pango2_attribute_set_range (attr, start, end);
|
||||
pango2_attr_list_insert (attrs, attr);
|
||||
|
||||
attr = pango2_attr_style_new (PANGO2_STYLE_NORMAL);
|
||||
pango2_attribute_set_range (attr, start, end);
|
||||
pango2_attr_list_insert (attrs, attr);
|
||||
|
||||
attr = pango2_attr_size_new (12 * PANGO2_SCALE);
|
||||
pango2_attribute_set_range (attr, start, end);
|
||||
pango2_attr_list_insert (attrs, attr);
|
||||
|
||||
attr = pango2_attr_font_features_new ("tnum=1");
|
||||
pango2_attribute_set_range (attr, start, end);
|
||||
pango2_attr_list_insert (attrs, attr);
|
||||
|
||||
attr = pango2_attr_letter_spacing_new (0);
|
||||
pango2_attribute_set_range (attr, start, end);
|
||||
pango2_attr_list_insert (attrs, attr);
|
||||
start = end;
|
||||
|
||||
g_string_append (str, self->sample_text);
|
||||
g_string_append (str, "
"); /* Unicode line separator */
|
||||
end = start + text_len + strlen ("
");
|
||||
|
||||
attr = pango2_attr_size_new (sizes[i] * PANGO2_SCALE);
|
||||
pango2_attribute_set_range (attr, start, end);
|
||||
pango2_attr_list_insert (attrs, attr);
|
||||
|
||||
start = end;
|
||||
}
|
||||
gtk_label_set_text (self->content, str->str);
|
||||
gtk_label_set_attributes (self->content, attrs);
|
||||
g_string_free (str, TRUE);
|
||||
|
||||
pango2_attr_list_unref (attrs);
|
||||
|
||||
fg = gdk_rgba_to_string (&self->foreground);
|
||||
bg = gdk_rgba_to_string (&self->background);
|
||||
css = g_strdup_printf (".content { caret-color: %s; background-color: %s; }", fg, bg);
|
||||
gtk_css_provider_load_from_data (self->bg_provider, css, strlen (css));
|
||||
g_free (css);
|
||||
g_free (fg);
|
||||
g_free (bg);
|
||||
}
|
||||
|
||||
static void
|
||||
waterfall_view_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
WaterfallView *self = WATERFALL_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_set_object (&self->font_map, g_value_get_object (value));
|
||||
gtk_widget_set_font_map (GTK_WIDGET (self->content), self->font_map);
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
pango2_font_description_free (self->font_desc);
|
||||
self->font_desc = pango2_font_description_copy (g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
self->size = g_value_get_float (value);
|
||||
break;
|
||||
|
||||
case PROP_LETTERSPACING:
|
||||
self->letterspacing = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_LINE_HEIGHT:
|
||||
self->line_height = g_value_get_float (value);
|
||||
break;
|
||||
|
||||
case PROP_FOREGROUND:
|
||||
self->foreground = *(GdkRGBA *)g_value_get_boxed (value);
|
||||
break;
|
||||
|
||||
case PROP_BACKGROUND:
|
||||
self->background = *(GdkRGBA *)g_value_get_boxed (value);
|
||||
break;
|
||||
|
||||
case PROP_VARIATIONS:
|
||||
g_free (self->variations);
|
||||
self->variations = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_FEATURES:
|
||||
g_free (self->features);
|
||||
self->features = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_PALETTE:
|
||||
g_free (self->palette);
|
||||
self->palette = g_strdup (g_value_get_string (value));
|
||||
self->palette_quark = g_quark_from_string (self->palette);
|
||||
break;
|
||||
|
||||
case PROP_SAMPLE_TEXT:
|
||||
g_free (self->sample_text);
|
||||
self->sample_text = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
|
||||
update_view (self);
|
||||
}
|
||||
|
||||
static void
|
||||
waterfall_view_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
WaterfallView *self = WATERFALL_VIEW (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FONT_MAP:
|
||||
g_value_set_object (value, self->font_map);
|
||||
break;
|
||||
|
||||
case PROP_FONT_DESC:
|
||||
g_value_set_boxed (value, self->font_desc);
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
g_value_set_float (value, self->size);
|
||||
break;
|
||||
|
||||
case PROP_LETTERSPACING:
|
||||
g_value_set_int (value, self->letterspacing);
|
||||
break;
|
||||
|
||||
case PROP_LINE_HEIGHT:
|
||||
g_value_set_float (value, self->line_height);
|
||||
break;
|
||||
|
||||
case PROP_FOREGROUND:
|
||||
g_value_set_boxed (value, &self->foreground);
|
||||
break;
|
||||
|
||||
case PROP_BACKGROUND:
|
||||
g_value_set_boxed (value, &self->background);
|
||||
break;
|
||||
|
||||
case PROP_VARIATIONS:
|
||||
g_value_set_string (value, self->variations);
|
||||
break;
|
||||
|
||||
case PROP_FEATURES:
|
||||
g_value_set_string (value, self->features);
|
||||
break;
|
||||
|
||||
case PROP_PALETTE:
|
||||
g_value_set_string (value, self->palette);
|
||||
break;
|
||||
|
||||
case PROP_SAMPLE_TEXT:
|
||||
g_value_set_string (value, self->sample_text);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
waterfall_view_class_init (WaterfallViewClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = waterfall_view_dispose;
|
||||
object_class->finalize = waterfall_view_finalize;
|
||||
object_class->get_property = waterfall_view_get_property;
|
||||
object_class->set_property = waterfall_view_set_property;
|
||||
|
||||
properties[PROP_FONT_MAP] =
|
||||
g_param_spec_object ("font-map", "", "",
|
||||
PANGO2_TYPE_FONT_MAP,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FONT_DESC] =
|
||||
g_param_spec_boxed ("font-desc", "", "",
|
||||
PANGO2_TYPE_FONT_DESCRIPTION,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_SIZE] =
|
||||
g_param_spec_float ("size", "", "",
|
||||
0., 100., 12.,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_LETTERSPACING] =
|
||||
g_param_spec_int ("letterspacing", "", "",
|
||||
-G_MAXINT, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_LINE_HEIGHT] =
|
||||
g_param_spec_float ("line-height", "", "",
|
||||
0., 100., 1.,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FOREGROUND] =
|
||||
g_param_spec_boxed ("foreground", "", "",
|
||||
GDK_TYPE_RGBA,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_BACKGROUND] =
|
||||
g_param_spec_boxed ("background", "", "",
|
||||
GDK_TYPE_RGBA,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_VARIATIONS] =
|
||||
g_param_spec_string ("variations", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_FEATURES] =
|
||||
g_param_spec_string ("features", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_PALETTE] =
|
||||
g_param_spec_string ("palette", "", "",
|
||||
PANGO2_COLOR_PALETTE_DEFAULT,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
properties[PROP_SAMPLE_TEXT] =
|
||||
g_param_spec_string ("sample-text", "", "",
|
||||
"",
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (G_OBJECT_CLASS (class), NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
|
||||
"/org/gtk/fontexplorer/waterfallview.ui");
|
||||
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), WaterfallView, swin);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), WaterfallView, content);
|
||||
|
||||
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "waterfallview");
|
||||
}
|
14
demos/font-explorer/waterfallview.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
||||
#define WATERFALL_VIEW_TYPE (waterfall_view_get_type ())
|
||||
#define WATERFALL_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WATERFALL_VIEW_TYPE, WaterfallView))
|
||||
|
||||
|
||||
typedef struct _WaterfallView WaterfallView;
|
||||
typedef struct _WaterfallViewClass WaterfallViewClass;
|
||||
|
||||
|
||||
GType waterfall_view_get_type (void);
|
31
demos/font-explorer/waterfallview.ui
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="WaterfallView" parent="GtkWidget">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<style>
|
||||
<class name="view"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="swin">
|
||||
<property name="hscrollbar-policy">automatic</property>
|
||||
<property name="vscrollbar-policy">automatic</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="content">
|
||||
<property name="label">Content</property>
|
||||
<property name="wrap">0</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0</property>
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<property name="halign">fill</property>
|
||||
<property name="valign">fill</property>
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -33,12 +33,22 @@ static void create_window (GApplication *app, const char *contents);
|
||||
static void
|
||||
show_action_dialog (GSimpleAction *action)
|
||||
{
|
||||
GtkAlertDialog *dialog;
|
||||
const char *name;
|
||||
GtkWidget *dialog;
|
||||
|
||||
dialog = gtk_alert_dialog_new ("You activated action: \"%s\"",
|
||||
g_action_get_name (G_ACTION (action)));
|
||||
gtk_alert_dialog_show (dialog, NULL);
|
||||
g_object_unref (dialog);
|
||||
name = g_action_get_name (G_ACTION (action));
|
||||
|
||||
dialog = gtk_message_dialog_new (NULL,
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_INFO,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"You activated action: \"%s\"",
|
||||
name);
|
||||
|
||||
g_signal_connect (dialog, "response",
|
||||
G_CALLBACK (gtk_window_destroy), NULL);
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -57,7 +67,7 @@ show_action_infobar (GSimpleAction *action,
|
||||
text = g_strdup_printf ("You activated radio action: \"%s\".\n"
|
||||
"Current value: %s", name, value);
|
||||
gtk_label_set_text (GTK_LABEL (window->message), text);
|
||||
gtk_widget_set_visible (window->infobar, TRUE);
|
||||
gtk_widget_show (window->infobar);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
@@ -80,38 +90,43 @@ activate_new (GSimpleAction *action,
|
||||
}
|
||||
|
||||
static void
|
||||
open_response_cb (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
open_response_cb (GtkNativeDialog *dialog,
|
||||
int response_id,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
|
||||
GApplication *app = G_APPLICATION (user_data);
|
||||
GtkFileChooserNative *native = user_data;
|
||||
GApplication *app = g_object_get_data (G_OBJECT (native), "app");
|
||||
GtkWidget *message_dialog;
|
||||
GFile *file;
|
||||
char *contents;
|
||||
GError *error = NULL;
|
||||
|
||||
file = gtk_file_dialog_open_finish (dialog, result, &error);
|
||||
if (file)
|
||||
if (response_id == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
char *contents;
|
||||
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native));
|
||||
|
||||
if (g_file_load_contents (file, NULL, &contents, NULL, NULL, &error))
|
||||
{
|
||||
create_window (app, contents);
|
||||
g_free (contents);
|
||||
}
|
||||
else
|
||||
{
|
||||
message_dialog = gtk_message_dialog_new (NULL,
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"Error loading file: \"%s\"",
|
||||
error->message);
|
||||
g_signal_connect (message_dialog, "response",
|
||||
G_CALLBACK (gtk_window_destroy), NULL);
|
||||
gtk_widget_show (message_dialog);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
GtkAlertDialog *alert;
|
||||
|
||||
alert = gtk_alert_dialog_new ("Error loading file: \"%s\"", error->message);
|
||||
gtk_alert_dialog_show (alert, NULL);
|
||||
g_object_unref (alert);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_object_unref (app);
|
||||
gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (native));
|
||||
g_object_unref (native);
|
||||
}
|
||||
|
||||
|
||||
@@ -121,11 +136,21 @@ activate_open (GSimpleAction *action,
|
||||
gpointer user_data)
|
||||
{
|
||||
GApplication *app = user_data;
|
||||
GtkFileDialog *dialog;
|
||||
GtkFileChooserNative *native;
|
||||
|
||||
dialog = gtk_file_dialog_new ();
|
||||
gtk_file_dialog_open (dialog, NULL, NULL, open_response_cb, g_object_ref (app));
|
||||
g_object_unref (dialog);
|
||||
native = gtk_file_chooser_native_new ("Open File",
|
||||
NULL,
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
"_Open",
|
||||
"_Cancel");
|
||||
|
||||
g_object_set_data_full (G_OBJECT (native), "app", g_object_ref (app), g_object_unref);
|
||||
g_signal_connect (native,
|
||||
"response",
|
||||
G_CALLBACK (open_response_cb),
|
||||
native);
|
||||
|
||||
gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -214,41 +239,6 @@ activate_quit (GSimpleAction *action,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
delete_messages (gpointer data)
|
||||
{
|
||||
g_list_free_full ((GList *)data, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
pop_message (GtkWidget *status)
|
||||
{
|
||||
GList *messages = (GList *) g_object_steal_data (G_OBJECT (status), "messages");
|
||||
|
||||
if (messages)
|
||||
{
|
||||
char *message = messages->data;
|
||||
messages = g_list_remove (messages, message);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (status), "messages",
|
||||
messages, delete_messages);
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (status), message);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
push_message (GtkWidget *status,
|
||||
const char *message)
|
||||
{
|
||||
GList *messages = (GList *) g_object_steal_data (G_OBJECT (status), "messages");
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (status), message);
|
||||
messages = g_list_prepend (messages, g_strdup (message));
|
||||
g_object_set_data_full (G_OBJECT (status), "messages",
|
||||
messages, delete_messages);
|
||||
}
|
||||
|
||||
static void
|
||||
update_statusbar (GtkTextBuffer *buffer,
|
||||
DemoApplicationWindow *window)
|
||||
@@ -259,7 +249,7 @@ update_statusbar (GtkTextBuffer *buffer,
|
||||
GtkTextIter iter;
|
||||
|
||||
/* clear any previous message, underflow is allowed */
|
||||
pop_message (window->status);
|
||||
gtk_statusbar_pop (GTK_STATUSBAR (window->status), 0);
|
||||
|
||||
count = gtk_text_buffer_get_char_count (buffer);
|
||||
|
||||
@@ -273,7 +263,7 @@ update_statusbar (GtkTextBuffer *buffer,
|
||||
msg = g_strdup_printf ("Cursor at row %d column %d - %d chars in document",
|
||||
row, col, count);
|
||||
|
||||
push_message (window->status, msg);
|
||||
gtk_statusbar_push (GTK_STATUSBAR (window->status), 0, msg);
|
||||
|
||||
g_free (msg);
|
||||
}
|
||||
@@ -330,7 +320,7 @@ static GActionEntry win_entries[] = {
|
||||
static void
|
||||
clicked_cb (GtkWidget *widget, DemoApplicationWindow *window)
|
||||
{
|
||||
gtk_widget_set_visible (window->infobar, FALSE);
|
||||
gtk_widget_hide (window->infobar);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -514,8 +504,6 @@ demo_application_window_dispose (GObject *object)
|
||||
|
||||
demo_application_window_store_state (window);
|
||||
|
||||
gtk_widget_dispose_template (GTK_WIDGET (window), demo_application_window_get_type ());
|
||||
|
||||
G_OBJECT_CLASS (demo_application_window_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
@@ -76,13 +76,8 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="status">
|
||||
<object class="GtkStatusbar" id="status">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="margin-start">2</property>
|
||||
<property name="margin-end">2</property>
|
||||
<property name="margin-top">2</property>
|
||||
<property name="margin-bottom">2</property>
|
||||
<layout>
|
||||
<property name="column">0</property>
|
||||
<property name="row">3</property>
|
||||
|
@@ -7,8 +7,6 @@
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
|
||||
static GtkWidget *progress_bar = NULL;
|
||||
|
||||
static gboolean
|
||||
@@ -142,6 +140,7 @@ create_page3 (GtkWidget *assistant)
|
||||
|
||||
label = gtk_label_new ("This is a confirmation page, press 'Apply' to apply changes");
|
||||
|
||||
gtk_widget_show (label);
|
||||
gtk_assistant_append_page (GTK_ASSISTANT (assistant), label);
|
||||
gtk_assistant_set_page_type (GTK_ASSISTANT (assistant), label, GTK_ASSISTANT_PAGE_CONFIRM);
|
||||
gtk_assistant_set_page_complete (GTK_ASSISTANT (assistant), label, TRUE);
|
||||
@@ -158,14 +157,11 @@ create_page4 (GtkWidget *assistant)
|
||||
gtk_widget_set_margin_start (progress_bar, 40);
|
||||
gtk_widget_set_margin_end (progress_bar, 40);
|
||||
|
||||
gtk_widget_show (progress_bar);
|
||||
gtk_assistant_append_page (GTK_ASSISTANT (assistant), progress_bar);
|
||||
gtk_assistant_set_page_type (GTK_ASSISTANT (assistant), progress_bar, GTK_ASSISTANT_PAGE_PROGRESS);
|
||||
gtk_assistant_set_page_title (GTK_ASSISTANT (assistant), progress_bar, "Applying changes");
|
||||
|
||||
gtk_accessible_update_property (GTK_ACCESSIBLE (progress_bar),
|
||||
GTK_ACCESSIBLE_PROPERTY_LABEL, "Applying changes",
|
||||
-1);
|
||||
|
||||
/* This prevents the assistant window from being
|
||||
* closed while we're "busy" applying changes.
|
||||
*/
|
||||
@@ -203,7 +199,7 @@ do_assistant (GtkWidget *do_widget)
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (assistant))
|
||||
gtk_widget_set_visible (assistant, TRUE);
|
||||
gtk_widget_show (assistant);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (assistant));
|
||||
|
||||
|
@@ -116,8 +116,7 @@ effective_align (GtkAlign align,
|
||||
return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
|
||||
case GTK_ALIGN_FILL:
|
||||
case GTK_ALIGN_CENTER:
|
||||
case GTK_ALIGN_BASELINE_FILL:
|
||||
case GTK_ALIGN_BASELINE_CENTER:
|
||||
case GTK_ALIGN_BASELINE:
|
||||
default:
|
||||
return align;
|
||||
}
|
||||
@@ -259,8 +258,7 @@ blur_overlay_get_child_position (BlurOverlay *overlay,
|
||||
case GTK_ALIGN_END:
|
||||
alloc->x += width - alloc->width;
|
||||
break;
|
||||
case GTK_ALIGN_BASELINE_FILL:
|
||||
case GTK_ALIGN_BASELINE_CENTER:
|
||||
case GTK_ALIGN_BASELINE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
@@ -283,8 +281,7 @@ blur_overlay_get_child_position (BlurOverlay *overlay,
|
||||
case GTK_ALIGN_END:
|
||||
alloc->y += height - alloc->height;
|
||||
break;
|
||||
case GTK_ALIGN_BASELINE_FILL:
|
||||
case GTK_ALIGN_BASELINE_CENTER:
|
||||
case GTK_ALIGN_BASELINE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
@@ -300,13 +297,12 @@ blur_overlay_snapshot (GtkWidget *widget,
|
||||
GtkWidget *main_widget;
|
||||
GskRenderNode *main_widget_node = NULL;
|
||||
GtkWidget *child;
|
||||
int width, height;
|
||||
GtkAllocation main_alloc;
|
||||
cairo_region_t *clip = NULL;
|
||||
int i;
|
||||
|
||||
main_widget = BLUR_OVERLAY (widget)->main_widget;
|
||||
width = gtk_widget_get_width (widget);
|
||||
height = gtk_widget_get_height (widget);
|
||||
gtk_widget_get_allocation (widget, &main_alloc);
|
||||
|
||||
for (child = gtk_widget_get_first_child (widget);
|
||||
child != NULL;
|
||||
@@ -319,7 +315,7 @@ blur_overlay_snapshot (GtkWidget *widget,
|
||||
|
||||
if (blur > 0)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
GtkAllocation alloc;
|
||||
graphene_rect_t bounds;
|
||||
|
||||
if (main_widget_node == NULL)
|
||||
@@ -331,8 +327,8 @@ blur_overlay_snapshot (GtkWidget *widget,
|
||||
main_widget_node = gtk_snapshot_free_to_node (child_snapshot);
|
||||
}
|
||||
|
||||
if (!gtk_widget_compute_bounds (child, gtk_widget_get_parent (child), &bounds))
|
||||
graphene_rect_init (&bounds, 0, 0, 0, 0);
|
||||
gtk_widget_get_allocation (child, &alloc);
|
||||
graphene_rect_init (&bounds, alloc.x, alloc.y, alloc.width, alloc.height);
|
||||
gtk_snapshot_push_blur (snapshot, blur);
|
||||
gtk_snapshot_push_clip (snapshot, &bounds);
|
||||
gtk_snapshot_append_node (snapshot, main_widget_node);
|
||||
@@ -341,17 +337,13 @@ blur_overlay_snapshot (GtkWidget *widget,
|
||||
|
||||
if (clip == NULL)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
rect.x = rect.y = 0;
|
||||
rect.width = width;
|
||||
rect.height = height;
|
||||
rect.width = main_alloc.width;
|
||||
rect.height = main_alloc.height;
|
||||
clip = cairo_region_create_rectangle (&rect);
|
||||
}
|
||||
|
||||
rect.x = floor (bounds.origin.x);
|
||||
rect.y = floor (bounds.origin.y);
|
||||
rect.width = ceil (bounds.origin.x + bounds.size.width - rect.x);
|
||||
rect.height = ceil (bounds.origin.y + bounds.size.height - rect.y);
|
||||
cairo_region_subtract_rectangle (clip, &rect);
|
||||
cairo_region_subtract_rectangle (clip, (cairo_rectangle_int_t *)&alloc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -18,7 +18,8 @@
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef __BLUR_OVERLAY_H__
|
||||
#define __BLUR_OVERLAY_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
@@ -50,12 +51,18 @@ struct _BlurOverlayClass
|
||||
GtkAllocation *allocation);
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType blur_overlay_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget *blur_overlay_new (void);
|
||||
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
|
||||
|
||||
#endif /* __BLUR_OVERLAY_H__ */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/* Builder
|
||||
* #Keywords: GMenu, GtkPopoverMenuBar, GtkBuilder, GtkShortcutController, toolbar
|
||||
* #Keywords: GMenu, GtkPopoverMenuBar, GtkBuilder, GtkStatusBar, GtkShortcutController, toolbar
|
||||
*
|
||||
* Demonstrates a traditional interface, loaded from a XML description,
|
||||
* and shows how to connect actions to the menu items and toolbar buttons.
|
||||
@@ -37,30 +37,22 @@ remove_timeout (gpointer data)
|
||||
g_source_remove (id);
|
||||
}
|
||||
|
||||
static int
|
||||
pop_message (gpointer data)
|
||||
static gboolean
|
||||
pop_status (gpointer data)
|
||||
{
|
||||
GtkWidget *status = data;
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (status), "");
|
||||
g_object_set_data (G_OBJECT (status), "timeout", GUINT_TO_POINTER (0));
|
||||
|
||||
gtk_statusbar_pop (GTK_STATUSBAR (data), 0);
|
||||
g_object_set_data (G_OBJECT (data), "timeout", NULL);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
status_message (GtkWidget *status,
|
||||
const char *text)
|
||||
status_message (GtkStatusbar *status,
|
||||
const char *text)
|
||||
{
|
||||
guint id;
|
||||
|
||||
id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (status), "timeout"));
|
||||
if (id)
|
||||
g_source_remove (id);
|
||||
|
||||
gtk_label_set_text (GTK_LABEL (status), text);
|
||||
|
||||
id = g_timeout_add (5000, pop_message, status);
|
||||
gtk_statusbar_push (GTK_STATUSBAR (status), 0, text);
|
||||
id = g_timeout_add (5000, pop_status, status);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (status), "timeout", GUINT_TO_POINTER (id), remove_timeout);
|
||||
}
|
||||
@@ -73,7 +65,7 @@ help_activate (GSimpleAction *action,
|
||||
GtkWidget *status;
|
||||
|
||||
status = GTK_WIDGET (g_object_get_data (G_OBJECT (user_data), "status"));
|
||||
status_message (status, "Help not available");
|
||||
status_message (GTK_STATUSBAR (status), "Help not available");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -86,7 +78,7 @@ not_implemented (GSimpleAction *action,
|
||||
|
||||
text = g_strdup_printf ("Action “%s” not implemented", g_action_get_name (G_ACTION (action)));
|
||||
status = GTK_WIDGET (g_object_get_data (G_OBJECT (user_data), "status"));
|
||||
status_message (status, text);
|
||||
status_message (GTK_STATUSBAR (status), text);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
@@ -176,7 +168,7 @@ do_builder (GtkWidget *do_widget)
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_set_visible (window, TRUE);
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -1,5 +1,4 @@
|
||||
/* Clipboard
|
||||
* #Keywords: drag-and-drop, dnd
|
||||
*
|
||||
* GdkClipboard is used for clipboard handling. This demo shows how to
|
||||
* copy and paste text, images, colors or files to and from the clipboard.
|
||||
@@ -51,10 +50,10 @@ copy_button_clicked (GtkStack *source_stack,
|
||||
}
|
||||
else if (strcmp (visible_child_name, "Color") == 0)
|
||||
{
|
||||
const GdkRGBA *color;
|
||||
GdkRGBA color;
|
||||
|
||||
color = gtk_color_dialog_button_get_rgba (GTK_COLOR_DIALOG_BUTTON (visible_child));
|
||||
gdk_clipboard_set (clipboard, GDK_TYPE_RGBA, color);
|
||||
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (visible_child), &color);
|
||||
gdk_clipboard_set (clipboard, GDK_TYPE_RGBA, &color);
|
||||
}
|
||||
else if (strcmp (visible_child_name, "File") == 0)
|
||||
{
|
||||
@@ -216,71 +215,37 @@ file_button_set_file (GtkButton *button,
|
||||
}
|
||||
|
||||
static void
|
||||
file_chooser_response (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
file_chooser_response (GtkNativeDialog *dialog,
|
||||
int response,
|
||||
GtkButton *button)
|
||||
{
|
||||
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
|
||||
GtkButton *button = GTK_BUTTON (user_data);
|
||||
GFile *file;
|
||||
gtk_native_dialog_hide (dialog);
|
||||
|
||||
file = gtk_file_dialog_open_finish (dialog, result, NULL);
|
||||
if (file)
|
||||
if (response == GTK_RESPONSE_ACCEPT)
|
||||
{
|
||||
GFile *file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
||||
file_button_set_file (button, file);
|
||||
g_object_unref (file);
|
||||
|
||||
update_copy_button_sensitivity (gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_STACK));
|
||||
}
|
||||
|
||||
gtk_native_dialog_destroy (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
open_file_cb (GtkWidget *button)
|
||||
{
|
||||
GtkFileDialog *dialog;
|
||||
GtkFileChooserNative *chooser;
|
||||
|
||||
dialog = gtk_file_dialog_new ();
|
||||
chooser = gtk_file_chooser_native_new ("Choose a file",
|
||||
GTK_WINDOW (gtk_widget_get_ancestor (button, GTK_TYPE_WINDOW)),
|
||||
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
"_Open",
|
||||
"_Cancel");
|
||||
|
||||
gtk_file_dialog_open (dialog,
|
||||
GTK_WINDOW (gtk_widget_get_ancestor (button, GTK_TYPE_WINDOW)),
|
||||
NULL,
|
||||
file_chooser_response, button);
|
||||
|
||||
g_object_unref (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
folder_chooser_response (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
|
||||
GtkButton *button = GTK_BUTTON (user_data);
|
||||
GFile *file;
|
||||
|
||||
file = gtk_file_dialog_select_folder_finish (dialog, result, NULL);
|
||||
if (file)
|
||||
{
|
||||
file_button_set_file (button, file);
|
||||
g_object_unref (file);
|
||||
|
||||
update_copy_button_sensitivity (gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_STACK));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
open_folder_cb (GtkWidget *button)
|
||||
{
|
||||
GtkFileDialog *dialog;
|
||||
|
||||
dialog = gtk_file_dialog_new ();
|
||||
|
||||
gtk_file_dialog_select_folder (dialog,
|
||||
GTK_WINDOW (gtk_widget_get_ancestor (button, GTK_TYPE_WINDOW)),
|
||||
NULL,
|
||||
folder_chooser_response, button);
|
||||
|
||||
g_object_unref (dialog);
|
||||
g_signal_connect (chooser, "response", G_CALLBACK (file_chooser_response), button);
|
||||
gtk_native_dialog_show (GTK_NATIVE_DIALOG (chooser));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -381,7 +346,6 @@ do_clipboard (GtkWidget *do_widget)
|
||||
gtk_builder_cscope_add_callback (scope, source_changed_cb);
|
||||
gtk_builder_cscope_add_callback (scope, text_changed_cb);
|
||||
gtk_builder_cscope_add_callback (scope, open_file_cb);
|
||||
gtk_builder_cscope_add_callback (scope, open_folder_cb);
|
||||
gtk_builder_cscope_add_callback (scope, on_drop);
|
||||
gtk_builder_cscope_add_callback (scope, drag_prepare);
|
||||
builder = gtk_builder_new ();
|
||||
@@ -405,7 +369,7 @@ do_clipboard (GtkWidget *do_widget)
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_set_visible (window, TRUE);
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
|
@@ -4,9 +4,6 @@
|
||||
<object class="GtkWindow" id="window">
|
||||
<property name="resizable">1</property>
|
||||
<property name="title">Clipboard</property>
|
||||
<accessibility>
|
||||
<relation name="described-by">label</relation>
|
||||
</accessibility>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
@@ -16,7 +13,7 @@
|
||||
<property name="margin-bottom">12</property>
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">“Copy” will copy the selected data the clipboard, “Paste” will show the current clipboard contents. You can also drag the data to the bottom.</property>
|
||||
<property name="wrap">1</property>
|
||||
<property name="max-width-chars">40</property>
|
||||
@@ -27,9 +24,6 @@
|
||||
<property name="spacing">12</property>
|
||||
<child>
|
||||
<object class="GtkDropDown" id="source_chooser">
|
||||
<accessibility>
|
||||
<property name="label">Source Type</property>
|
||||
</accessibility>
|
||||
<property name="valign">center</property>
|
||||
<property name="model">
|
||||
<object class="GtkStringList">
|
||||
@@ -38,7 +32,6 @@
|
||||
<item>Color</item>
|
||||
<item>Image</item>
|
||||
<item>File</item>
|
||||
<item>Folder</item>
|
||||
</items>
|
||||
</object>
|
||||
</property>
|
||||
@@ -60,9 +53,6 @@
|
||||
<property name="name">Text</property>
|
||||
<property name="child">
|
||||
<object class="GtkEntry" id="source_text">
|
||||
<accessibility>
|
||||
<property name="label">Text Drag Source</property>
|
||||
</accessibility>
|
||||
<property name="valign">center</property>
|
||||
<signal name="notify::text" handler="text_changed_cb" object="copy_button"/>
|
||||
<property name="text">Copy this!</property>
|
||||
@@ -74,14 +64,7 @@
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">Color</property>
|
||||
<property name="child">
|
||||
<object class="GtkColorDialogButton" id="source_color">
|
||||
<accessibility>
|
||||
<property name="label">Color Drag Source</property>
|
||||
</accessibility>
|
||||
<property name="dialog">
|
||||
<object class="GtkColorDialog">
|
||||
</object>
|
||||
</property>
|
||||
<object class="GtkColorButton" id="source_color">
|
||||
<property name="valign">center</property>
|
||||
<property name="rgba">purple</property>
|
||||
</object>
|
||||
@@ -99,17 +82,14 @@
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="image_rose">
|
||||
<accessibility>
|
||||
<property name="label">Photo Drag Source</property>
|
||||
</accessibility>
|
||||
<property name="active">1</property>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
<signal name="prepare" handler="drag_prepare"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<accessibility>
|
||||
<property name="label">Portland Rose Photo</property>
|
||||
</accessibility>
|
||||
<style>
|
||||
<class name="large-icons"/>
|
||||
</style>
|
||||
@@ -120,9 +100,6 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="image_floppy">
|
||||
<accessibility>
|
||||
<property name="label">Icon Drag Source</property>
|
||||
</accessibility>
|
||||
<property name="group">image_rose</property>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
@@ -131,9 +108,6 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<accessibility>
|
||||
<property name="label">Floppy Buddy Icon</property>
|
||||
</accessibility>
|
||||
<style>
|
||||
<class name="large-icons"/>
|
||||
</style>
|
||||
@@ -144,9 +118,6 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="image_logo">
|
||||
<accessibility>
|
||||
<property name="label">SVG Drag Source</property>
|
||||
</accessibility>
|
||||
<property name="group">image_floppy</property>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
@@ -155,9 +126,6 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<accessibility>
|
||||
<property name="label">gtk-demo logo</property>
|
||||
</accessibility>
|
||||
<style>
|
||||
<class name="large-icons"/>
|
||||
</style>
|
||||
@@ -175,9 +143,6 @@
|
||||
<property name="name">File</property>
|
||||
<property name="child">
|
||||
<object class="GtkButton" id="source_file">
|
||||
<accessibility>
|
||||
<property name="label">File Drag Source</property>
|
||||
</accessibility>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
<property name="propagation-phase">capture</property>
|
||||
@@ -197,33 +162,6 @@
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">Folder</property>
|
||||
<property name="child">
|
||||
<object class="GtkButton" id="source_folder">
|
||||
<accessibility>
|
||||
<property name="label">Folder Drag Source</property>
|
||||
</accessibility>
|
||||
<child>
|
||||
<object class="GtkDragSource">
|
||||
<property name="propagation-phase">capture</property>
|
||||
<signal name="prepare" handler="drag_prepare"/>
|
||||
</object>
|
||||
</child>
|
||||
<property name="valign">center</property>
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="label">—</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="ellipsize">start</property>
|
||||
</object>
|
||||
</property>
|
||||
<signal name="clicked" handler="open_folder_cb"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
@@ -258,7 +196,7 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="paste_label">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<lookup name="visible-child-name" type="GtkStack">
|
||||
@@ -285,9 +223,6 @@
|
||||
<property name="name">Text</property>
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<accessibility>
|
||||
<relation name="labelled-by">paste_label</relation>
|
||||
</accessibility>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="xalign">0</property>
|
||||
@@ -301,9 +236,6 @@
|
||||
<property name="name">Image</property>
|
||||
<property name="child">
|
||||
<object class="GtkImage">
|
||||
<accessibility>
|
||||
<relation name="labelled-by">paste_label</relation>
|
||||
</accessibility>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
@@ -322,9 +254,6 @@
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkColorSwatch">
|
||||
<accessibility>
|
||||
<relation name="labelled-by">paste_label</relation>
|
||||
</accessibility>
|
||||
<property name="accessible-role">img</property>
|
||||
<property name="can-focus">0</property>
|
||||
<property name="selectable">0</property>
|
||||
@@ -340,9 +269,6 @@
|
||||
<property name="name">File</property>
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<accessibility>
|
||||
<relation name="labelled-by">paste_label</relation>
|
||||
</accessibility>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="xalign">0</property>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -11,8 +11,6 @@
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
|
||||
enum
|
||||
{
|
||||
ICON_NAME_COL,
|
||||
@@ -262,12 +260,13 @@ mask_entry_set_background (MaskEntry *entry)
|
||||
{
|
||||
if (!g_regex_match_simple (entry->mask, gtk_editable_get_text (GTK_EDITABLE (entry)), 0, 0))
|
||||
{
|
||||
PangoAttrList *attrs;
|
||||
Pango2AttrList *attrs;
|
||||
Pango2Color color = { 65535, 32767, 32767, 65535 };
|
||||
|
||||
attrs = pango_attr_list_new ();
|
||||
pango_attr_list_insert (attrs, pango_attr_foreground_new (65535, 32767, 32767));
|
||||
attrs = pango2_attr_list_new ();
|
||||
pango2_attr_list_insert (attrs, pango2_attr_foreground_new (&color));
|
||||
gtk_entry_set_attributes (GTK_ENTRY (entry), attrs);
|
||||
pango_attr_list_unref (attrs);
|
||||
pango2_attr_list_unref (attrs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -449,7 +448,7 @@ do_combobox (GtkWidget *do_widget)
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_set_visible (window, TRUE);
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
|
@@ -277,7 +277,7 @@ do_constraints (GtkWidget *do_widget)
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_set_visible (window, TRUE);
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
|