GTK+ 检查器

许多 GTK+ 用户和开发者都听说过 GTK+ 检查器,它是一款用于检查、修改和理解 GTK+ 应用程序的工具。检查器功能非常强大,它允许主题设计者实时测试 CSS 更改,并放大控件以查看最微小的细节,让开发者检查应用程序控件及其属性,并让用户玩耍(并最终破坏)应用程序。

在本文中,我们将探索 GTK+ 检查器,并展示您可以用它做什么。

序言

由于检查器是一个调试工具,因此默认情况下它是禁用的。要开始使用检查器,您首先必须启用它。您可以使用 DConf 编辑器轻松完成此操作

Enabling the Gtk+ Inspector with DConf Editor
使用 DConf 编辑器启用 GTK+ 检查器

或者,您可以使用终端启用它。为此,请运行以下命令

$ gsettings set org.gtk.Settings.Debug enable-inspector-keybinding true

完成!检查器现已启用!

打开检查器

现在检查器已启用,您需要运行它。检查器始终与应用程序相关联。让我们以 GNOME 日历为例

GNOME Calendar
GNOME 日历应用程序

有多种方法可以启动检查器。您可以在使用应用程序时,通过键入 <Ctrl> + <Shift> + D(或<Ctrl> + <Shift> + I 自动选择鼠标指针下的控件)来打开它。或者,您可以使用环境变量GTK_DEBUG=interactive从终端启动应用程序。

检查器将打开,您将看到以下窗口

Inspector on Calendar
GNOME 日历上的检查器窗口

这就是您需要做的全部。现在让我们探索检查器提供的各种功能。

探索检查器

起初,大量的按钮和选项卡可能会让那些不精通应用程序检查艺术的人感到困惑。以下是按顺序对选项卡的快速说明

  • 对象:公开应用程序的控件,并允许编辑属性和查看每个控件的详细信息。如下所述。
  • 统计信息:显示应用程序的杂项统计信息。您需要使用 GOBJECT_DEBUG=instance-count 运行应用程序。
  • 资源:显示嵌入在应用程序二进制文件中的各种资源,例如自定义图标或 GtkBuilder 文件等。
  • CSS:允许实时测试 CSS。如下所述。
  • 视觉:控制应用程序的一些视觉方面,例如文本方向、深色/浅色变体、主题、缩放比例等。
  • 常规:显示有关 GTK+ 应用程序(及其运行会话)的杂项信息。

让我们剖析 GTK+ 检查器的主窗口

Inspector window
主检查器窗口

检查器的这 4 个带注释的部分是最常用的部分。主题设计人员会想要检查 (3) 和 (4),而开发人员通常使用 (1) 和 (2)。

检查控件

对于开发人员,检查器通过让您更改屏幕上任何控件的属性来显示其用处。让我们从单击第一个按钮并使用鼠标光标选择一个控件开始

Selecting widgets
使用检查器选择控件

现在,您可以通过浏览对象 > 属性选项卡轻松更改该控件的属性。例如,您可以更改控件的可见性、标签的文本等等!

Editing a widget property
编辑控件属性

现在您已经了解如何检查 GTK+ 应用程序,请尝试并探索有多少应用程序被组织起来。更改控件的属性,看看会发生什么。大多数情况下,这是安全的,不会破坏您的 GNOME 会话或冻结您的计算机!

编辑 CSS

检查器也是设计师的强大工具。它最强大的功能之一是实时 CSS 编辑器。让我们从转到 CSS 选项卡开始

CSS Editor
检查器 CSS 编辑器视图

让我们来玩玩 CSS!粘贴以下 CSS 代码,看看会发生什么

window stack {
    background-color: orange;
}

哇!窗口变得像外星人一样!该 CSS 代码更改了 GtkWindow 内任何 GtkStack 控件的背景颜色。如果您想了解有关 CSS 选择器以及 GTK+ 如何使用 CSS 进行主题化的更多信息,本文末尾提供了一些有用的链接。

谨慎的读者可能会问:CSS 元素的层次结构是什么?如何查看哪些 CSS 元素可用?

别担心!GTK+ 检查器允许您在对象 > CSS 节点选项卡中轻松检查 CSS 层次结构。

CSS Nodes
CSS 节点选项卡

GTK+ 控件具有文档化的 CSS 名称。您可以浏览 GTK+ 文档,了解控件是如何组织的,以及如何使用 CSS 来控制控件的各个方面。

不确定您的 CSS 更改是否完美?让我们放大控件以确保我们不会错过任何细节

Zooming widget using Magnifier
使用放大镜选项卡缩放控件

看起来不错?加入 -design 并与社区分享您出色的 CSS 片段!

总结

虽然本文探讨了 GTK+ 检查器的一些最大方面,但这绝不是检查器所有功能的详尽列表。但是,在阅读本文后,您应该能够打开检查器并自行探索其更多强大的功能。

有疑问?评论?建议?请过来发表评论,加入 GNOME IRC 网络上的 #gtk+ 频道,让我们知道您的想法!

有用的链接

Adwaita

今天,来自 GNOME 设计团队的 Jakub Steiner 将谈论 Adwaita,它是 GTK+ 的默认主题;设计师可用于设置 GTK+ 样式的工具;以及工具包如何更改以允许更好的设计工作流程。

Adwaita 是 GTK+ 面向用户的外观。过去,GTK+ 没有外观;工具包没有明确定义的外观。就像 FOSS 世界中的许多事情一样,它是自带的。有一个Raleigh,这是一个后备皮肤,只有在主题或系统设置出现问题时才会显示。而且您真的不想看到它。

Adwaita

CSS

随着 GTK+ 3.0 的发布,一项大胆的新努力开始了。这项努力旨在让视觉设计师使用他们理解的工具来负责视觉设计。与其使用主题引擎来绘制独特的控件,不如选择在 Web 上使用的样式引擎。“一切都是盒子”的 CSS 模型非常适合 GTK+。这需要付出很多努力,主要由 Benjamin Otte 承担,他多年来设法为我们提供了我们梦想的东西:一个类似 CSS 的盒子模型,允许我们使用填充、边距、边框和巧妙的功能(如最小宽度)来间隔元素/控件。在选择器方面,我们处理的不是随版本而变化的直接嵌套控件结构,而是我们被赋予了一个抽象的、类似 HTML 的DOM结构,带有节点和类。节点也始终如一地携带状态,并且更容易进行动画处理。

SCSS

在 GTK+ 中,有很多看起来像按钮但不是按钮的控件。每个程序员都很懒,这是一件好事。设计师也不例外。有一个缩写来表示它,DRY — 不要重复自己。因此,在旧的 Adwaita 中,当我们设计一些看起来相同的东西的外观时,我们只有一个属性块和大量的选择器 — 该外观的目标。按钮、下拉列表,等等。没有太多键入,但要更改却很疯狂。

SASS 通过提供定义一次公共绘制过程的方法来拯救了我们,但在结构良好的样式表中重用了它。您可以绘制“像按钮一样”的东西,但不要将其定义为按钮。您仍然会在下拉部分中找到语义组织良好的下拉列表。SASS 将这些宏称为混入,您将在 src/gtk/theme/Adwaita/_drawing.scss 中找到我们的绘图宏。

/* Switch Slider being a button */
slider {
/* ... */
@include button(normal, $edge: $shadow_color);
}
检查器

设计师工作流程的巨大改进是引入了 检查器。检查器是一个非常有价值的工具,可以交互式地测试新样式,或找出为什么特定选择器不起作用。它提供了几个强大的工具

  • 控件选择器。您可以交互式地指向一个控件,以了解其属性或它在控件树堆栈中的位置。从 3.20 开始,您还可以了解其 CSS 节点、了解它可以进入哪种状态、了解已分配给它的所有类。它还可以告诉您在样式表中定义设置属性的位置。这可以帮助您找出为什么您的选择器不起作用。有点。如果能看到所有匹配的选择器,甚至是那些被优先选择器覆盖的选择器,那就太好了。
  • 交互式 CSS 样式表。您可以编写一个 CSS 规则,并使其实时应用。这不仅有助于找出正确的选择器,还可以直接使用 GTK+ 进行绘制实验,而不是使用像 Inkscape 这样的工具。能够快速迭代和尝试事情会导致更好的设计。

如果这一切听起来与现代浏览器提供的非常相似,那就不是什么巧合。

CSS Nodes in the Inspector
检查器中的 CSS 节点
未来的改进

在更改 Adwaita 方面使我们不太灵活的一个主要因素是图形资源。我们仍然有一些事情必须求助于使用图像资源。这些实际上在一个大型资源表 SVG 中,我们有一些脚本可以分解多个尺寸的图像(用于 HiDPI)。添加或更改特定位仍然很麻烦。

为了让它不那么无聊,这里有一个小型的 Web 演示,演示了我们如何可能避免使用图像资源来绘制 GtkScale 滑块,以及 使用简单的 CSS 框

<div id="scale" class="scale">
  <div class="trough"></div>
  <div id="slider" class="slider run-animation"></div>
</div>

<style type="text/css">
.scale {
  position: relative;
  width: 100%;
  height: 64px;
}
.scale:hover { }
.trough {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  height: 8px;
  border-style: solid;
  border-width: 2px;
  border-radius: 4px;
  left: 0; right: 0;
  border-color: #a7a7a7;
  background-color: #b1b3b1;
  background-image: linear-gradient(to bottom, #a7a7a7, #bebebe);
  box-shadow: 0 1px 0 rgba(255,255,255,0.8);
}
.slider {
  position: absolute;
  width: 48px; height: 48px;
  top: 50%;
  left: 0%;
  transform: translateY(-50%) translateX(0%) rotate(0deg);
  border-style: solid;
  border-width: 2px;
  border-color: #a7a7a7;
  border-radius: 0;
  background-color: #e0e0e0;
  background-image: linear-gradient(135deg, #ededed, #d3d3d3);
  box-shadow: inset 0 0 0 2px rgba(255,255,255,0.2),
              2px 2px 2px rgba(0,0,0,0.1);
}
.slider.run-animation {
  animation-name: morph, progress;
  animation-delay: 6s,10s;
  animation-duration: 3s,3s;
  animation-iteration-count:1,infinite;
  animation-direction: normal, alternate;
  animation-timing-function: ease-in-out;
  animation-fill-mode: forwards;
}
.slider.run-animation:hover {
  /* the best way to reset CSS animations is switching between identical keyframes */
  animation-name: morphClone, progressClone;
}
@keyframes morph {
  0% {
    border-radius: 0;
    transform: translateY(-50%) translateX(0%) rotate(0deg);
  }
  90% {
    border-radius: 50% 50% 0 50%;
    transform: translateY(-50%) translateX(0%) rotate(0deg);
  }
  100% {
    border-radius: 50% 50% 0 50%;
    transform: translateY(-60%) translateX(0%) rotate(45deg);
  }
}
@keyframes morphClone {
  0% {
    border-radius: 0;
    transform: translateY(-50%) translateX(0%) rotate(0deg);
  }
  90% {
    border-radius: 50% 50% 0 50%;
    transform: translateY(-50%) translateX(0%) rotate(0deg);
  }
  100% {
    border-radius: 50% 50% 0 50%;
    transform: translateY(-60%) translateX(0%) rotate(45deg);
  }
}
@keyframes progress {
  0% {
    left: 0%;
    transform: translateY(-60%) translateX(0%) rotate(45deg);
  }
  100% {
    left: 100%;
    transform: translateY(-60%) translateX(-100%) rotate(45deg);
  }
}
@keyframes progressClone {
  0% {
    left: 0%;
    transform: translateY(-60%) translateX(0%) rotate(45deg);
  }
  100% {
    left: 100%;
    transform: translateY(-60%) translateX(-100%) rotate(45deg);
  }
}
</style>

本质上,滑块是一个有 3 个角圆角的盒子,并旋转了 45 度。我们只需要盒子。

    /* transforms-based scale slider on the web */
.slider {
  position: absolute;
  width: 48px; height: 48px;
  top: 50%;
  left: 0%;
  /* move up slightly after rotation, thus not 50% */
  transform: translateY(-60%) rotate(45deg);
  border-style: solid;
  border-width: 2px;
  border-color: #a7a7a7;
  border-radius: 50% 50% 0 50%;
  background-color: #e0e0e0;
  background-image: linear-gradient(135deg, #ededed, #d3d3d3);
  box-shadow: inset 0 0 0 2px rgba(255,255,255,0.2),
              2px 2px 2px rgba(0,0,0,0.1);
}