mirror of
https://github.com/elementary/gala.git
synced 2024-12-24 17:53:19 +03:00
Show window titles in Multitasking View (#1076)
This commit is contained in:
parent
3916d058c9
commit
ac8a21e990
@ -195,8 +195,7 @@ public class Gala.GestureTracker : Object {
|
||||
float value = ((target_value - initial_value) * (float) percentage) + initial_value;
|
||||
|
||||
if (rounded) {
|
||||
var scale_factor = InternalUtils.get_ui_scaling_factor ();
|
||||
value = (float) Math.round (value * scale_factor) / scale_factor;
|
||||
value = (float) InternalUtils.pixel_align (value);
|
||||
}
|
||||
|
||||
return value;
|
||||
|
@ -337,6 +337,14 @@ namespace Gala {
|
||||
return Meta.Backend.get_backend ().get_settings ().get_ui_scaling_factor ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Round the value to match physical pixels.
|
||||
*/
|
||||
public static int pixel_align (float value) {
|
||||
var scale_factor = InternalUtils.get_ui_scaling_factor ();
|
||||
return (int) Math.round (value * scale_factor) / scale_factor;
|
||||
}
|
||||
|
||||
private static Gtk.StyleContext selection_style_context = null;
|
||||
public static Gdk.RGBA get_theme_accent_color () {
|
||||
if (selection_style_context == null) {
|
||||
|
147
src/Widgets/Tooltip.vala
Normal file
147
src/Widgets/Tooltip.vala
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2021 elementary, Inc (https://elementary.io)
|
||||
* 2021 José Expósito <jose.exposito89@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Clutter actor to display text in a tooltip-like component.
|
||||
*/
|
||||
public class Gala.Tooltip : Clutter.Actor {
|
||||
private static Clutter.Color text_color;
|
||||
private static Gdk.RGBA bg_color;
|
||||
private static Gtk.Border padding;
|
||||
private static int border_radius;
|
||||
|
||||
/**
|
||||
* Canvas to draw the Tooltip background.
|
||||
*/
|
||||
private Clutter.Canvas background_canvas;
|
||||
|
||||
/**
|
||||
* Actor to display the Tooltip text.
|
||||
*/
|
||||
private Clutter.Text? text_actor = null;
|
||||
|
||||
/**
|
||||
* Text displayed in the Tooltip.
|
||||
* @see set_text
|
||||
*/
|
||||
private string text;
|
||||
|
||||
/**
|
||||
* Maximum width of the Tooltip.
|
||||
* @see set_max_width
|
||||
*/
|
||||
public float max_width;
|
||||
|
||||
static construct {
|
||||
var label_widget_path = new Gtk.WidgetPath ();
|
||||
label_widget_path.append_type (GLib.Type.from_name ("label"));
|
||||
label_widget_path.iter_set_object_name (-1, "tooltip");
|
||||
|
||||
var tooltip_style_context = new Gtk.StyleContext ();
|
||||
tooltip_style_context.add_class (Gtk.STYLE_CLASS_BACKGROUND);
|
||||
tooltip_style_context.set_path (label_widget_path);
|
||||
|
||||
bg_color = (Gdk.RGBA) tooltip_style_context.get_property (
|
||||
Gtk.STYLE_PROPERTY_BACKGROUND_COLOR,
|
||||
Gtk.StateFlags.NORMAL
|
||||
);
|
||||
|
||||
border_radius = (int) tooltip_style_context.get_property (
|
||||
Gtk.STYLE_PROPERTY_BORDER_RADIUS,
|
||||
Gtk.StateFlags.NORMAL
|
||||
);
|
||||
|
||||
padding = tooltip_style_context.get_padding (Gtk.StateFlags.NORMAL);
|
||||
|
||||
text_color = Clutter.Color.from_string ("#ffffff");
|
||||
}
|
||||
|
||||
construct {
|
||||
text = "";
|
||||
max_width = 200;
|
||||
|
||||
background_canvas = new Clutter.Canvas ();
|
||||
background_canvas.draw.connect (draw_background);
|
||||
content = background_canvas;
|
||||
|
||||
draw ();
|
||||
}
|
||||
|
||||
public void set_text (string new_text, bool redraw = true) {
|
||||
text = new_text;
|
||||
|
||||
if (redraw) {
|
||||
draw ();
|
||||
}
|
||||
}
|
||||
|
||||
public void set_max_width (float new_max_width, bool redraw = true) {
|
||||
max_width = new_max_width;
|
||||
|
||||
if (redraw) {
|
||||
draw ();
|
||||
}
|
||||
}
|
||||
|
||||
private void draw () {
|
||||
visible = (text.length != 0);
|
||||
|
||||
if (!visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
// First set the text
|
||||
remove_child (text_actor);
|
||||
|
||||
text_actor = new Clutter.Text () {
|
||||
color = text_color,
|
||||
x = padding.left,
|
||||
y = padding.top,
|
||||
ellipsize = Pango.EllipsizeMode.MIDDLE,
|
||||
use_markup = true
|
||||
};
|
||||
text_actor.set_markup (Markup.printf_escaped ("<span size='large'>%s</span>", text));
|
||||
|
||||
if ((text_actor.width + padding.left + padding.right) > max_width) {
|
||||
text_actor.width = max_width - padding.left - padding.right;
|
||||
}
|
||||
|
||||
add_child (text_actor);
|
||||
|
||||
// Adjust the size of the tooltip to the text
|
||||
width = text_actor.width + padding.left + padding.right;
|
||||
height = text_actor.height + padding.top + padding.bottom;
|
||||
background_canvas.set_size ((int) width, (int) height);
|
||||
|
||||
// And paint the background
|
||||
background_canvas.invalidate ();
|
||||
}
|
||||
|
||||
private static bool draw_background (Cairo.Context cr, int width, int height) {
|
||||
cr.save ();
|
||||
cr.set_operator (Cairo.Operator.CLEAR);
|
||||
cr.paint ();
|
||||
cr.restore ();
|
||||
|
||||
Granite.Drawing.Utilities.cairo_rounded_rectangle (cr, 0, 0, width, height, border_radius);
|
||||
cr.set_source_rgba (bg_color.red, bg_color.green, bg_color.blue, bg_color.alpha);
|
||||
cr.fill ();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -42,12 +42,14 @@ namespace Gala {
|
||||
}
|
||||
|
||||
/**
|
||||
* A container for a clone of the texture of a MetaWindow, a WindowIcon,
|
||||
* A container for a clone of the texture of a MetaWindow, a WindowIcon, a Tooltip with the title,
|
||||
* a close button and a shadow. Used together with the WindowCloneContainer.
|
||||
*/
|
||||
public class WindowClone : Actor {
|
||||
const int WINDOW_ICON_SIZE = 64;
|
||||
const int ACTIVE_SHAPE_SIZE = 12;
|
||||
const int FADE_ANIMATION_DURATION = 200;
|
||||
const int TITLE_MAX_WIDTH_MARGIN = 60;
|
||||
|
||||
/**
|
||||
* The window was selected. The MultitaskingView should consider activating
|
||||
@ -83,7 +85,7 @@ namespace Gala {
|
||||
_active = value;
|
||||
|
||||
active_shape.save_easing_state ();
|
||||
active_shape.set_easing_duration (200);
|
||||
active_shape.set_easing_duration (FADE_ANIMATION_DURATION);
|
||||
|
||||
active_shape.opacity = _active ? 255 : 0;
|
||||
|
||||
@ -116,10 +118,12 @@ namespace Gala {
|
||||
ulong check_confirm_dialog_cb = 0;
|
||||
uint shadow_update_timeout = 0;
|
||||
int scale_factor = 0;
|
||||
bool in_slot_animation = false;
|
||||
|
||||
Actor close_button;
|
||||
Actor active_shape;
|
||||
Actor window_icon;
|
||||
Tooltip window_title;
|
||||
|
||||
public WindowClone (Meta.Window window, GestureTracker? gesture_tracker, bool overview_mode = false) {
|
||||
Object (window: window, gesture_tracker: gesture_tracker, overview_mode: overview_mode);
|
||||
@ -154,7 +158,7 @@ namespace Gala {
|
||||
|
||||
close_button = Utils.create_close_button ();
|
||||
close_button.opacity = 0;
|
||||
close_button.set_easing_duration (200);
|
||||
close_button.set_easing_duration (FADE_ANIMATION_DURATION);
|
||||
close_button.button_press_event.connect (() => {
|
||||
close_window ();
|
||||
return true;
|
||||
@ -168,9 +172,11 @@ namespace Gala {
|
||||
window_icon.set_pivot_point (0.5f, 0.5f);
|
||||
window_icon.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
|
||||
window_icon.set_easing_mode (MultitaskingView.ANIMATION_MODE);
|
||||
window_icon.set_position (
|
||||
(window_frame_rect.width - WINDOW_ICON_SIZE) / 2,
|
||||
window_frame_rect.height - (WINDOW_ICON_SIZE * scale_factor) * 0.75f);
|
||||
set_window_icon_position (window_frame_rect.width, window_frame_rect.height);
|
||||
|
||||
window_title = new Tooltip ();
|
||||
window_title.opacity = 0;
|
||||
window_title.set_easing_duration (FADE_ANIMATION_DURATION);
|
||||
|
||||
active_shape = new Clutter.Actor ();
|
||||
active_shape.background_color = { 255, 255, 255, 200 };
|
||||
@ -178,6 +184,7 @@ namespace Gala {
|
||||
|
||||
add_child (active_shape);
|
||||
add_child (window_icon);
|
||||
add_child (window_title);
|
||||
add_child (close_button);
|
||||
|
||||
load_clone ();
|
||||
@ -225,6 +232,7 @@ namespace Gala {
|
||||
set_child_below_sibling (active_shape, clone);
|
||||
set_child_above_sibling (close_button, clone);
|
||||
set_child_above_sibling (window_icon, clone);
|
||||
set_child_above_sibling (window_title, clone);
|
||||
|
||||
transition_to_original_state (false);
|
||||
|
||||
@ -295,6 +303,9 @@ namespace Gala {
|
||||
var target_x = outer_rect.x - offset_x;
|
||||
var target_y = outer_rect.y - offset_y;
|
||||
|
||||
in_slot_animation = true;
|
||||
place_widgets (outer_rect.width, outer_rect.height);
|
||||
|
||||
GestureTracker.OnBegin on_animation_begin = () => {
|
||||
window_icon.set_easing_duration (0);
|
||||
};
|
||||
@ -308,9 +319,9 @@ namespace Gala {
|
||||
|
||||
set_size (width, height);
|
||||
set_position (x, y);
|
||||
|
||||
window_icon.opacity = (uint) opacity;
|
||||
window_icon.set_position ((width - WINDOW_ICON_SIZE) / 2,
|
||||
height - (WINDOW_ICON_SIZE * scale_factor) * 0.75f);
|
||||
set_window_icon_position (width, height, false);
|
||||
};
|
||||
|
||||
GestureTracker.OnEnd on_animation_end = (percentage, cancel_action) => {
|
||||
@ -337,9 +348,13 @@ namespace Gala {
|
||||
toggle_shadow (false);
|
||||
}
|
||||
|
||||
window_icon.set_position ((outer_rect.width - WINDOW_ICON_SIZE) / 2, outer_rect.height - (WINDOW_ICON_SIZE * scale_factor) * 0.75f);
|
||||
window_icon.opacity = 0;
|
||||
close_button.opacity = 0;
|
||||
set_window_icon_position (outer_rect.width, outer_rect.height);
|
||||
|
||||
window_icon.get_transition ("opacity").completed.connect (() => {
|
||||
in_slot_animation = false;
|
||||
place_widgets (outer_rect.width, outer_rect.height);
|
||||
});
|
||||
};
|
||||
|
||||
if (!animate || gesture_tracker == null || !with_gesture) {
|
||||
@ -360,10 +375,11 @@ namespace Gala {
|
||||
var initial_width = width;
|
||||
var initial_height = height;
|
||||
|
||||
GestureTracker.OnBegin on_animation_begin = () => {
|
||||
window_icon.opacity = 0;
|
||||
window_icon.set_easing_duration (0);
|
||||
};
|
||||
window_icon.opacity = 0;
|
||||
window_icon.set_easing_duration (0);
|
||||
|
||||
in_slot_animation = true;
|
||||
place_widgets (rect.width, rect.height);
|
||||
|
||||
GestureTracker.OnUpdate on_animation_update = (percentage) => {
|
||||
var x = GestureTracker.animation_value (initial_x, rect.x, percentage);
|
||||
@ -374,9 +390,9 @@ namespace Gala {
|
||||
|
||||
set_size (width, height);
|
||||
set_position (x, y);
|
||||
|
||||
window_icon.opacity = (uint) opacity;
|
||||
window_icon.set_position ((width - WINDOW_ICON_SIZE) / 2,
|
||||
height - (WINDOW_ICON_SIZE * scale_factor) * 0.75f);
|
||||
set_window_icon_position (width, height, false);
|
||||
};
|
||||
|
||||
GestureTracker.OnEnd on_animation_end = (percentage, cancel_action) => {
|
||||
@ -394,9 +410,7 @@ namespace Gala {
|
||||
set_position (rect.x, rect.y);
|
||||
|
||||
window_icon.opacity = 255;
|
||||
window_icon.set_position ((rect.width - WINDOW_ICON_SIZE) / 2,
|
||||
rect.height - (WINDOW_ICON_SIZE * scale_factor) * 0.75f);
|
||||
|
||||
set_window_icon_position (rect.width, rect.height);
|
||||
restore_easing_state ();
|
||||
|
||||
toggle_shadow (true);
|
||||
@ -409,13 +423,17 @@ namespace Gala {
|
||||
opacity = 255;
|
||||
restore_easing_state ();
|
||||
}
|
||||
|
||||
window_icon.get_transition ("opacity").completed.connect (() => {
|
||||
in_slot_animation = false;
|
||||
place_widgets (rect.width, rect.height);
|
||||
});
|
||||
};
|
||||
|
||||
if (gesture_tracker == null || !with_gesture) {
|
||||
on_animation_begin (0);
|
||||
on_animation_end (1, false, 0);
|
||||
} else {
|
||||
gesture_tracker.connect_handlers ((owned) on_animation_begin, (owned) on_animation_update, (owned) on_animation_end);
|
||||
gesture_tracker.connect_handlers (null, (owned) on_animation_update, (owned) on_animation_end);
|
||||
}
|
||||
}
|
||||
|
||||
@ -478,14 +496,14 @@ namespace Gala {
|
||||
}
|
||||
|
||||
public override bool enter_event (Clutter.CrossingEvent event) {
|
||||
close_button.opacity = 255;
|
||||
|
||||
close_button.opacity = in_slot_animation ? 0 : 255;
|
||||
window_title.opacity = in_slot_animation ? 0 : 255;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool leave_event (Clutter.CrossingEvent event) {
|
||||
close_button.opacity = 0;
|
||||
|
||||
window_title.opacity = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -498,7 +516,9 @@ namespace Gala {
|
||||
Granite.Widgets.Utils.get_default_close_button_position (out pos);
|
||||
|
||||
close_button.save_easing_state ();
|
||||
window_title.save_easing_state ();
|
||||
close_button.set_easing_duration (0);
|
||||
window_title.set_easing_duration (0);
|
||||
|
||||
close_button.y = -close_button.height * 0.33f;
|
||||
|
||||
@ -510,7 +530,17 @@ namespace Gala {
|
||||
close_button.x = -close_button.width * 0.5f;
|
||||
break;
|
||||
}
|
||||
|
||||
bool show = has_pointer && !in_slot_animation;
|
||||
close_button.opacity = show ? 255 : 0;
|
||||
window_title.opacity = close_button.opacity;
|
||||
|
||||
window_title.set_text (window.get_title (), false);
|
||||
window_title.set_max_width (dest_width - (TITLE_MAX_WIDTH_MARGIN * scale_factor));
|
||||
set_window_title_position (dest_width, dest_height);
|
||||
|
||||
close_button.restore_easing_state ();
|
||||
window_title.restore_easing_state ();
|
||||
}
|
||||
|
||||
void toggle_shadow (bool show) {
|
||||
@ -615,7 +645,7 @@ namespace Gala {
|
||||
|
||||
clone.get_transformed_position (out abs_x, out abs_y);
|
||||
clone.save_easing_state ();
|
||||
clone.set_easing_duration (200);
|
||||
clone.set_easing_duration (FADE_ANIMATION_DURATION);
|
||||
clone.set_easing_mode (AnimationMode.EASE_IN_CUBIC);
|
||||
clone.set_scale (scale, scale);
|
||||
clone.opacity = 0;
|
||||
@ -631,13 +661,14 @@ namespace Gala {
|
||||
set_position (abs_x + prev_parent_x, abs_y + prev_parent_y);
|
||||
|
||||
window_icon.save_easing_state ();
|
||||
window_icon.set_easing_duration (200);
|
||||
window_icon.set_easing_duration (FADE_ANIMATION_DURATION);
|
||||
window_icon.set_easing_mode (AnimationMode.EASE_IN_OUT_CUBIC);
|
||||
window_icon.set_position (click_x - (abs_x + prev_parent_x) - window_icon.width / 2,
|
||||
click_y - (abs_y + prev_parent_y) - window_icon.height / 2);
|
||||
window_icon.restore_easing_state ();
|
||||
|
||||
close_button.opacity = 0;
|
||||
window_title.opacity = 0;
|
||||
|
||||
dragging = true;
|
||||
|
||||
@ -782,10 +813,28 @@ namespace Gala {
|
||||
window_icon.save_easing_state ();
|
||||
window_icon.set_easing_duration (250);
|
||||
window_icon.set_easing_mode (AnimationMode.EASE_OUT_QUAD);
|
||||
window_icon.set_position ((slot.width - WINDOW_ICON_SIZE) / 2, slot.height - WINDOW_ICON_SIZE * 0.75f);
|
||||
set_window_icon_position (slot.width, slot.height);
|
||||
window_icon.restore_easing_state ();
|
||||
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
private void set_window_icon_position (float window_width, float window_height, bool aligned = true) {
|
||||
var x = (window_width - WINDOW_ICON_SIZE) / 2;
|
||||
var y = window_height - (WINDOW_ICON_SIZE * scale_factor) * 0.75f;
|
||||
|
||||
if (aligned) {
|
||||
x = InternalUtils.pixel_align (x);
|
||||
y = InternalUtils.pixel_align (y);
|
||||
}
|
||||
|
||||
window_icon.set_position (x, y);
|
||||
}
|
||||
|
||||
private void set_window_title_position (float window_width, float window_height) {
|
||||
var x = InternalUtils.pixel_align ((window_width - window_title.width) / 2);
|
||||
var y = InternalUtils.pixel_align (window_height - (WINDOW_ICON_SIZE * scale_factor) * 0.75f - (window_title.height / 2) - (18 * scale_factor));
|
||||
window_title.set_position (x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ gala_bin_sources = files(
|
||||
'Widgets/SafeWindowClone.vala',
|
||||
'Widgets/ScreenShield.vala',
|
||||
'Widgets/SelectionArea.vala',
|
||||
'Widgets/Tooltip.vala',
|
||||
'Widgets/WindowClone.vala',
|
||||
'Widgets/WindowCloneContainer.vala',
|
||||
'Widgets/WindowIconActor.vala',
|
||||
|
Loading…
Reference in New Issue
Block a user