[libadwaita/wip/exalm/tab-style: 1/5] tab-box: Refresh design
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libadwaita/wip/exalm/tab-style: 1/5] tab-box: Refresh design
- Date: Wed, 6 Apr 2022 22:30:54 +0000 (UTC)
commit a26a878ed7a56aa79b989be56dd016f78bffdcc2
Author: Alexander Mikhaylenko <alexm gnome org>
Date: Wed Apr 6 15:18:27 2022 +0400
tab-box: Refresh design
Ensure it's visible in dark variant.
Replace borders with separators. Make sure separators never touch a tab
with background.
Replace the needs-attention gradient with a bar; animate it.
Replace the undershoot gradient with a fade.
Fixes https://gitlab.gnome.org/GNOME/libadwaita/-/issues/318
src/adw-tab-bar-private.h | 5 +
src/adw-tab-bar.c | 58 ++---
src/adw-tab-bar.ui | 4 -
src/adw-tab-box.c | 462 +++++++++++++++++++++++++---------
src/adw-tab.c | 72 +++++-
src/adw-tab.ui | 6 +
src/stylesheet/widgets/_tab-view.scss | 208 ++++-----------
7 files changed, 487 insertions(+), 328 deletions(-)
---
diff --git a/src/adw-tab-bar-private.h b/src/adw-tab-bar-private.h
index e191f092..f6670c63 100644
--- a/src/adw-tab-bar-private.h
+++ b/src/adw-tab-bar-private.h
@@ -14,8 +14,13 @@
#include "adw-tab-bar.h"
+#include "adw-tab-box-private.h"
+
G_BEGIN_DECLS
gboolean adw_tab_bar_tabs_have_visible_focus (AdwTabBar *self);
+AdwTabBox *adw_tab_bar_get_tab_box (AdwTabBar *self);
+AdwTabBox *adw_tab_bar_get_pinned_tab_box (AdwTabBar *self);
+
G_END_DECLS
diff --git a/src/adw-tab-bar.c b/src/adw-tab-bar.c
index 3c05f38d..b914a9f2 100644
--- a/src/adw-tab-bar.c
+++ b/src/adw-tab-bar.c
@@ -187,46 +187,6 @@ page_detached_cb (AdwTabBar *self,
g_signal_handlers_disconnect_by_func (page, notify_pinned_cb, self);
}
-static void
-update_needs_attention (AdwTabBar *self,
- gboolean pinned)
-{
- GtkStyleContext *context;
- gboolean left, right;
-
- g_object_get (pinned ? self->pinned_box : self->box,
- "needs-attention-left", &left,
- "needs-attention-right", &right,
- NULL);
-
- if (pinned)
- context = gtk_widget_get_style_context (GTK_WIDGET (self->pinned_scrolled_window));
- else
- context = gtk_widget_get_style_context (GTK_WIDGET (self->scrolled_window));
-
- if (left)
- gtk_style_context_add_class (context, "needs-attention-left");
- else
- gtk_style_context_remove_class (context, "needs-attention-left");
-
- if (right)
- gtk_style_context_add_class (context, "needs-attention-right");
- else
- gtk_style_context_remove_class (context, "needs-attention-right");
-}
-
-static void
-notify_needs_attention_cb (AdwTabBar *self)
-{
- update_needs_attention (self, FALSE);
-}
-
-static void
-notify_needs_attention_pinned_cb (AdwTabBar *self)
-{
- update_needs_attention (self, TRUE);
-}
-
static inline gboolean
is_overflowing (GtkAdjustment *adj)
{
@@ -609,8 +569,6 @@ adw_tab_bar_class_init (AdwTabBarClass *klass)
gtk_widget_class_bind_template_child (widget_class, AdwTabBar, pinned_scrolled_window);
gtk_widget_class_bind_template_child (widget_class, AdwTabBar, start_action_bin);
gtk_widget_class_bind_template_child (widget_class, AdwTabBar, end_action_bin);
- gtk_widget_class_bind_template_callback (widget_class, notify_needs_attention_cb);
- gtk_widget_class_bind_template_callback (widget_class, notify_needs_attention_pinned_cb);
gtk_widget_class_bind_template_callback (widget_class, notify_resize_frozen_cb);
gtk_widget_class_bind_template_callback (widget_class, stop_kinetic_scrolling_cb);
gtk_widget_class_bind_template_callback (widget_class, extra_drag_drop_cb);
@@ -1094,3 +1052,19 @@ adw_tab_bar_get_is_overflowing (AdwTabBar *self)
return self->is_overflowing;
}
+
+AdwTabBox *
+adw_tab_bar_get_tab_box (AdwTabBar *self)
+{
+ g_return_val_if_fail (ADW_IS_TAB_BAR (self), NULL);
+
+ return self->box;
+}
+
+AdwTabBox *
+adw_tab_bar_get_pinned_tab_box (AdwTabBar *self)
+{
+ g_return_val_if_fail (ADW_IS_TAB_BAR (self), NULL);
+
+ return self->pinned_box;
+}
diff --git a/src/adw-tab-bar.ui b/src/adw-tab-bar.ui
index c6f68e0c..81583d7c 100644
--- a/src/adw-tab-bar.ui
+++ b/src/adw-tab-bar.ui
@@ -33,8 +33,6 @@
<object class="AdwTabBox" id="pinned_box">
<property name="pinned">True</property>
<property name="tab-bar">AdwTabBar</property>
- <signal name="notify::needs-attention-left" handler="notify_needs_attention_pinned_cb"
swapped="true"/>
- <signal name="notify::needs-attention-right" handler="notify_needs_attention_pinned_cb"
swapped="true"/>
<signal name="notify::resize-frozen" handler="notify_resize_frozen_cb" swapped="true"/>
<signal name="stop-kinetic-scrolling" handler="stop_kinetic_scrolling_cb"
object="pinned_scrolled_window" swapped="true"/>
<signal name="extra-drag-drop" handler="extra_drag_drop_cb" swapped="true"/>
@@ -52,8 +50,6 @@
<child>
<object class="AdwTabBox" id="box">
<property name="tab-bar">AdwTabBar</property>
- <signal name="notify::needs-attention-left" handler="notify_needs_attention_cb"
swapped="true"/>
- <signal name="notify::needs-attention-right" handler="notify_needs_attention_cb"
swapped="true"/>
<signal name="notify::resize-frozen" handler="notify_resize_frozen_cb" swapped="true"/>
<signal name="stop-kinetic-scrolling" handler="stop_kinetic_scrolling_cb"
object="scrolled_window" swapped="true"/>
<signal name="extra-drag-drop" handler="extra_drag_drop_cb" swapped="true"/>
diff --git a/src/adw-tab-box.c b/src/adw-tab-box.c
index 3f3be10b..55c9a7bd 100644
--- a/src/adw-tab-box.c
+++ b/src/adw-tab-box.c
@@ -21,8 +21,7 @@
#include "adw-widget-utils-private.h"
#include <math.h>
-/* Border collapsing without glitches */
-#define SPACING -1
+#define SPACING 3
#define DND_THRESHOLD_MULTIPLIER 4
#define DROP_SWITCH_TIMEOUT 500
@@ -38,6 +37,9 @@
#define MAX_TAB_WIDTH_NON_EXPAND 220
+#define FADE_OFFSET 6.0f
+#define FADE_WIDTH 36.0f
+
typedef enum {
TAB_RESIZE_NORMAL,
TAB_RESIZE_FIXED_TAB_WIDTH,
@@ -63,6 +65,7 @@ typedef struct {
AdwTabPage *page;
AdwTab *tab;
GtkWidget *container;
+ GtkWidget *separator;
int pos;
int width;
@@ -89,8 +92,6 @@ struct _AdwTabBox
AdwTabBar *tab_bar;
AdwTabView *view;
GtkAdjustment *adjustment;
- gboolean needs_attention_left;
- gboolean needs_attention_right;
gboolean expand_tabs;
gboolean inverted;
@@ -101,7 +102,6 @@ struct _AdwTabBox
int n_tabs;
GtkPopover *context_menu;
- GtkWidget *background;
int allocated_width;
int last_width;
@@ -164,6 +164,12 @@ struct _AdwTabBox
GdkDragAction extra_drag_actions;
GType *extra_drag_types;
gsize extra_drag_n_types;
+
+ GskGLShader *shader;
+ gboolean shader_compiled;
+
+ GtkWidget *needs_attention_left;
+ GtkWidget *needs_attention_right;
};
G_DEFINE_FINAL_TYPE_WITH_CODE (AdwTabBox, adw_tab_box, GTK_TYPE_WIDGET,
@@ -174,8 +180,6 @@ enum {
PROP_PINNED,
PROP_TAB_BAR,
PROP_VIEW,
- PROP_NEEDS_ATTENTION_LEFT,
- PROP_NEEDS_ATTENTION_RIGHT,
PROP_RESIZE_FROZEN,
PROP_HADJUSTMENT,
PROP_VADJUSTMENT,
@@ -200,6 +204,7 @@ static void
remove_and_free_tab_info (TabInfo *info)
{
gtk_widget_unparent (GTK_WIDGET (info->container));
+ gtk_widget_unparent (GTK_WIDGET (info->separator));
g_free (info);
}
@@ -403,6 +408,93 @@ is_touchscreen (GtkGesture *gesture)
return input_source == GDK_SOURCE_TOUCHSCREEN;
}
+static void
+update_separators (AdwTabBox *self)
+{
+ GList *l;
+ GtkStateFlags mask = GTK_STATE_FLAG_PRELIGHT |
+ GTK_STATE_FLAG_ACTIVE |
+ GTK_STATE_FLAG_CHECKED;
+ TabInfo *last_pinned_tab = NULL;
+
+ /* We have a separator between pinned and non-pinned tabs, and we need to
+ * sync it same as the ones within each tab box */
+ if (!self->pinned) {
+ AdwTabBox *box = adw_tab_bar_get_pinned_tab_box (self->tab_bar);
+
+ l = g_list_last (box->tabs);
+
+ if (l) {
+ last_pinned_tab = l->data;
+
+ if (last_pinned_tab->end_reorder_offset < 0) {
+ last_pinned_tab = box->reordered_tab;
+ } else if (l->prev && last_pinned_tab == box->reordered_tab) {
+ TabInfo *prev = l->prev->data;
+
+ if (prev->end_reorder_offset > 0)
+ last_pinned_tab = prev;
+ }
+ }
+ }
+
+ for (l = self->tabs; l; l = l->next) {
+ TabInfo *info = l->data;
+ TabInfo *prev = NULL;
+ TabInfo *prev_prev = NULL;
+ TabInfo *visually_prev = NULL;
+ GtkStateFlags flags;
+
+ if (l->prev)
+ prev = l->prev->data;
+ else if (!self->pinned)
+ prev = last_pinned_tab;
+
+ if (l->prev && l->prev->prev)
+ prev_prev = l->prev->prev->data;
+ else if (!self->pinned)
+ prev_prev = last_pinned_tab;
+
+ if (prev && prev_prev) {
+ /* Since the reordered tab has been moved away, the 2 tabs around it are
+ * now adjacent. Treat them as such for the separator purposes. */
+ if (prev == self->reordered_tab && prev_prev->end_reorder_offset > 0)
+ visually_prev = prev_prev;
+
+ if (prev == self->reordered_tab && info->end_reorder_offset < 0)
+ visually_prev = prev_prev;
+ }
+
+ if (prev && self->reordered_tab) {
+ /* There's a gap between the current and the previous tab. This means the
+ * reordered tab is between them, so treat is as the previous tab. */
+ if (info->end_reorder_offset - prev->end_reorder_offset > 0)
+ visually_prev = self->reordered_tab;
+ }
+
+ if (!visually_prev)
+ visually_prev = prev;
+
+ flags = gtk_widget_get_state_flags (GTK_WIDGET (info->tab));
+
+ if (visually_prev)
+ flags |= gtk_widget_get_state_flags (GTK_WIDGET (visually_prev->tab));
+
+ if ((flags & mask) || !visually_prev)
+ gtk_widget_add_css_class (info->separator, "hidden");
+ else
+ gtk_widget_remove_css_class (info->separator, "hidden");
+ }
+
+ /* Since the first non-pinned separator depends on pinned tabs, we need to
+ * notify the non-pinned box. We don't need to do the opposite though. */
+ if (self->pinned) {
+ AdwTabBox *box = adw_tab_bar_get_tab_box (self->tab_bar);
+
+ update_separators (box);
+ }
+}
+
/* Tab resize delay */
static void
@@ -672,15 +764,8 @@ update_visible (AdwTabBox *self)
right = TRUE;
}
- if (self->needs_attention_left != left) {
- self->needs_attention_left = left;
- g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NEEDS_ATTENTION_LEFT]);
- }
-
- if (self->needs_attention_right != right) {
- self->needs_attention_right = right;
- g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NEEDS_ATTENTION_RIGHT]);
- }
+ gtk_revealer_set_reveal_child (GTK_REVEALER (self->needs_attention_left), left);
+ gtk_revealer_set_reveal_child (GTK_REVEALER (self->needs_attention_right), right);
}
static double
@@ -945,6 +1030,8 @@ check_end_reordering (AdwTabBox *self)
gtk_widget_queue_allocate (GTK_WIDGET (self));
self->reordered_tab = NULL;
+
+ update_separators (self);
}
static void
@@ -955,7 +1042,9 @@ start_reordering (AdwTabBox *self,
/* The reordered tab should be displayed above everything else */
gtk_widget_insert_before (GTK_WIDGET (self->reordered_tab->container),
- GTK_WIDGET (self), NULL);
+ GTK_WIDGET (self), self->needs_attention_left);
+ gtk_widget_insert_before (GTK_WIDGET (self->reordered_tab->separator),
+ GTK_WIDGET (self), self->needs_attention_left);
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
@@ -1096,6 +1185,8 @@ reset_reorder_animations (AdwTabBox *self)
l = l->prev;
animate_reorder_offset (self, l->data, 0);
}
+
+ update_separators (self);
}
static void
@@ -1167,6 +1258,8 @@ page_reordered_cb (AdwTabBox *self,
}
self->continue_reorder = FALSE;
+
+ update_separators (self);
}
static void
@@ -1218,6 +1311,8 @@ update_drag_reodering (AdwTabBox *self)
animate_reorder_offset (self, info, offset);
}
+
+ update_separators (self);
}
static gboolean
@@ -1622,6 +1717,20 @@ allocate_tab (AdwGizmo *widget,
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (-width_diff / 2, 0)));
}
+static void
+state_flags_changed_cb (GtkWidget *tab,
+ GtkStateFlags previous,
+ AdwTabBox *self)
+{
+ GtkStateFlags flags = gtk_widget_get_state_flags (tab);
+ GtkStateFlags mask = GTK_STATE_FLAG_PRELIGHT |
+ GTK_STATE_FLAG_ACTIVE |
+ GTK_STATE_FLAG_CHECKED;
+
+ if ((flags ^ previous) & mask)
+ update_separators (self);
+}
+
static TabInfo *
create_tab_info (AdwTabBox *self,
AdwTabPage *page)
@@ -1650,10 +1759,15 @@ create_tab_info (AdwTabBox *self,
self->extra_drag_types,
self->extra_drag_n_types);
+ info->separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL);
+ gtk_widget_set_can_target (info->separator, FALSE);
+
gtk_widget_set_parent (GTK_WIDGET (info->tab), info->container);
- gtk_widget_set_parent (info->container, GTK_WIDGET (self));
+ gtk_widget_insert_before (info->separator, GTK_WIDGET (self), self->needs_attention_left);
+ gtk_widget_insert_before (info->container, GTK_WIDGET (self), self->needs_attention_left);
g_signal_connect_object (info->tab, "extra-drag-drop", G_CALLBACK (extra_drag_drop_cb), self, 0);
+ g_signal_connect_object (info->tab, "state-flags-changed", G_CALLBACK (state_flags_changed_cb), self, 0);
return info;
}
@@ -1706,6 +1820,8 @@ page_attached_cb (AdwTabBox *self,
adw_tab_box_select_page (self, page);
else
scroll_to_tab_full (self, info, -1, FOCUS_ANIMATION_DURATION, TRUE);
+
+ update_separators (self);
}
/* Closing */
@@ -1734,6 +1850,8 @@ close_animation_done_cb (TabInfo *info)
remove_and_free_tab_info (info);
self->n_tabs--;
+
+ update_separators (self);
}
static void
@@ -2001,6 +2119,8 @@ insert_placeholder (AdwTabBox *self,
G_CALLBACK (open_animation_done_cb), info);
adw_animation_play (info->appear_animation);
+
+ update_separators (self);
}
static void
@@ -2086,6 +2206,8 @@ remove_animation_done_cb (TabInfo *info)
self->n_tabs--;
self->reorder_placeholder = NULL;
+
+ update_separators (self);
}
static gboolean
@@ -2843,15 +2965,12 @@ adw_tab_box_measure (GtkWidget *widget,
AdwTabBox *self = ADW_TAB_BOX (widget);
int min, nat;
- gtk_widget_measure (self->background, orientation, -1,
- &min, &nat, NULL, NULL);
-
if (self->n_tabs == 0) {
if (minimum)
- *minimum = min;
+ *minimum = 0;
if (natural)
- *natural = nat;
+ *natural = 0;
if (minimum_baseline)
*minimum_baseline = -1;
@@ -2877,30 +2996,41 @@ adw_tab_box_measure (GtkWidget *widget,
}
if (!self->pinned)
- width += SPACING;
+ width += SPACING;
width = MAX (self->last_width, width);
- min = MAX (min, width);
- nat = MAX (nat, width);
+ min = nat = width;
} else {
GList *l;
+ int child_min, child_nat;
min = nat = 0;
for (l = self->tabs; l; l = l->next) {
TabInfo *info = l->data;
- int child_min, child_nat;
gtk_widget_measure (info->container, orientation, -1,
&child_min, &child_nat, NULL, NULL);
- if (child_min > min)
- min = child_min;
+ min = MAX (min, child_min);
+ nat = MAX (nat, child_nat);
- if (child_nat > nat)
- nat = child_nat;
+ gtk_widget_measure (info->separator, orientation, -1,
+ &child_min, NULL, NULL, NULL);
+
+ min = MAX (min, child_min);
}
+
+ gtk_widget_measure (self->needs_attention_left, orientation, -1,
+ &child_min, NULL, NULL, NULL);
+
+ min = MAX (min, child_min);
+
+ gtk_widget_measure (self->needs_attention_right, orientation, -1,
+ &child_min, NULL, NULL, NULL);
+
+ min = MAX (min, child_min);
}
if (minimum)
@@ -2928,8 +3058,8 @@ adw_tab_box_size_allocate (GtkWidget *widget,
GtkAllocation child_allocation;
int pos;
double value;
-
- gtk_widget_allocate (self->background, width, height, baseline, NULL);
+ int indicator_size;
+ GskTransform *transform;
adw_tab_box_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1,
&self->allocated_width, NULL, NULL, NULL);
@@ -3002,6 +3132,8 @@ adw_tab_box_size_allocate (GtkWidget *widget,
for (l = self->tabs; l; l = l->next) {
TabInfo *info = l->data;
+ GtkAllocation separator_allocation;
+ int separator_width;
if (!info->appear_animation)
info->display_width = info->width;
@@ -3015,10 +3147,25 @@ adw_tab_box_size_allocate (GtkWidget *widget,
child_allocation.x = ((info == self->reordered_tab) ? self->reorder_window_x : info->pos) - (int) floor
(value);
child_allocation.y = 0;
- child_allocation.width = info->width;
+ child_allocation.width = MAX (0, info->width);
child_allocation.height = height;
+ gtk_widget_measure (info->separator, GTK_ORIENTATION_HORIZONTAL, -1,
+ &separator_width, NULL, NULL, NULL);
+ separator_allocation.x = child_allocation.x + child_allocation.width;
+ if (is_rtl) {
+ separator_allocation.x = child_allocation.x + child_allocation.width;
+ separator_allocation.x += (SPACING - separator_width) / 2;
+ } else {
+ separator_allocation.x = child_allocation.x;
+ separator_allocation.x -= (SPACING + separator_width) / 2;
+ }
+ separator_allocation.y = 0;
+ separator_allocation.width = separator_width;
+ separator_allocation.height = height;
+
gtk_widget_size_allocate (info->container, &child_allocation, baseline);
+ gtk_widget_size_allocate (info->separator, &separator_allocation, baseline);
pos += (is_rtl ? -1 : 1) * (info->width + SPACING);
}
@@ -3045,58 +3192,124 @@ adw_tab_box_size_allocate (GtkWidget *widget,
}
}
+ gtk_widget_measure (self->needs_attention_left, GTK_ORIENTATION_HORIZONTAL, -1,
+ &indicator_size, NULL, NULL, NULL);
+ gtk_widget_allocate (self->needs_attention_left, indicator_size, height, baseline, NULL);
+
+ gtk_widget_measure (self->needs_attention_right, GTK_ORIENTATION_HORIZONTAL, -1,
+ &indicator_size, NULL, NULL, NULL);
+ transform = gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (width - indicator_size, 0));
+ gtk_widget_allocate (self->needs_attention_right, indicator_size, height, baseline, transform);
+
update_visible (self);
}
static void
-snapshot_tab (AdwTabBox *self,
- GtkSnapshot *snapshot,
- TabInfo *info,
- cairo_region_t *clip_region)
+ensure_shader (AdwTabBox *self)
{
- cairo_rectangle_int_t rect = { 0, 0, 0, 0 };
- gboolean clip = FALSE;
- int pos, width, scroll_pos;
- int i, n;
+ GtkNative *native;
+ GskRenderer *renderer;
+ GError *error = NULL;
- if (gtk_widget_get_opacity (info->container) <= 0)
+ if (self->shader)
return;
- rect.height = gtk_widget_get_height (GTK_WIDGET (self));
- scroll_pos = (int) floor (gtk_adjustment_get_value (self->adjustment));
+ self->shader = gsk_gl_shader_new_from_resource ("/org/gnome/Adwaita/glsl/fade.glsl");
- pos = get_tab_position (self, info);
- width = info->width;
+ native = gtk_widget_get_native (GTK_WIDGET (self));
+ renderer = gtk_native_get_renderer (native);
- n = cairo_region_num_rectangles (clip_region);
- for (i = 0; i < n; i++) {
- cairo_rectangle_int_t clip_rect;
- int x1, x2;
+ self->shader_compiled = gsk_gl_shader_compile (self->shader, renderer, &error);
- cairo_region_get_rectangle (clip_region, i, &clip_rect);
- x1 = clip_rect.x + scroll_pos;
- x2 = x1 + clip_rect.width;
+ if (error) {
+ /* If shaders aren't supported, the error doesn't matter and we just
+ * silently fall back */
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
+ g_critical ("Couldn't compile shader: %s\n", error->message);
+ }
- if (x1 < pos && x2 > pos + width) {
- clip = FALSE;
- break;
+ g_clear_error (&error);
+}
+
+static void
+snapshot_tabs (AdwTabBox *self,
+ GtkSnapshot *snapshot)
+{
+ int w = gtk_widget_get_width (GTK_WIDGET (self));
+ int h = gtk_widget_get_height (GTK_WIDGET (self));
+ int scroll_start, scroll_end;
+ int reordered_pos = -1, reordered_width = -1;
+ GList *l;
+ gboolean is_rtl, is_clipping = FALSE;
+
+ scroll_start = (int) floor (gtk_adjustment_get_value (self->adjustment));
+ scroll_end = scroll_start + (int) ceil (gtk_adjustment_get_page_size (self->adjustment));
+ is_rtl = gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL;
+
+ if (self->reordered_tab && gtk_widget_get_opacity (self->reordered_tab->container) > 0) {
+ int clip_x, clip_width;
+
+ reordered_pos = get_tab_position (self, self->reordered_tab);
+ reordered_width = gtk_widget_get_allocated_width (self->reordered_tab->container);
+
+ if (is_rtl) {
+ clip_x = reordered_pos + reordered_width - scroll_start;
+ clip_width = w - clip_x;
+ } else {
+ clip_x = 0;
+ clip_width = reordered_pos - scroll_start;
}
- if (x2 < pos || x1 > pos + width)
+ gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (clip_x, 0, clip_width, h));
+ is_clipping = TRUE;
+ }
+
+ for (l = self->tabs; l; l = l->next) {
+ TabInfo *info = l->data;
+ int pos, width;
+
+ pos = get_tab_position (self, info);
+ width = gtk_widget_get_allocated_width (info->container);
+
+ if (pos + width < scroll_start)
+ continue;
+
+ if (pos > scroll_end)
+ continue;
+
+ if (info == self->reordered_tab)
continue;
- gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (clip_rect.x, clip_rect.y, clip_rect.width,
clip_rect.height));
+ if (is_clipping &&
+ reordered_pos > 0 && reordered_width > 0 &&
+ ((is_rtl && pos < reordered_pos) ||
+ (!is_rtl && pos + width > reordered_pos + reordered_width))) {
+ int clip_x, clip_width;
+
+ if (is_rtl) {
+ clip_x = 0;
+ clip_width = reordered_pos - scroll_start;
+ } else {
+ clip_x = reordered_pos + reordered_width - scroll_start;
+ clip_width = w - clip_x;
+ }
+
+ reordered_pos = reordered_width = -1;
+
+ gtk_snapshot_pop (snapshot);
+ gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (clip_x, 0, clip_width, h));
+ }
+
gtk_widget_snapshot_child (GTK_WIDGET (self), info->container, snapshot);
- gtk_snapshot_pop (snapshot);
- clip = TRUE;
+ gtk_widget_snapshot_child (GTK_WIDGET (self), info->separator, snapshot);
}
- if (!clip)
- gtk_widget_snapshot_child (GTK_WIDGET (self), info->container, snapshot);
+ if (is_clipping) {
+ gtk_snapshot_pop (snapshot);
- rect.x = pos - scroll_pos;
- rect.width = width;
- cairo_region_subtract_rectangle (clip_region, &rect);
+ gtk_widget_snapshot_child (GTK_WIDGET (self), self->reordered_tab->container, snapshot);
+ gtk_widget_snapshot_child (GTK_WIDGET (self), self->reordered_tab->separator, snapshot);
+ }
}
static void
@@ -3104,42 +3317,54 @@ adw_tab_box_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
AdwTabBox *self = ADW_TAB_BOX (widget);
- int w = gtk_widget_get_width (widget);
- int h = gtk_widget_get_height (widget);
- cairo_rectangle_int_t rect = { 0, 0, 0, 0 };
- cairo_region_t *region;
- int i, n;
- GList *l;
+ double value = gtk_adjustment_get_value (self->adjustment);
+ double page_size = gtk_adjustment_get_page_size (self->adjustment);
+ double upper = gtk_adjustment_get_upper (self->adjustment);
+ gboolean draw_fade = value > 0 || value + page_size < upper;
- rect.width = w;
- rect.height = h;
- region = cairo_region_create_rectangle (&rect);
+ if (!self->n_tabs)
+ return;
- if (self->reordered_tab)
- snapshot_tab (self, snapshot, self->reordered_tab, region);
+ if (draw_fade) {
+ int width, height;
+ graphene_rect_t bounds;
- if (self->selected_tab)
- snapshot_tab (self, snapshot, self->selected_tab, region);
+ ensure_shader (self);
- for (l = self->tabs; l; l = l->next) {
- TabInfo *info = l->data;
+ width = gtk_widget_get_width (widget);
+ height = gtk_widget_get_height (widget);
- if (info == self->reordered_tab || info == self->selected_tab)
- continue;
+ graphene_rect_init (&bounds, 0, 0, width, height);
- snapshot_tab (self, snapshot, info, region);
+ if (self->shader_compiled) {
+ gboolean fadeLeft = value > 0;
+ gboolean fadeRight = value + page_size < upper;
+
+ gtk_snapshot_push_gl_shader (snapshot, self->shader, &bounds,
+ gsk_gl_shader_format_args (self->shader,
+ "offsetLeft", FADE_OFFSET,
+ "offsetRight", FADE_OFFSET,
+ "strengthLeft", fadeLeft ? 1.0f : 0.0f,
+ "strengthRight", fadeRight ? 1.0f : 0.0f,
+ "widthLeft", FADE_WIDTH,
+ "widthRight", FADE_WIDTH,
+ NULL));
+ } else {
+ gtk_snapshot_push_clip (snapshot, &bounds);
+ }
}
- n = cairo_region_num_rectangles (region);
- for (i = 0; i < n; i++) {
- cairo_region_get_rectangle (region, i, &rect);
+ snapshot_tabs (self, snapshot);
+
+ if (draw_fade) {
+ if (self->shader_compiled)
+ gtk_snapshot_gl_shader_pop_texture (snapshot);
- gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (rect.x, rect.y, rect.width, rect.height));
- gtk_widget_snapshot_child (widget, self->background, snapshot);
gtk_snapshot_pop (snapshot);
}
- cairo_region_destroy (region);
+ gtk_widget_snapshot_child (GTK_WIDGET (self), self->needs_attention_left, snapshot);
+ gtk_widget_snapshot_child (GTK_WIDGET (self), self->needs_attention_right, snapshot);
}
static gboolean
@@ -3162,6 +3387,8 @@ adw_tab_box_unrealize (GtkWidget *widget)
g_clear_pointer ((GtkWidget **) &self->context_menu, gtk_widget_unparent);
GTK_WIDGET_CLASS (adw_tab_box_parent_class)->unrealize (widget);
+
+ g_clear_object (&self->shader);
}
static void
@@ -3216,8 +3443,6 @@ adw_tab_box_dispose (GObject *object)
g_clear_handle_id (&self->drop_switch_timeout_id, g_source_remove);
- g_clear_pointer (&self->background, gtk_widget_unparent);
-
self->drag_gesture = NULL;
self->tab_bar = NULL;
adw_tab_box_set_view (self, NULL);
@@ -3226,6 +3451,9 @@ adw_tab_box_dispose (GObject *object)
g_clear_object (&self->resize_animation);
g_clear_object (&self->scroll_animation);
+ g_clear_pointer (&self->needs_attention_left, gtk_widget_unparent);
+ g_clear_pointer (&self->needs_attention_right, gtk_widget_unparent);
+
G_OBJECT_CLASS (adw_tab_box_parent_class)->dispose (object);
}
@@ -3260,14 +3488,6 @@ adw_tab_box_get_property (GObject *object,
g_value_set_object (value, self->view);
break;
- case PROP_NEEDS_ATTENTION_LEFT:
- g_value_set_boolean (value, self->needs_attention_left);
- break;
-
- case PROP_NEEDS_ATTENTION_RIGHT:
- g_value_set_boolean (value, self->needs_attention_right);
- break;
-
case PROP_RESIZE_FROZEN:
g_value_set_boolean (value, self->tab_resize_mode != TAB_RESIZE_NORMAL);
break;
@@ -3361,20 +3581,6 @@ adw_tab_box_class_init (AdwTabBoxClass *klass)
ADW_TYPE_TAB_VIEW,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
- props[PROP_NEEDS_ATTENTION_LEFT] =
- g_param_spec_boolean ("needs-attention-left",
- "Needs Attention Left",
- "Needs Attention Left",
- FALSE,
- G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
-
- props[PROP_NEEDS_ATTENTION_RIGHT] =
- g_param_spec_boolean ("needs-attention-right",
- "Needs Attention Right",
- "Needs Attention Right",
- FALSE,
- G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
-
props[PROP_RESIZE_FROZEN] =
g_param_spec_boolean ("resize-frozen",
"Resize Frozen",
@@ -3434,17 +3640,13 @@ adw_tab_box_init (AdwTabBox *self)
{
GtkEventController *controller;
AdwAnimationTarget *target;
+ GtkWidget *widget;
self->can_remove_placeholder = TRUE;
self->expand_tabs = TRUE;
gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN);
- self->background = adw_gizmo_new ("background", NULL, NULL, NULL, NULL, NULL, NULL);
- gtk_widget_set_can_target (self->background, FALSE);
- gtk_widget_set_can_focus (self->background, FALSE);
- gtk_widget_set_parent (self->background, GTK_WIDGET (self));
-
controller = gtk_event_controller_motion_new ();
g_signal_connect_swapped (controller, "motion", G_CALLBACK (motion_cb), self);
g_signal_connect_swapped (controller, "leave", G_CALLBACK (leave_cb), self);
@@ -3511,6 +3713,28 @@ adw_tab_box_init (AdwTabBox *self)
g_signal_connect_swapped (self->scroll_animation, "done",
G_CALLBACK (scroll_animation_done_cb), self);
+
+ self->needs_attention_left = gtk_revealer_new ();
+ gtk_revealer_set_transition_type (GTK_REVEALER (self->needs_attention_left),
+ GTK_REVEALER_TRANSITION_TYPE_CROSSFADE);
+ gtk_widget_set_can_target (self->needs_attention_left, FALSE);
+ gtk_widget_set_can_focus (self->needs_attention_left, FALSE);
+ gtk_widget_set_parent (self->needs_attention_left, GTK_WIDGET (self));
+
+ widget = adw_gizmo_new ("indicator", NULL, NULL, NULL, NULL, NULL, NULL);
+ gtk_widget_add_css_class (widget, "left");
+ gtk_revealer_set_child (GTK_REVEALER (self->needs_attention_left), widget);
+
+ self->needs_attention_right = gtk_revealer_new ();
+ gtk_revealer_set_transition_type (GTK_REVEALER (self->needs_attention_right),
+ GTK_REVEALER_TRANSITION_TYPE_CROSSFADE);
+ gtk_widget_set_can_target (self->needs_attention_right, FALSE);
+ gtk_widget_set_can_focus (self->needs_attention_right, FALSE);
+ gtk_widget_set_parent (self->needs_attention_right, GTK_WIDGET (self));
+
+ widget = adw_gizmo_new ("indicator", NULL, NULL, NULL, NULL, NULL, NULL);
+ gtk_widget_add_css_class (widget, "right");
+ gtk_revealer_set_child (GTK_REVEALER (self->needs_attention_right), widget);
}
void
diff --git a/src/adw-tab.c b/src/adw-tab.c
index 36978829..a9e0eb9c 100644
--- a/src/adw-tab.c
+++ b/src/adw-tab.c
@@ -20,6 +20,12 @@
#define BASE_WIDTH 118
#define BASE_WIDTH_PINNED 28
+#define ATTENTION_INDICATOR_PINNED_WIDTH 14
+#define ATTENTION_INDICATOR_WIDTH_MULTIPLIER 0.6
+#define ATTENTION_INDICATOR_MIN_WIDTH 20
+#define ATTENTION_INDICATOR_MAX_WIDTH 180
+#define ATTENTION_INDICATOR_ANIMATION_DURATION 250
+
struct _AdwTab
{
GtkWidget parent_instance;
@@ -31,6 +37,7 @@ struct _AdwTab
GtkImage *indicator_icon;
GtkWidget *indicator_btn;
GtkWidget *close_btn;
+ GtkWidget *needs_attention_indicator;
GtkDropTarget *drop_target;
AdwTabView *view;
@@ -47,6 +54,7 @@ struct _AdwTab
gboolean fully_visible;
AdwAnimation *close_btn_animation;
+ AdwAnimation *needs_attention_animation;
GskGLShader *shader;
gboolean shader_compiled;
@@ -93,6 +101,13 @@ close_btn_animation_value_cb (double value,
gtk_widget_queue_draw (GTK_WIDGET (self));
}
+static void
+attention_indicator_animation_value_cb (double value,
+ AdwTab *self)
+{
+ gtk_widget_queue_allocate (GTK_WIDGET (self));
+}
+
static void
update_state (AdwTab *self)
{
@@ -197,8 +212,15 @@ update_indicator (AdwTab *self)
static void
update_needs_attention (AdwTab *self)
{
- set_style_class (GTK_WIDGET (self), "needs-attention",
- adw_tab_page_get_needs_attention (self->page));
+ gboolean needs_attention = adw_tab_page_get_needs_attention (self->page);
+
+ adw_timed_animation_set_value_from (ADW_TIMED_ANIMATION (self->needs_attention_animation),
+ adw_animation_get_value (self->needs_attention_animation));
+ adw_timed_animation_set_value_to (ADW_TIMED_ANIMATION (self->needs_attention_animation),
+ needs_attention ? 1 : 0);
+ adw_animation_play (self->needs_attention_animation);
+
+ set_style_class (GTK_WIDGET (self), "needs-attention", needs_attention);
}
static void
@@ -381,6 +403,11 @@ adw_tab_measure (GtkWidget *widget,
&child_min, &child_nat, NULL, NULL);
min = MAX (min, child_min);
nat = MAX (nat, child_nat);
+
+ gtk_widget_measure (self->needs_attention_indicator, orientation, for_size,
+ &child_min, &child_nat, NULL, NULL);
+ min = MAX (min, child_min);
+ nat = MAX (nat, child_nat);
}
if (minimum)
@@ -426,6 +453,22 @@ allocate_child (GtkWidget *child,
gtk_widget_size_allocate (child, &child_alloc, baseline);
}
+static int
+get_attention_indicator_width (AdwTab *self,
+ int center_width)
+{
+ double base_width;
+
+ if (self->pinned) {
+ base_width = ATTENTION_INDICATOR_PINNED_WIDTH;
+ } else {
+ base_width = center_width * ATTENTION_INDICATOR_WIDTH_MULTIPLIER;
+ base_width = CLAMP (base_width, ATTENTION_INDICATOR_MIN_WIDTH, ATTENTION_INDICATOR_MAX_WIDTH);
+ }
+
+ return base_width * adw_animation_get_value (self->needs_attention_animation);
+}
+
static void
adw_tab_size_allocate (GtkWidget *widget,
int width,
@@ -433,14 +476,16 @@ adw_tab_size_allocate (GtkWidget *widget,
int baseline)
{
AdwTab *self = ADW_TAB (widget);
- int indicator_width, close_width, icon_width, title_width;
+ int indicator_width, close_width, icon_width, title_width, needs_attention_width;
int center_x, center_width = 0;
int start_width = 0, end_width = 0;
+ int needs_attention_x;
measure_child (self->icon_stack, height, &icon_width);
measure_child (self->title, height, &title_width);
measure_child (self->indicator_btn, height, &indicator_width);
measure_child (self->close_btn, height, &close_width);
+ measure_child (self->needs_attention_indicator, height, &needs_attention_width);
if (gtk_widget_get_visible (self->indicator_btn)) {
if (self->pinned) {
@@ -489,6 +534,13 @@ adw_tab_size_allocate (GtkWidget *widget,
gtk_widget_get_visible (self->close_btn) &&
center_x + center_width > width - close_width;
+ needs_attention_width = MAX (needs_attention_width,
+ get_attention_indicator_width (self, center_width));
+ needs_attention_x = (width - needs_attention_width) / 2;
+
+ allocate_child (self->needs_attention_indicator, width, height,
+ needs_attention_x, needs_attention_width, baseline);
+
if (gtk_widget_get_visible (self->icon_stack)) {
allocate_child (self->icon_stack, width, height,
center_x, icon_width, baseline);
@@ -530,6 +582,7 @@ adw_tab_snapshot (GtkWidget *widget,
float opacity = gtk_widget_get_opacity (self->close_btn);
gboolean draw_fade = self->close_overlap && opacity > 0;
+ gtk_widget_snapshot_child (widget, self->needs_attention_indicator, snapshot);
gtk_widget_snapshot_child (widget, self->indicator_btn, snapshot);
gtk_widget_snapshot_child (widget, self->icon_stack, snapshot);
@@ -697,10 +750,12 @@ adw_tab_dispose (GObject *object)
g_clear_object (&self->shader);
g_clear_object (&self->close_btn_animation);
+ g_clear_object (&self->needs_attention_animation);
gtk_widget_unparent (self->indicator_btn);
gtk_widget_unparent (self->icon_stack);
gtk_widget_unparent (self->title);
gtk_widget_unparent (self->close_btn);
+ gtk_widget_unparent (self->needs_attention_indicator);
G_OBJECT_CLASS (adw_tab_parent_class)->dispose (object);
}
@@ -780,6 +835,7 @@ adw_tab_class_init (AdwTabClass *klass)
gtk_widget_class_bind_template_child (widget_class, AdwTab, indicator_icon);
gtk_widget_class_bind_template_child (widget_class, AdwTab, indicator_btn);
gtk_widget_class_bind_template_child (widget_class, AdwTab, close_btn);
+ gtk_widget_class_bind_template_child (widget_class, AdwTab, needs_attention_indicator);
gtk_widget_class_bind_template_child (widget_class, AdwTab, drop_target);
gtk_widget_class_bind_template_callback (widget_class, close_clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, indicator_clicked_cb);
@@ -815,6 +871,16 @@ adw_tab_init (AdwTab *self)
adw_timed_animation_set_easing (ADW_TIMED_ANIMATION (self->close_btn_animation),
ADW_EASE_IN_OUT_CUBIC);
+
+ target = adw_callback_animation_target_new ((AdwAnimationTargetFunc)
+ attention_indicator_animation_value_cb,
+ self, NULL);
+ self->needs_attention_animation =
+ adw_timed_animation_new (GTK_WIDGET (self), 0, 0,
+ ATTENTION_INDICATOR_ANIMATION_DURATION, target);
+
+ adw_timed_animation_set_easing (ADW_TIMED_ANIMATION (self->needs_attention_animation),
+ ADW_EASE_IN_OUT_CUBIC);
}
AdwTab *
diff --git a/src/adw-tab.ui b/src/adw-tab.ui
index ff16772f..ef9c3730 100644
--- a/src/adw-tab.ui
+++ b/src/adw-tab.ui
@@ -88,5 +88,11 @@
</style>
</object>
</child>
+ <child>
+ <object class="AdwGizmo" id="needs_attention_indicator">
+ <property name="css-name">indicator</property>
+ <property name="valign">end</property>
+ </object>
+ </child>
</template>
</interface>
diff --git a/src/stylesheet/widgets/_tab-view.scss b/src/stylesheet/widgets/_tab-view.scss
index 551e1d14..bc720f98 100644
--- a/src/stylesheet/widgets/_tab-view.scss
+++ b/src/stylesheet/widgets/_tab-view.scss
@@ -1,128 +1,62 @@
-$tab_needs_attention_gradient: radial-gradient(ellipse at bottom,
- transparentize(white, .2),
- gtkalpha($accent_color, .4) 10%,
- gtkalpha($accent_color, 0) 30%);
-
-
-@mixin undershoot-gradient($dir, $color) {
- background: linear-gradient(to #{$dir},
- $color,
- transparentize(black, 1) 20px);
-}
-
-@mixin need-attention-gradient($dir) {
- background: linear-gradient(to #{$dir},
- gtkalpha($accent_color, .5),
- gtkalpha($accent_color, .3) 1px,
- gtkalpha($accent_color, 0) 20px);
-}
-
tabbar {
.box {
min-height: 38px;
}
- scrolledwindow.pinned {
- undershoot {
- border: 0 solid $border_color;
- }
-
- &:dir(rtl) undershoot.left {
- border-left-width: 1px;
- }
-
- &:dir(ltr) undershoot.right {
- border-right-width: 1px;
+ tabbox {
+ > widget {
+ @include focus-ring();
+ border-radius: $button_radius;
+ margin-bottom: 3px;
+ margin-top: 3px;
}
- tabbox > background {
- &:dir(ltr) {
- box-shadow: inset -1px 0 $border_color;
- }
+ > separator {
+ margin-top: 9px;
+ margin-bottom: 9px;
+ transition: opacity 150ms ease-in-out;
- &:dir(rtl) {
- box-shadow: inset 1px 0 $border_color;
+ &.hidden {
+ opacity: 0;
}
}
}
- undershoot {
+ tab {
transition: background 150ms ease-in-out;
- &.left {
- @include undershoot-gradient("right", $shade_color);
- }
-
- &.right {
- @include undershoot-gradient("left", $shade_color);
- }
- }
-
- .needs-attention-left undershoot.left {
- @include need-attention-gradient("right");
- }
-
- .needs-attention-right undershoot.right {
- @include need-attention-gradient("left");
- }
-
- tabbox {
- > background {
- background-color: $shade_color;
+ @if $contrast == 'high' {
+ &:hover,
+ &:active,
+ &:checked {
+ box-shadow: inset 0 0 0 1px $border_color;
+ }
}
- > widget {
- @include focus-ring();
- }
- }
+ &:checked {
+ background-color: $view_selected_color;
- tab {
- border-style: solid;
- border-color: $border_color;
- border-width: 0 1px 0 1px;
- transition: background 150ms ease-in-out;
- background-color: gtkalpha($shade_color, .6);
- background-clip: padding-box;
+ &:hover {
+ background-color: $view_selected_hover_color;
- &:checked {
- background-color: transparent;
+ &:active {
+ background-color: $view_selected_active_color;
+ }
+ }
}
&:hover {
- background-image: image(gtkalpha(currentColor, .03));
- }
-
- &.needs-attention {
- background-image: $tab_needs_attention_gradient;
+ background-color: $view_hover_color;
- &:hover {
- background-image: image(gtkalpha(currentColor, .03)), $tab_needs_attention_gradient;
+ &:active {
+ background-color: $view_active_color;
}
}
}
.start-action,
.end-action {
- background-color: gtkalpha($shade_color, .6);
- background-clip: padding-box;
- border-color: $border_color;
- border-style: solid;
- transition: background 150ms ease-in-out;
-
- button {
- border: none;
- border-radius: 0;
- }
- }
-
- .start-action:dir(ltr),
- .end-action:dir(rtl) {
- border-right-width: 1px;
- }
-
- .start-action:dir(rtl),
- .end-action:dir(ltr) {
- border-left-width: 1px;
+ padding: 3px;
}
&:not(.inline) {
@@ -132,59 +66,6 @@ tabbar {
border-bottom: 1px solid $headerbar_border_color;
}
- scrolledwindow.pinned {
- undershoot {
- border-color: $headerbar_border_color;
- }
-
- tabbox > background {
- &:dir(ltr) {
- box-shadow: inset -1px 0 $headerbar_border_color;
- }
-
- &:dir(rtl) {
- box-shadow: inset 1px 0 $headerbar_border_color;
- }
- }
- }
-
- undershoot {
- &.left {
- @include undershoot-gradient("right", $headerbar_shade_color);
- }
-
- &.right {
- @include undershoot-gradient("left", $headerbar_shade_color);
- }
- }
-
- .needs-attention-left undershoot.left {
- @include need-attention-gradient("right");
- }
-
- .needs-attention-right undershoot.right {
- @include need-attention-gradient("left");
- }
-
- tabbox > background {
- background-color: $headerbar_shade_color;
- }
-
- tab {
- border-color: $headerbar_border_color;
- background-color: gtkalpha($headerbar_shade_color, .6);
-
- &:checked {
- background-color: transparent;
- }
- }
-
- .start-action,
- .end-action {
- background-color: gtkalpha($headerbar_shade_color, .6);
- border-color: $headerbar_border_color;
- }
-
&:backdrop .box {
background-color: $headerbar_backdrop_color;
transition: $backdrop_transition;
@@ -193,20 +74,18 @@ tabbar {
}
dnd tab {
- min-height: 26px;
background-color: $headerbar_bg_color;
+ background-image: image($view_selected_active_color);
color: $headerbar_fg_color;
- &.needs-attention {
- background-image: $tab_needs_attention_gradient;
- }
+ box-shadow: 0 0 0 1px transparentize(black, 0.97),
+ 0 1px 3px 1px transparentize(black, .93),
+ 0 2px 6px 2px transparentize(black, .97);
- box-shadow: 0 1px 5px 1px transparentize(black, .91),
- 0 2px 14px 3px transparentize(black, .95),
- 0 0 0 1px transparentize(black, if($contrast == 'high', .2, .95));
-
- outline: 1px solid $window_outline_color;
- outline-offset: -1px;
+ @if $contrast == 'high' {
+ outline: 1px solid $border_color;
+ outline-offset: -1px;
+ }
margin: 25px;
}
@@ -214,7 +93,9 @@ dnd tab {
tabbar,
dnd {
tab {
+ min-height: 24px;
padding: 6px;
+ border-radius: $button_radius;
button.image-button {
padding: 0;
@@ -223,6 +104,13 @@ dnd {
min-height: 24px;
border-radius: 99px;
}
+
+ indicator {
+ min-height: 2px;
+ border-radius: 2px;
+ background: if($contrast == 'high', $accent_color, gtkalpha($accent_color, 0.5));
+ transform: translateY(6px);
+ }
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]