Compare commits

...

28 Commits

Author SHA1 Message Date
Carlos Soriano
852c89aa5e experiment with revealers 2016-05-30 17:52:46 +02:00
Carlos Soriano
acf2652f88 gdkdisplay: fix warning
Of possibility of using it uninitialised.
2016-05-25 17:19:02 +02:00
Carlos Soriano
36cf8ad173 f 2016-05-25 17:19:02 +02:00
Carlos Soriano
82c8d2c4b6 another meh 2016-05-25 17:19:02 +02:00
Carlos Soriano
973927c2f6 another try 2016-05-25 17:19:02 +02:00
Carlos Soriano
c90bc86dbb Implement new GtkPathBar
Following mockups and rewritting it completly to be able
to be used by other projects like gnome-builder and dconf-editor
and sanitize its code.
This GtkPathBar will be only "visual", so no file management is done,
and instead a subclass GtkFilesPathBar in a following patch will
implement file management for the use case of GtkFileChooser and Nautilus.
2016-05-25 17:19:02 +02:00
Carlos Soriano
f9731434f9 gtkhidingbox: add copyright and authors 2016-05-25 17:19:02 +02:00
Carlos Soriano
48e971f72e gtkhidingbox: prefer width for height 2016-05-25 17:19:02 +02:00
Carlos Soriano
c68cea3292 gtkhidingbox: add getter for overflow children
Useful to know which children cannot be shown, so clients
can manage themselves those.
A use case is GtkPathBar for the popup overflow menu.
2016-05-25 17:19:02 +02:00
Carlos Soriano
21f0fddfc9 gtkhidingbox: fix wrong extra space distribution
It was using the whole allocation to distribute the space,
instead of the actual extra space.
2016-05-25 17:19:02 +02:00
Carlos Soriano
212a95cafb gtkhidingbox: use internal gtk_widget_simple_clip 2016-05-25 17:19:02 +02:00
Carlos Soriano
be7a7577b9 gtkhidingbox: remove extra widgets pixels
I have to ask Rafał Lużyński why he added it... It makes everything
jumpy when reallocating.

Remove it for now.
2016-05-25 17:19:02 +02:00
Carlos Soriano
c4980370dc gtkhidingbox: add property to choose side to handle overflow
i.e. The case of Nautilus and FileChooser GtkPathBar is that we always
want to show the end part of the path. However that might not be the
case for other uses, like gnome-software and its titles.
2016-05-25 17:19:01 +02:00
Carlos Soriano
facee991ee gtkhidingbox: simplify visibility management
Extract a function, refactor, and manage the widget visibility
and child visibility at once, and use that for further checks.

This will be useful on a later patch when we add a property to choose
between hiding widget from the start or from the end, so we can allocate
or not children just checking the child visibility.
2016-05-25 17:19:01 +02:00
Carlos Soriano
0fa8ff0221 gtkhidingbox: take into account child expand property 2016-05-25 17:19:01 +02:00
Carlos Soriano
871cdf27ec gtkhidingbox: remove unneeded comment 2016-05-25 17:19:01 +02:00
Carlos Soriano
04f1171577 gtkhidingbox: use class_install_properties 2016-05-25 17:19:01 +02:00
Carlos Soriano
0b044ea55a gtkhidingbox: don't nest unneeded loop 2016-05-25 17:19:01 +02:00
Carlos Soriano
84844d1c42 gtkhidingbox: use full variable names 2016-05-25 17:19:01 +02:00
Carlos Soriano
f66ab18126 gtkhidingbox: use directly the parameters 2016-05-25 17:19:01 +02:00
Carlos Soriano
a831aeca08 gtkhidingbox: assume we always have min and nat pointers 2016-05-25 17:19:01 +02:00
Carlos Soriano
3ea9ddac3a gtkhidingbox: use full variable names 2016-05-25 17:19:01 +02:00
Carlos Soriano
b8dfa1d749 gtkhidingbox: use the parameters directly 2016-05-25 17:19:01 +02:00
Carlos Soriano
a1ba8ac410 gtkhidingbox: we can assume we have min and nat pointers 2016-05-25 17:19:01 +02:00
Carlos Soriano
559ce33238 gtkhidingbox: reorder variables 2016-05-25 17:19:01 +02:00
Carlos Soriano
9a0ac6c47d gtkhidingbox: reorder variables 2016-05-25 17:19:01 +02:00
Carlos Soriano
947bf993de gtkhidingbox: use full variable names
Instead of acronims
2016-05-25 17:19:00 +02:00
Carlos Soriano
c9903e0d3b Add GtkHidingBox
We didn't have a way to hide children given the allocation size
available set by the parent.
This is an use case for the GtkPathBar, which will be rewrote in future
patches where we will want to use a composite widget instead of a all
custom allocation widget.

For that, implement a container which hides widgets when the allocated
size is smaller than the requested size by its children.
The code is made by Rafał Lużyński for gnome-software and is adapted to
Gtk+ standards.

Now will follow a few patches improving the code and adding support
for some features needed by the GtkPathBar.
2016-05-25 17:19:00 +02:00
24 changed files with 3443 additions and 1848 deletions

View File

@@ -2628,7 +2628,7 @@ gdk_display_get_monitor_at_point (GdkDisplay *display,
int x,
int y)
{
GdkMonitor *nearest;
GdkMonitor *nearest = NULL;
int nearest_dist = G_MAXINT;
int n_monitors, i;

View File

@@ -197,6 +197,7 @@ gtk_public_h_sources = \
gtkfilechoosernative.h \
gtkfilechooserwidget.h \
gtkfilefilter.h \
gtkfilespathbar.h \
gtkfixed.h \
gtkflowbox.h \
gtkfontbutton.h \
@@ -252,6 +253,7 @@ gtk_public_h_sources = \
gtkpagesetup.h \
gtkpaned.h \
gtkpapersize.h \
gtkpathbar.h \
gtkplacessidebar.h \
gtkplug.h \
gtkpopover.h \
@@ -487,6 +489,7 @@ gtk_private_h_sources = \
gtkgestureswipeprivate.h \
gtkgesturezoomprivate.h \
gtkheaderbarprivate.h \
gtkhidingbox.h \
gtkhslaprivate.h \
gtkiconcache.h \
gtkiconhelperprivate.h \
@@ -518,8 +521,8 @@ gtk_private_h_sources = \
gtkmountoperationprivate.h \
gtknativedialogprivate.h \
gtkorientableprivate.h \
gtkpathbarcontainerprivate.h \
gtkpango.h \
gtkpathbar.h \
gtkplacessidebarprivate.h \
gtkplacesviewprivate.h \
gtkplacesviewrowprivate.h \
@@ -756,6 +759,7 @@ gtk_base_c_sources = \
gtkfilechooserutils.c \
gtkfilechooserwidget.c \
gtkfilefilter.c \
gtkfilespathbar.c \
gtkfilesystem.c \
gtkfilesystemmodel.c \
gtkfixed.c \
@@ -779,6 +783,7 @@ gtk_base_c_sources = \
gtkglarea.c \
gtkgrid.c \
gtkheaderbar.c \
gtkhidingbox.c \
gtkhsla.c \
gtkicon.c \
gtkiconcache.c \
@@ -828,6 +833,7 @@ gtk_base_c_sources = \
gtkorientable.c \
gtkoverlay.c \
gtkpagesetup.c \
gtkpathbarcontainer.c \
gtkpaned.c \
gtkpango.c \
gtkpapersize.c \

View File

@@ -6,7 +6,6 @@
<glade-widget-classes>
<!-- base GTK+ private widgets -->
<glade-widget-class name="GtkPathBar" generic-name="pathbar" title="Path Bar" icon-name="widget-gtk-toolbar"/>
<glade-widget-class name="GtkColorEditor" generic-name="coloreditor" title="Color Editor" icon-name="widget-gtk-colorselection"/>
<glade-widget-class name="GtkColorSwatch" generic-name="colorswatch" title="Color Swatch" icon-name="widget-gtk-colorselection"/>
<glade-widget-class name="GtkColorPlane" generic-name="colorplane" title="Color Plane" icon-name="widget-gtk-colorselection"/>
@@ -23,7 +22,6 @@
</glade-widget-classes>
<glade-widget-group name="gtk-private" title="Private GTK+ Classes">
<glade-widget-class-ref name="GtkPathBar"/>
<glade-widget-class-ref name="GtkColorEditor"/>
<glade-widget-class-ref name="GtkColorSwatch"/>
<glade-widget-class-ref name="GtkColorPlane"/>

View File

@@ -102,6 +102,7 @@
#include <gtk/gtkfilechoosernative.h>
#include <gtk/gtkfilechooserwidget.h>
#include <gtk/gtkfilefilter.h>
#include <gtk/gtkfilespathbar.h>
#include <gtk/gtkflowbox.h>
#include <gtk/gtkfontbutton.h>
#include <gtk/gtkfontchooser.h>
@@ -120,6 +121,7 @@
#include <gtk/gtkglarea.h>
#include <gtk/gtkgrid.h>
#include <gtk/gtkheaderbar.h>
#include <gtk/gtkhidingbox.h>
#include <gtk/gtkicontheme.h>
#include <gtk/gtkiconview.h>
#include <gtk/gtkimage.h>
@@ -154,6 +156,7 @@
#include <gtk/gtkoverlay.h>
#include <gtk/gtkpagesetup.h>
#include <gtk/gtkpapersize.h>
#include <gtk/gtkpathbar.h>
#include <gtk/gtkpaned.h>
#include <gtk/gtkplacessidebar.h>
#include <gtk/gtkpopover.h>

View File

@@ -479,7 +479,12 @@ count_expand_children (GtkBox *box,
{
*visible_children += 1;
if (child->expand || gtk_widget_compute_expand (child->widget, private->orientation))
{
if (GTK_IS_REVEALER (child->widget))
g_print ("########################## IT IS\n");
*expand_children += 1;
}
}
}
}

View File

@@ -49,7 +49,7 @@
#include "gtkmessagedialog.h"
#include "gtkmountoperation.h"
#include "gtkpaned.h"
#include "gtkpathbar.h"
#include "gtkfilespathbar.h"
#include "gtkplacessidebar.h"
#include "gtkplacessidebarprivate.h"
#include "gtkplacesviewprivate.h"
@@ -550,11 +550,9 @@ static void list_row_activated (GtkTreeView *tree_view,
static void list_cursor_changed (GtkTreeView *treeview,
GtkFileChooserWidget *impl);
static void path_bar_clicked (GtkPathBar *path_bar,
GFile *file,
GFile *child,
gboolean child_is_hidden,
GtkFileChooserWidget *impl);
static void on_path_bar_file (GtkFilesPathBar *path_bar,
GParamSpec *pspec,
GtkFileChooserWidget *impl);
static void update_cell_renderer_attributes (GtkFileChooserWidget *impl);
@@ -3034,7 +3032,7 @@ put_recent_folder_in_pathbar (GtkFileChooserWidget *impl, GtkTreeIter *iter)
gtk_tree_model_get (GTK_TREE_MODEL (priv->recent_model), iter,
MODEL_COL_FILE, &file,
-1);
_gtk_path_bar_set_file (GTK_PATH_BAR (priv->browse_path_bar), file, FALSE);
gtk_files_path_bar_set_file (GTK_FILES_PATH_BAR (priv->browse_path_bar), file);
g_object_unref (file);
}
@@ -5482,7 +5480,7 @@ update_current_folder_get_info_cb (GCancellable *cancellable,
if (! _gtk_file_info_consider_as_directory (info))
goto out;
_gtk_path_bar_set_file (GTK_PATH_BAR (priv->browse_path_bar), data->file, data->keep_trail);
gtk_files_path_bar_set_file (GTK_FILES_PATH_BAR (priv->browse_path_bar), data->file);
if (priv->current_folder != data->file)
{
@@ -7842,24 +7840,15 @@ list_row_activated (GtkTreeView *tree_view,
}
static void
path_bar_clicked (GtkPathBar *path_bar,
GFile *file,
GFile *child_file,
gboolean child_is_hidden,
on_path_bar_file (GtkFilesPathBar *path_bar,
GParamSpec *pspec,
GtkFileChooserWidget *impl)
{
if (child_file)
pending_select_files_add (impl, child_file);
GFile *file;
if (!change_folder_and_display_error (impl, file, FALSE))
return;
file = gtk_files_path_bar_get_file (path_bar);
/* Say we have "/foo/bar/[.baz]" and the user clicks on "bar". We should then
* show hidden files so that ".baz" appears in the file list, as it will still
* be shown in the path bar: "/foo/[bar]/.baz"
*/
if (child_is_hidden)
g_object_set (impl, "show-hidden", TRUE, NULL);
change_folder_and_display_error (impl, file, FALSE);
}
static void
@@ -7957,7 +7946,7 @@ up_folder_handler (GtkFileChooserWidget *impl)
{
GtkFileChooserWidgetPrivate *priv = impl->priv;
_gtk_path_bar_up (GTK_PATH_BAR (priv->browse_path_bar));
//_gtk_path_bar_up (GTK_PATH_BAR (priv->browse_path_bar));
}
/* Handler for the "down-folder" keybinding signal */
@@ -7966,7 +7955,7 @@ down_folder_handler (GtkFileChooserWidget *impl)
{
GtkFileChooserWidgetPrivate *priv = impl->priv;
_gtk_path_bar_down (GTK_PATH_BAR (priv->browse_path_bar));
//_gtk_path_bar_down (GTK_PATH_BAR (priv->browse_path_bar));
}
/* Handler for the "home-folder" keybinding signal */
@@ -8495,7 +8484,7 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
gtk_widget_class_bind_template_callback (widget_class, list_selection_changed);
gtk_widget_class_bind_template_callback (widget_class, list_cursor_changed);
gtk_widget_class_bind_template_callback (widget_class, filter_combo_changed);
gtk_widget_class_bind_template_callback (widget_class, path_bar_clicked);
gtk_widget_class_bind_template_callback (widget_class, on_path_bar_file);
gtk_widget_class_bind_template_callback (widget_class, places_sidebar_open_location_cb);
gtk_widget_class_bind_template_callback (widget_class, places_sidebar_show_error_message_cb);
gtk_widget_class_bind_template_callback (widget_class, places_sidebar_show_other_locations_with_flags_cb);
@@ -8561,10 +8550,8 @@ post_process_ui (GtkFileChooserWidget *impl)
g_list_free (cells);
/* Set the GtkPathBar file system backend */
_gtk_path_bar_set_file_system (GTK_PATH_BAR (impl->priv->browse_path_bar), impl->priv->file_system);
file = g_file_new_for_path ("/");
_gtk_path_bar_set_file (GTK_PATH_BAR (impl->priv->browse_path_bar), file, FALSE);
gtk_files_path_bar_set_file (GTK_FILES_PATH_BAR (impl->priv->browse_path_bar), file);
g_object_unref (file);
/* Set the fixed size icon renderer, this requires
@@ -8631,7 +8618,7 @@ gtk_file_chooser_widget_init (GtkFileChooserWidget *impl)
/* Ensure GTK+ private types used by the template
* definition before calling gtk_widget_init_template()
*/
g_type_ensure (GTK_TYPE_PATH_BAR);
g_type_ensure (GTK_TYPE_FILES_PATH_BAR);
g_type_ensure (GTK_TYPE_PLACES_VIEW);
gtk_widget_init_template (GTK_WIDGET (impl));

541
gtk/gtkfilespathbar.c Normal file
View File

@@ -0,0 +1,541 @@
/* gtkfilespathbar.c
*
* Copyright (C) 2015 Red Hat
*
* 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 2 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/>.
*
* Authors: Carlos Soriano <csoriano@gnome.org>
*/
#include "config.h"
#include "gtkfilespathbar.h"
#include "gtkpathbar.h"
#include "gtkpopover.h"
#include "gtkintl.h"
#include "gtkmarshalers.h"
#include "gtktypebuiltins.h"
#define LOCAL_FILESYSTEM_ROOT_URI "file:///"
#define OTHER_LOCATIONS_URI "other-locations:///"
/**
* SECTION:gtkfilespathbar
* @Short_description: Widget that displays a path in UNIX format in a button-like manner
* @Title: GtkFilesPathBar
* @See_also: #GtkPathBar, #GtkFileChooser
*
* #GtkFilesPathBar is a stock widget that displays a path in UNIX format in a way that
* the user can interact with it, selecting part of it or providing menus for
* every part of the path.
*
* Given the usual big lenght of paths, it conveniently manages the overflow of it,
* hiding the parts of the path that doesn't have snouegh space to be displayed
* in a overflow popover
*/
struct _GtkFilesPathBarPrivate
{
GtkWidget *path_bar;
GFile *file;
GCancellable *cancellable;
GFileMonitor *monitor;
};
G_DEFINE_TYPE_WITH_PRIVATE (GtkFilesPathBar, gtk_files_path_bar, GTK_TYPE_BIN)
enum {
POPULATE_POPUP,
LAST_SIGNAL
};
enum {
PROP_0,
PROP_FILE,
LAST_PROP
};
static GParamSpec *files_path_bar_properties[LAST_PROP] = { NULL, };
static guint files_path_bar_signals[LAST_SIGNAL] = { 0 };
typedef struct {
GtkFilesPathBar *path_bar;
GString *display_path;
GFile *root_file;
gchar *root_label;
GIcon *root_icon;
GCancellable *cancellable;
} PathFilesInfo;
static GMount*
get_mounted_mount_for_root (GFile *file)
{
GVolumeMonitor *volume_monitor;
GList *mounts;
GList *l;
GMount *mount;
GMount *result = NULL;
GFile *root = NULL;
GFile *default_location = NULL;
volume_monitor = g_volume_monitor_get ();
mounts = g_volume_monitor_get_mounts (volume_monitor);
for (l = mounts; l != NULL; l = l->next)
{
mount = l->data;
if (g_mount_is_shadowed (mount))
continue;
root = g_mount_get_root (mount);
if (g_file_equal (file, root))
{
result = g_object_ref (mount);
break;
}
default_location = g_mount_get_default_location (mount);
if (!g_file_equal (default_location, root) &&
g_file_equal (file, default_location))
{
result = g_object_ref (mount);
break;
}
}
g_clear_object (&root);
g_clear_object (&default_location);
g_list_free_full (mounts, g_object_unref);
return result;
}
static gboolean
file_is_home_dir (GFile *file)
{
gboolean is_home_dir;
gchar *path;
path = g_file_get_path (file);
is_home_dir = g_strcmp0 (path, g_get_home_dir ()) == 0;
if (path)
g_free (path);
return is_home_dir;
}
static gboolean
file_is_absolute_root (GFile *file)
{
gboolean is_filesystem_root;
gchar *file_basename;
file_basename = g_file_get_basename (file);
is_filesystem_root = g_strcmp0 (file_basename, G_DIR_SEPARATOR_S) == 0;
g_free (file_basename);
return is_filesystem_root;
}
static gboolean
file_is_root (GFile *file)
{
GMount *mount;
gboolean is_root = FALSE;
mount = get_mounted_mount_for_root (file);
is_root = file_is_absolute_root (file) || file_is_home_dir (file) || mount;
g_clear_object (&mount);
return is_root;
}
static GIcon*
get_root_icon (GFile *file)
{
GIcon *icon = NULL;
GFile *local_filesystem_file;
local_filesystem_file = g_file_new_for_uri (LOCAL_FILESYSTEM_ROOT_URI);
if (g_file_equal (file, local_filesystem_file))
icon = g_themed_icon_new ("drive-harddisk");
g_object_unref (local_filesystem_file);
return icon;
}
static gchar*
get_root_label (GFile *file)
{
gchar *label = NULL;
gchar *path;
GMount *mount;
GFile *other_locations;
path = g_file_get_path (file);
mount = get_mounted_mount_for_root (file);
other_locations = g_file_new_for_uri (OTHER_LOCATIONS_URI);
if (g_strcmp0 (path, g_get_home_dir ()) == 0)
label = g_strdup (_("Home"));
else if (g_file_equal (file, other_locations))
label = g_strdup (_("Other Locations"));
else if (mount)
label = g_mount_get_name (mount);
if (path)
g_free (path);
g_clear_object (&mount);
g_object_unref (other_locations);
return label;
}
static void
free_path_files_info (PathFilesInfo *path_files_info)
{
if (path_files_info->display_path)
g_string_free (path_files_info->display_path, TRUE);
if (path_files_info->root_label)
g_free (path_files_info->root_label);
g_clear_object (&path_files_info->cancellable);
g_clear_object (&path_files_info->root_file);
g_clear_object (&path_files_info->root_icon);
g_slice_free (PathFilesInfo, path_files_info);
}
static void
on_all_path_files_info_queried (PathFilesInfo *path_files_info)
{
GtkFilesPathBarPrivate *priv = gtk_files_path_bar_get_instance_private (path_files_info->path_bar);
gchar *root_uri;
root_uri = g_file_get_uri (path_files_info->root_file);
gtk_path_bar_set_path_extended (GTK_PATH_BAR (priv->path_bar),
path_files_info->display_path->str, root_uri,
path_files_info->root_label, path_files_info->root_icon);
g_free (root_uri);
free_path_files_info (path_files_info);
}
static void
on_queried_file_info (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GFile *file = G_FILE (object);
GError *error = NULL;
PathFilesInfo *path_files_info = (PathFilesInfo *) user_data;
GFileInfo *file_info = NULL;
gchar *uri;
uri = g_file_get_uri (file);
if (g_cancellable_is_cancelled (path_files_info->cancellable))
{
free_path_files_info (path_files_info);
goto out;
}
file_info = g_file_query_info_finish (file, result, &error);
if (!error || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
{
if (file_is_root (file))
{
uri = g_file_get_uri (file);
path_files_info->root_icon = get_root_icon (file);
path_files_info->root_label = get_root_label (file);
path_files_info->root_file = g_object_ref (file);
/* If it is not specific root managed by us, just query display name */
if (!path_files_info->root_label && !path_files_info->root_icon)
{
if (!error)
{
path_files_info->root_label = g_strdup (g_file_info_get_display_name (file_info));
}
else
{
g_warning ("Error trying to get info from %s, location not supported", uri);
free_path_files_info (path_files_info);
goto out;
}
}
g_string_prepend (path_files_info->display_path, uri);
on_all_path_files_info_queried (path_files_info);
}
else
{
GFile *parent;
parent = g_file_get_parent (file);
g_string_prepend (path_files_info->display_path, g_file_info_get_display_name (file_info));
g_string_prepend (path_files_info->display_path, G_DIR_SEPARATOR_S);
g_file_query_info_async (parent,
"standard::display-name",
G_FILE_QUERY_INFO_NONE,
G_PRIORITY_DEFAULT,
path_files_info->cancellable,
on_queried_file_info,
path_files_info);
}
}
else
{
g_warning ("%s", error->message);
free_path_files_info (path_files_info);
}
out:
g_object_unref (file);
g_clear_object (&file_info);
if (error)
g_error_free (error);
g_free (uri);
}
static void
on_path_bar_populate_popup (GtkPathBar *path_bar,
GtkWidget *container,
const gchar *selected_path,
GtkFilesPathBar *self)
{
GFile *file;
file = g_file_new_for_path (selected_path);
g_signal_emit (self, files_path_bar_signals[POPULATE_POPUP], 0,
container, file);
}
static void
on_path_bar_selected_path (GtkPathBar *path_bar,
GParamSpec *pspec,
GtkFilesPathBar *self)
{
GFile *file;
file = g_file_new_for_uri (gtk_path_bar_get_selected_path (path_bar));
gtk_files_path_bar_set_file (self, file);
g_object_unref (file);
}
static void
gtk_files_path_bar_dispose (GObject *object)
{
GtkFilesPathBar *self = (GtkFilesPathBar *)object;
GtkFilesPathBarPrivate *priv = gtk_files_path_bar_get_instance_private (self);
g_cancellable_cancel (priv->cancellable);
g_clear_object (&priv->cancellable);
g_clear_object (&priv->file);
G_OBJECT_CLASS (gtk_files_path_bar_parent_class)->dispose (object);
}
static void
gtk_files_path_bar_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkFilesPathBar *self = GTK_FILES_PATH_BAR (object);
GtkFilesPathBarPrivate *priv = gtk_files_path_bar_get_instance_private (self);
switch (prop_id)
{
case PROP_FILE:
g_value_set_object (value, priv->file);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_files_path_bar_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkFilesPathBar *self = GTK_FILES_PATH_BAR (object);
switch (prop_id)
{
case PROP_FILE:
gtk_files_path_bar_set_file (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
gtk_files_path_bar_class_init (GtkFilesPathBarClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = gtk_files_path_bar_dispose;
object_class->get_property = gtk_files_path_bar_get_property;
object_class->set_property = gtk_files_path_bar_set_property;
/**
* GtkFilesPathBar::populate-popup:
* @files_path_bar: the object which received the signal.
* @container: (type Gtk.Widget): a #GtkContainer
* @path: (type const gchar*): string of the path where the user performed a right click.
*
* The path bar emits this signal when the user invokes a contextual
* popup on one of its items. In the signal handler, the application may
* add extra items to the menu as appropriate. For example, a file manager
* may want to add a "Properties" command to the menu.
*
* The @container and all its contents are destroyed after the user
* dismisses the popup. The popup is re-created (and thus, this signal is
* emitted) every time the user activates the contextual menu.
*
* Since: 3.20
*/
files_path_bar_signals [POPULATE_POPUP] =
g_signal_new (I_("populate-popup"),
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkFilesPathBarClass, populate_popup),
NULL, NULL,
_gtk_marshal_VOID__OBJECT_STRING,
G_TYPE_NONE, 2,
GTK_TYPE_WIDGET,
G_TYPE_STRING);
files_path_bar_properties[PROP_FILE] =
g_param_spec_object ("file",
P_("File"),
P_("The file set in the path bar."),
G_TYPE_FILE,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, LAST_PROP, files_path_bar_properties);
gtk_widget_class_set_css_name (widget_class, "files-path-bar");
}
static void
gtk_files_path_bar_init (GtkFilesPathBar *self)
{
GtkFilesPathBarPrivate *priv = gtk_files_path_bar_get_instance_private (self);
g_type_ensure (GTK_TYPE_FILES_PATH_BAR);
priv->path_bar = gtk_path_bar_new ();
gtk_path_bar_set_inverted (GTK_PATH_BAR (priv->path_bar), TRUE);
gtk_widget_show (priv->path_bar);
g_signal_connect (GTK_PATH_BAR (priv->path_bar), "populate-popup",
G_CALLBACK (on_path_bar_populate_popup), self);
g_signal_connect (GTK_PATH_BAR (priv->path_bar), "notify::selected-path",
G_CALLBACK (on_path_bar_selected_path), self);
gtk_container_add (GTK_CONTAINER (self), priv->path_bar);
}
/**
* gtk_files_path_bar_get_file:
* @files_path_bar: a #GtkFilesPathBar
*
* Get the path represented by the files path bar
*
* Returns: (transfer none): The current #GFile.
*
* Since: 3.20
*/
GFile*
gtk_files_path_bar_get_file (GtkFilesPathBar *self)
{
GtkFilesPathBarPrivate *priv;
g_return_val_if_fail (GTK_IS_FILES_PATH_BAR (self), NULL);
priv = gtk_files_path_bar_get_instance_private (GTK_FILES_PATH_BAR (self));
return priv->file;
}
/**
* gtk_files_path_bar_set_file:
* @files_path_bar: a #GtkFilesPathBar
* @file: the #GFile.
*
* Set the #GFile represented by the path bar.
*
* Since: 3.20
*/
void
gtk_files_path_bar_set_file (GtkFilesPathBar *self,
GFile *file)
{
GtkFilesPathBarPrivate *priv;
PathFilesInfo *path_files_info;
g_return_if_fail (GTK_IS_FILES_PATH_BAR (self));
priv = gtk_files_path_bar_get_instance_private (GTK_FILES_PATH_BAR (self));
if (priv->file && g_file_equal (priv->file, file))
return;
g_cancellable_cancel (priv->cancellable);
g_clear_object (&priv->cancellable);
priv->cancellable = g_cancellable_new ();
g_clear_object (&priv->file);
priv->file = g_object_ref (file);
path_files_info = g_slice_new (PathFilesInfo);
path_files_info->path_bar = self;
path_files_info->display_path = g_string_new ("");
path_files_info->root_file = NULL;
path_files_info->root_label = NULL;
path_files_info->root_icon = NULL;
path_files_info->cancellable = g_object_ref (priv->cancellable);
g_file_query_info_async (g_object_ref (file),
"standard::display-name",
G_FILE_QUERY_INFO_NONE,
G_PRIORITY_DEFAULT,
path_files_info->cancellable,
on_queried_file_info,
path_files_info);
g_object_notify_by_pspec (G_OBJECT (self), files_path_bar_properties[PROP_FILE]);
}
GtkWidget *
gtk_files_path_bar_new (void)
{
return g_object_new (GTK_TYPE_FILES_PATH_BAR, NULL);
}

83
gtk/gtkfilespathbar.h Normal file
View File

@@ -0,0 +1,83 @@
/* gtkfilespathbar.h
*
* Copyright (C) 2015 Red Hat
*
* 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 2 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/>.
*
* Authors: Carlos Soriano <csoriano@gnome.org>
*/
#ifndef __GTK_FILES_PATH_BAR_H__
#define __GTK_FILES_PATH_BAR_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkbin.h>
#include <gio/gio.h>
G_BEGIN_DECLS
#define GTK_TYPE_FILES_PATH_BAR (gtk_files_path_bar_get_type())
#define GTK_FILES_PATH_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILES_PATH_BAR, GtkFilesPathBar))
#define GTK_FILES_PATH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILES_PATH_BAR, GtkFilesPathBarClass))
#define GTK_IS_FILES_PATH_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILES_PATH_BAR))
#define GTK_IS_FILES_PATH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILES_PATH_BAR)
#define GTK_FILES_PATH_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILES_PATH_BAR, GtkFilesPathBarClass))
typedef struct _GtkFilesPathBar GtkFilesPathBar;
typedef struct _GtkFilesPathBarClass GtkFilesPathBarClass;
typedef struct _GtkFilesPathBarPrivate GtkFilesPathBarPrivate;
struct _GtkFilesPathBarClass
{
GtkBinClass parent;
/*< public >*/
void (* populate_popup) (GtkFilesPathBar *files_path_bar,
GFile *selected_file);
/*< private >*/
/* Padding for future expansion */
gpointer reserved[10];
};
struct _GtkFilesPathBar
{
GtkBin parent_instance;
};
GDK_AVAILABLE_IN_3_20
GType gtk_files_path_bar_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_20
GtkWidget* gtk_files_path_bar_new (void);
GDK_AVAILABLE_IN_3_20
void gtk_files_path_bar_set_file (GtkFilesPathBar *files_path_bar,
GFile *file);
GDK_AVAILABLE_IN_3_20
GFile* gtk_files_path_bar_get_file (GtkFilesPathBar *files_path_bar);
GDK_AVAILABLE_IN_3_20
gboolean gtk_files_path_bar_get_edit_mode_enabled (GtkFilesPathBar *files_path_bar);
GDK_AVAILABLE_IN_3_20
void gtk_files_path_bar_set_edit_mode_enabled (GtkFilesPathBar *files_path_bar,
gboolean enable);
G_END_DECLS
#endif /* __GTK_FILES_PATH_BAR_H__ */

View File

@@ -29,6 +29,7 @@
#include "gtkcontainerprivate.h"
#include "gtkcsscustomgadgetprivate.h"
#include "gtkprivate.h"
#include "gtkrevealer.h"
#include "gtkintl.h"
@@ -1000,7 +1001,12 @@ gtk_grid_request_compute_expand (GtkGridRequest *request,
line = &lines->lines[attach->pos - lines->min];
line->empty = FALSE;
if (gtk_widget_compute_expand (child->widget, orientation))
{
if (GTK_IS_REVEALER (child->widget))
g_print ("########################## IT IS\n");
line->expand = TRUE;
}
}
for (list = priv->children; list; list = list->next)
@@ -1030,6 +1036,8 @@ gtk_grid_request_compute_expand (GtkGridRequest *request,
if (!has_expand && gtk_widget_compute_expand (child->widget, orientation))
{
if (GTK_IS_REVEALER (child->widget))
g_print ("########################## IT IS\n");
for (i = 0; i < attach->span; i++)
{
if (attach->pos + i >= max || attach->pos + 1 < min)

920
gtk/gtkhidingbox.c Normal file
View File

@@ -0,0 +1,920 @@
/*
* Copyright (C) 2015 Rafał Lużyński <digitalfreak@lingonborough.com>
* Copyright (C) 2015 Red Hat
*
* Licensed under the GNU General Public License Version 2
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Authors: Rafał Lużyński <digitalfreak@lingonborough.com>
* Carlos Soriano <csoriano@gnome.org>
*/
#include "config.h"
#include "gtkhidingbox.h"
#include "gtkwidgetprivate.h"
#include "gtkintl.h"
#include "gtksizerequest.h"
#include "gtkbuildable.h"
#include "gtkrevealer.h"
#include "gtkadjustment.h"
#include "gtkscrolledwindow.h"
#include "gtkbox.h"
//TODO remove
#include "gtkbutton.h"
#include "glib.h"
#define INVERT_ANIMATION_TIME 500 //ms
typedef enum {
ANIMATION_PHASE_NONE,
ANIMATION_PHASE_OUT,
ANIMATION_PHASE_MOVE,
ANIMATION_PHASE_IN
} HidingBoxAnimationPhase;
struct _GtkHidingBoxPrivate
{
GList *children;
gint16 spacing;
gint inverted :1;
GList *widgets_to_hide;
GList *widgets_to_show;
GList *widgets_to_remove;
GList *widgets_shown;
HidingBoxAnimationPhase animation_phase;
gint current_width;
gint current_height;
guint needs_update :1;
gboolean invert_animation;
GtkWidget *scrolled_window;
GtkWidget *box;
GtkAdjustment *hadjustment;
guint tick_id;
guint64 initial_time;
};
static void
gtk_hiding_box_buildable_init (GtkBuildableIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkHidingBox, gtk_hiding_box, GTK_TYPE_CONTAINER,
G_ADD_PRIVATE (GtkHidingBox)
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, gtk_hiding_box_buildable_init))
static void
gtk_hiding_box_buildable_add_child (GtkBuildable *buildable,
GtkBuilder *builder,
GObject *child,
const gchar *type)
{
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (buildable);
if (!type)
{
gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
priv->needs_update = TRUE;
}
else
{
GTK_BUILDER_WARN_INVALID_CHILD_TYPE (GTK_HIDING_BOX (buildable), type);
}
}
static void
gtk_hiding_box_buildable_init (GtkBuildableIface *iface)
{
iface->add_child = gtk_hiding_box_buildable_add_child;
}
enum {
PROP_0,
PROP_SPACING,
PROP_INVERTED,
LAST_PROP
};
static GParamSpec *hiding_box_properties[LAST_PROP] = { NULL, };
static void
gtk_hiding_box_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkHidingBox *box = GTK_HIDING_BOX (object);
switch (prop_id)
{
case PROP_SPACING:
gtk_hiding_box_set_spacing (box, g_value_get_int (value));
break;
case PROP_INVERTED:
gtk_hiding_box_set_inverted (box, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_hiding_box_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkHidingBox *box = GTK_HIDING_BOX (object);
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (box);
switch (prop_id)
{
case PROP_SPACING:
g_value_set_int (value, priv->spacing);
break;
case PROP_INVERTED:
g_value_set_boolean (value, priv->inverted);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_hiding_box_add (GtkContainer *container,
GtkWidget *widget)
{
GtkHidingBox *box = GTK_HIDING_BOX (container);
GtkWidget *revealer;
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (box);
GtkStyleContext *style_context;
revealer = gtk_revealer_new ();
style_context = gtk_widget_get_style_context (revealer);
gtk_style_context_add_class (style_context, "pathbar-initial-opacity");
gtk_revealer_set_transition_type (GTK_REVEALER (revealer),
GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT);
gtk_container_add (GTK_CONTAINER (revealer), widget);
g_print ("box fine? %s \n", G_OBJECT_TYPE_NAME (priv->box));
gtk_container_add (GTK_CONTAINER (priv->box), revealer);
priv->children = g_list_append (priv->children, widget);
gtk_widget_show (revealer);
g_print ("add\n");
}
static void
really_remove_child (GtkHidingBox *self,
GtkWidget *widget)
{
GList *child;
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (self);
g_print ("really remove child %p %s\n", widget, gtk_button_get_label (GTK_BUTTON (widget)));
for (child = priv->widgets_to_remove; child != NULL; child = child->next)
{
GtkWidget *revealer;
revealer = gtk_widget_get_parent (child->data);
g_print ("aver %p\n", child->data);
if (child->data == widget && !gtk_revealer_get_child_revealed (GTK_REVEALER (revealer)))
{
g_print ("############################## INSIDE\n");
gboolean was_visible = gtk_widget_get_visible (widget);
priv->widgets_to_remove = g_list_remove (priv->widgets_to_remove,
child->data);
gtk_container_remove (GTK_CONTAINER (priv->box), revealer);
if (was_visible)
gtk_widget_queue_resize (GTK_WIDGET (self));
break;
}
}
}
static void
unrevealed_really_remove_child (GObject *widget,
GParamSpec *pspec,
gpointer user_data)
{
GtkHidingBox *self = GTK_HIDING_BOX (user_data);
g_print ("unrevelaed really remove child %p %s\n", widget, G_OBJECT_TYPE_NAME (widget));
really_remove_child (self, gtk_bin_get_child (GTK_BIN (widget)));
}
static void
gtk_hiding_box_remove (GtkContainer *container,
GtkWidget *widget)
{
GList *child;
GtkHidingBox *box = GTK_HIDING_BOX (container);
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (box);
GtkWidget *to_remove;
g_print ("remove %p %s\n", widget, G_OBJECT_TYPE_NAME (widget));
if (GTK_IS_REVEALER (widget) && gtk_widget_get_parent (widget) == priv->box)
to_remove = gtk_bin_get_child (widget);
else
to_remove = widget;
priv->widgets_to_remove = g_list_append (priv->widgets_to_remove, to_remove);
priv->children = g_list_remove (priv->children, to_remove);
priv->needs_update = TRUE;
gtk_widget_queue_resize (GTK_WIDGET (container));
}
static void
gtk_hiding_box_forall (GtkContainer *container,
gboolean include_internals,
GtkCallback callback,
gpointer callback_data)
{
GtkHidingBox *box = GTK_HIDING_BOX (container);
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (box);
GList *child;
for (child = priv->children; child != NULL; child = child->next)
(* callback) (child->data, callback_data);
if (include_internals)
{
(* callback) (priv->scrolled_window, callback_data);
for (child = priv->widgets_to_remove; child != NULL; child = child->next)
(* callback) (child->data, callback_data);
}
}
static void
clear_animation_state (GtkHidingBox *self)
{
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (self);
priv->animation_phase = ANIMATION_PHASE_NONE;
g_list_free (priv->widgets_to_show);
priv->widgets_to_show = NULL;
g_list_free (priv->widgets_to_hide);
priv->widgets_to_hide = NULL;
}
static gboolean
update_children_visibility (GtkHidingBox *box,
GtkAllocation *allocation,
GtkRequestedSize *sizes,
gboolean update,
gint *children_size,
gint *n_visible_children_expanding)
{
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (box);
GtkWidget *child_widget;
GList *child;
GtkRequestedSize *sizes_temp;
gint i;
GList *children;
GList *temp_widgets_to_show = NULL;
gboolean allocate_more_children = TRUE;
gint n_visible_children = 0;
g_list_free (priv->widgets_to_show);
priv->widgets_to_show = NULL;
g_list_free (priv->widgets_to_hide);
priv->widgets_to_hide = NULL;
*n_visible_children_expanding = 0;
*children_size = -priv->spacing;
children = g_list_copy (priv->children);
sizes_temp = g_newa (GtkRequestedSize, g_list_length (priv->children));
if (priv->inverted)
children = g_list_reverse (children);
/* Retrieve desired size for visible children. */
for (i = 0, child = children; child != NULL; i++, child = child->next)
{
child_widget = GTK_WIDGET (child->data);
gtk_widget_get_preferred_width_for_height (child_widget,
allocation->height,
&sizes_temp[i].minimum_size,
&sizes_temp[i].natural_size);
/* Assert the api is working properly */
if (sizes_temp[i].minimum_size < 0)
g_error ("GtkHidingBox child %s minimum width: %d < 0 for height %d",
gtk_widget_get_name (child_widget),
sizes_temp[i].minimum_size, allocation->height);
if (sizes_temp[i].natural_size < sizes_temp[i].minimum_size)
g_error ("GtkHidingBox child %s natural width: %d < minimum %d for height %d",
gtk_widget_get_name (child_widget),
sizes_temp[i].natural_size, sizes_temp[i].minimum_size,
allocation->height);
*children_size += sizes_temp[i].minimum_size + priv->spacing;
sizes_temp[i].data = child_widget;
if (!allocate_more_children || *children_size > allocation->width)
{
allocate_more_children = FALSE;
if (gtk_revealer_get_child_revealed (GTK_REVEALER (gtk_widget_get_parent (child_widget))))
priv->widgets_to_hide = g_list_append (priv->widgets_to_hide, child_widget);
continue;
}
if (gtk_widget_get_hexpand (child_widget))
(n_visible_children_expanding)++;
(n_visible_children)++;
if (!g_list_find (priv->widgets_to_remove, child_widget))
priv->widgets_to_show = g_list_append (priv->widgets_to_show, child_widget);
}
for (i = 0; i < n_visible_children; i++)
{
if (priv->inverted)
{
sizes[n_visible_children - i - 1].minimum_size = sizes_temp[i].minimum_size;
sizes[n_visible_children - i - 1].natural_size = sizes_temp[i].natural_size;
}
else
{
sizes[i].minimum_size = sizes_temp[i].minimum_size;
sizes[i].natural_size = sizes_temp[i].natural_size;
}
}
g_list_free (children);
}
static gboolean
needs_update (GtkHidingBox *box,
GtkAllocation *allocation)
{
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (box);
GtkWidget *child_widget;
GList *child;
GtkRequestedSize *sizes_temp;
gint i;
GList *children;
GList *widget_shown;
GList *widgets_to_show = NULL;
gboolean needs_update = FALSE;
gboolean allocate_more_children = TRUE;
gint children_size = -priv->spacing;
if (priv->needs_update)
return TRUE;
if (allocation->width != priv->current_width ||
allocation->height != priv->current_height)
return TRUE;
children = g_list_copy (priv->children);
sizes_temp = g_newa (GtkRequestedSize, g_list_length (priv->children));
if (priv->inverted)
children = g_list_reverse (children);
widget_shown = priv->widgets_shown;
/* Retrieve desired size for visible children. */
for (i = 0, child = children; child != NULL; i++, child = child->next)
{
child_widget = GTK_WIDGET (child->data);
if (!gtk_widget_get_visible (child_widget) || !allocate_more_children)
{
needs_update = child->data != widget_shown->data;
widgets_to_show = g_list_prepend (widgets_to_show, child->data);
widget_shown = widget_shown->next;
if (needs_update)
{
break;
}
continue;
}
else
{
needs_update = child->data == widget_shown->data;
if (needs_update)
{
break;
}
}
gtk_widget_get_preferred_width_for_height (child_widget,
allocation->height,
&sizes_temp[i].minimum_size,
&sizes_temp[i].natural_size);
/* Assert the api is working properly */
if (sizes_temp[i].minimum_size < 0)
g_error ("GtkHidingBox child %s minimum width: %d < 0 for height %d",
gtk_widget_get_name (child_widget),
sizes_temp[i].minimum_size, allocation->height);
if (sizes_temp[i].natural_size < sizes_temp[i].minimum_size)
g_error ("GtkHidingBox child %s natural width: %d < minimum %d for height %d",
gtk_widget_get_name (child_widget),
sizes_temp[i].natural_size, sizes_temp[i].minimum_size,
allocation->height);
children_size += sizes_temp[i].minimum_size + priv->spacing;
sizes_temp[i].data = child_widget;
if (children_size > allocation->width)
{
allocate_more_children = FALSE;
}
}
needs_update = needs_update || widget_shown != NULL;
g_list_free (children);
return needs_update;
}
static void
opacity_on (GObject *widget,
GParamSpec *pspec,
gpointer user_data)
{
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (GTK_HIDING_BOX (user_data));
g_print ("############opacity on!!!!!\n");
g_signal_handlers_disconnect_by_func (widget, opacity_on, user_data);
priv->widgets_to_show = g_list_remove (priv->widgets_to_show,
gtk_bin_get_child (GTK_BIN (widget)));
}
static void
opacity_off (GObject *widget,
GParamSpec *pspec,
gpointer user_data)
{
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (GTK_HIDING_BOX (user_data));
g_print ("############opacity off!!!!!\n");
g_signal_handlers_disconnect_by_func (widget, opacity_off, user_data);
priv->widgets_to_hide = g_list_remove (priv->widgets_to_hide,
gtk_bin_get_child (GTK_BIN (widget)));
}
static void
idle_update_revealers (GtkHidingBox *box)
{
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (box);
GList *l;
for (l = priv->widgets_to_hide; l != NULL; l = l->next)
{
GtkRevealer *revealer;
g_print ("update revealer hide %s\n", gtk_button_get_label (GTK_BUTTON (l->data)));
revealer = GTK_REVEALER (gtk_widget_get_parent (l->data));
if (gtk_revealer_get_reveal_child (revealer))
{
GtkStyleContext *style_context;
style_context = gtk_widget_get_style_context (GTK_WIDGET (revealer));
gtk_style_context_remove_class (style_context, "pathbar-initial-opacity");
gtk_style_context_remove_class (style_context, "pathbar-opacity-on");
gtk_style_context_add_class (style_context, "pathbar-opacity-off");
g_signal_connect (revealer, "notify::child-revealed", (GCallback) opacity_off, box);
gtk_revealer_set_reveal_child (revealer, FALSE);
}
}
for (l = priv->widgets_to_remove; l != NULL; l = l->next)
{
GtkRevealer *revealer;
g_print ("update revealer remove %s\n", gtk_button_get_label (GTK_BUTTON (l->data)));
revealer = GTK_REVEALER (gtk_widget_get_parent (l->data));
if (gtk_revealer_get_child_revealed (revealer))
{
GtkStyleContext *style_context;
style_context = gtk_widget_get_style_context (GTK_WIDGET (revealer));
gtk_style_context_remove_class (style_context, "pathbar-initial-opacity");
gtk_style_context_remove_class (style_context, "pathbar-opacity-on");
gtk_style_context_add_class (style_context, "pathbar-opacity-off");
g_signal_connect (revealer, "notify::child-revealed",
(GCallback) unrevealed_really_remove_child, box);
gtk_revealer_set_reveal_child (revealer, FALSE);
}
else
{
g_print ("widget to remove NOT revealed %p\n", l->data);
really_remove_child (box, l->data);
}
}
if (priv->widgets_to_remove || priv->widgets_to_hide)
return;
for (l = priv->widgets_to_show; l != NULL; l = l->next)
{
GtkRevealer *revealer;
revealer = GTK_REVEALER (gtk_widget_get_parent (l->data));
if (!gtk_revealer_get_reveal_child (revealer))
{
GtkStyleContext *style_context;
style_context = gtk_widget_get_style_context (GTK_WIDGET (revealer));
gtk_style_context_remove_class (style_context, "pathbar-opacity-off");
gtk_style_context_remove_class (style_context, "pathbar-initial-opacity");
gtk_style_context_add_class (style_context, "pathbar-opacity-on");
gtk_revealer_set_reveal_child (revealer, TRUE);
g_signal_connect (revealer, "notify::child-revealed", (GCallback) opacity_on, box);
}
}
}
static void
gtk_hiding_box_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GtkHidingBox *box = GTK_HIDING_BOX (widget);
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (box);
GtkAllocation child_allocation;
GtkRequestedSize *sizes;
gint n_visible_children_expanding = 0;
gint children_size = 0;
gtk_widget_set_allocation (widget, allocation);
sizes = g_newa (GtkRequestedSize, g_list_length (priv->children));
update_children_visibility (box, allocation, sizes, FALSE, &children_size,
&n_visible_children_expanding);
idle_update_revealers (box);
child_allocation.x = allocation->x;
child_allocation.y = allocation->y;
child_allocation.width = allocation->width;
child_allocation.height = allocation->height;
gtk_widget_size_allocate (priv->scrolled_window, &child_allocation);
_gtk_widget_set_simple_clip (widget, NULL);
}
static void
finish_invert_animation (GtkHidingBox *self)
{
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (self);
priv->invert_animation = FALSE;
}
static void
invert_animation_on_tick (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data)
{
GtkHidingBox *self = GTK_HIDING_BOX (user_data);
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (self);
guint64 elapsed;
gfloat progress;
gdouble adjustment_value;
if (!priv->initial_time)
priv->initial_time = gdk_frame_clock_get_frame_time (frame_clock);
elapsed = gdk_frame_clock_get_frame_time (frame_clock) - priv->initial_time;
progress = elapsed / INVERT_ANIMATION_TIME;
if (progress >= 1)
{
finish_invert_animation (self);
return;
}
if (priv->inverted)
adjustment_value = 1 / (progress * (gtk_adjustment_get_lower (priv->hadjustment) - gtk_adjustment_get_upper (priv->hadjustment)));
else
adjustment_value = progress * (gtk_adjustment_get_lower (priv->hadjustment) - gtk_adjustment_get_upper (priv->hadjustment));
gtk_adjustment_set_value (priv->hadjustment, adjustment_value);
}
static void
start_invert_animation (GtkHidingBox *self)
{
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (self);
GList *child;
priv->invert_animation = TRUE;
for (child = priv->children; child != NULL; child = child->next)
{
GtkWidget *revealer;
revealer = gtk_widget_get_parent (GTK_WIDGET (child->data));
gtk_revealer_set_transition_duration (GTK_REVEALER (revealer), 0);
gtk_revealer_set_reveal_child (GTK_REVEALER (revealer), TRUE);
}
priv->tick_id = gtk_widget_add_tick_callback (priv->scrolled_window,
(GtkTickCallback) invert_animation_on_tick,
self, NULL);
}
static void
hadjustment_on_changed (GtkAdjustment *hadjustment,
gpointer user_data)
{
GtkHidingBox *box = GTK_HIDING_BOX (user_data);
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (box);
if (priv->invert_animation)
return;
if (priv->inverted)
gtk_adjustment_set_value (hadjustment, gtk_adjustment_get_upper (hadjustment));
else
gtk_adjustment_set_value (hadjustment, gtk_adjustment_get_lower (hadjustment));
}
static void
gtk_hiding_box_get_preferred_width (GtkWidget *widget,
gint *minimum_width,
gint *natural_width)
{
GtkHidingBox *box = GTK_HIDING_BOX (widget);
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (box);
gint child_minimum_width;
gint child_natural_width;
GList *child;
gint n_visible_children;
gboolean have_min = FALSE;
GList *children;
*minimum_width = 0;
*natural_width = 0;
children = g_list_copy (priv->children);
if (priv->inverted)
children = g_list_reverse (children);
n_visible_children = 0;
for (child = children; child != NULL; child = child->next)
{
if (!gtk_widget_is_visible (child->data))
continue;
++n_visible_children;
gtk_widget_get_preferred_width (child->data, &child_minimum_width, &child_natural_width);
/* Minimum is a minimum of the first visible child */
if (!have_min)
{
*minimum_width = child_minimum_width;
have_min = TRUE;
}
/* Natural is a sum of all visible children */
*natural_width += child_natural_width;
}
/* Natural must also include the spacing */
if (priv->spacing && n_visible_children > 1)
*natural_width += priv->spacing * (n_visible_children - 1);
g_list_free (children);
}
static void
gtk_hiding_box_get_preferred_height (GtkWidget *widget,
gint *minimum_height,
gint *natural_height)
{
GtkHidingBox *box = GTK_HIDING_BOX (widget);
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (box);
gint child_minimum_height;
gint child_natural_height;
GList *child;
*minimum_height = 0;
*natural_height = 0;
for (child = priv->children; child != NULL; child = child->next)
{
if (!gtk_widget_is_visible (child->data))
continue;
gtk_widget_get_preferred_height (child->data, &child_minimum_height, &child_natural_height);
*minimum_height = MAX (*minimum_height, child_minimum_height);
*natural_height = MAX (*natural_height, child_natural_height);
}
}
static GtkSizeRequestMode
gtk_hiding_box_get_request_mode (GtkWidget *self)
{
return GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
}
static void
on_what (gpointer data,
GObject *where_the_object_was)
{
G_BREAKPOINT ();
}
static void
gtk_hiding_box_init (GtkHidingBox *box)
{
GtkHidingBoxPrivate *priv = gtk_hiding_box_get_instance_private (box);
GtkAdjustment *hadjustment;
GtkWidget *hscrollbar;
gtk_widget_set_has_window (GTK_WIDGET (box), FALSE);
priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
priv->hadjustment = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->scrolled_window));
g_signal_connect (priv->hadjustment, "changed", (GCallback) hadjustment_on_changed, box);
hscrollbar = gtk_scrolled_window_get_hscrollbar (GTK_SCROLLED_WINDOW (priv->scrolled_window));
gtk_widget_hide (hscrollbar);
priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
g_object_weak_ref (G_OBJECT (priv->box), on_what, NULL);
gtk_container_add (GTK_CONTAINER (priv->scrolled_window), priv->box);
gtk_widget_set_parent (priv->scrolled_window, GTK_WIDGET (box));
priv->invert_animation = FALSE;
priv->spacing = 0;
priv->inverted = FALSE;
priv->widgets_to_hide = NULL;
priv->widgets_to_show = NULL;
priv->widgets_to_remove = NULL;
priv->widgets_shown = NULL;
priv->animation_phase = ANIMATION_PHASE_NONE;
gtk_widget_show_all (priv->scrolled_window);
}
static void
gtk_hiding_box_class_init (GtkHidingBoxClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
object_class->set_property = gtk_hiding_box_set_property;
object_class->get_property = gtk_hiding_box_get_property;
widget_class->size_allocate = gtk_hiding_box_size_allocate;
widget_class->get_preferred_width = gtk_hiding_box_get_preferred_width;
widget_class->get_preferred_height = gtk_hiding_box_get_preferred_height;
widget_class->get_request_mode = gtk_hiding_box_get_request_mode;
container_class->add = gtk_hiding_box_add;
container_class->remove = gtk_hiding_box_remove;
container_class->forall = gtk_hiding_box_forall;
hiding_box_properties[PROP_SPACING] =
g_param_spec_int ("spacing",
_("Spacing"),
_("The amount of space between children"),
0, G_MAXINT, 0,
G_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
hiding_box_properties[PROP_INVERTED] =
g_param_spec_int ("inverted",
_("Direction of hiding children inverted"),
P_("If false the container will start hiding widgets from the end when there is not enough space, and the oposite in case inverted is true."),
0, G_MAXINT, 0,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, LAST_PROP, hiding_box_properties);
}
/**
* gtk_hiding_box_new:
*
* Creates a new #GtkHidingBox.
*
* Returns: a new #GtkHidingBox.
**/
GtkWidget *
gtk_hiding_box_new (void)
{
return g_object_new (GTK_TYPE_HIDING_BOX, NULL);
}
/**
* gtk_hiding_box_set_spacing:
* @box: a #GtkHidingBox
* @spacing: the number of pixels to put between children
*
* Sets the #GtkHidingBox:spacing property of @box, which is the
* number of pixels to place between children of @box.
*/
void
gtk_hiding_box_set_spacing (GtkHidingBox *box,
gint spacing)
{
GtkHidingBoxPrivate *priv ;
g_return_if_fail (GTK_IS_HIDING_BOX (box));
priv = gtk_hiding_box_get_instance_private (box);
if (priv->spacing != spacing)
{
priv->spacing = spacing;
g_object_notify (G_OBJECT (box), "spacing");
gtk_widget_queue_resize (GTK_WIDGET (box));
}
}
/**
* gtk_hiding_box_get_spacing:
* @box: a #GtkHidingBox
*
* Gets the value set by gtk_hiding_box_set_spacing().
*
* Returns: spacing between children
**/
gint
gtk_hiding_box_get_spacing (GtkHidingBox *box)
{
GtkHidingBoxPrivate *priv ;
g_return_val_if_fail (GTK_IS_HIDING_BOX (box), 0);
priv = gtk_hiding_box_get_instance_private (box);
return priv->spacing;
}
void
gtk_hiding_box_set_inverted (GtkHidingBox *box,
gboolean inverted)
{
GtkHidingBoxPrivate *priv ;
g_return_if_fail (GTK_IS_HIDING_BOX (box));
priv = gtk_hiding_box_get_instance_private (box);
if (priv->inverted != inverted)
{
priv->inverted = inverted != FALSE;
g_object_notify (G_OBJECT (box), "inverted");
gtk_widget_queue_resize (GTK_WIDGET (box));
}
}
gboolean
gtk_hiding_box_get_inverted (GtkHidingBox *box)
{
GtkHidingBoxPrivate *priv ;
g_return_val_if_fail (GTK_IS_HIDING_BOX (box), 0);
priv = gtk_hiding_box_get_instance_private (box);
return priv->inverted;
}
GList *
gtk_hiding_box_get_overflow_children (GtkHidingBox *box)
{
GtkHidingBoxPrivate *priv ;
GList *result = NULL;
GList *l;
g_return_val_if_fail (GTK_IS_HIDING_BOX (box), 0);
priv = gtk_hiding_box_get_instance_private (box);
for (l = priv->children; l != NULL; l = l->next)
if (gtk_widget_is_visible (l->data) && !gtk_widget_get_child_visible (l->data))
result = g_list_append (result, l->data);
return result;
}

77
gtk/gtkhidingbox.h Normal file
View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2015 Rafał Lużyński <digitalfreak@lingonborough.com>
*
* Licensed under the GNU General Public License Version 2
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __GTK_HIDING_BOX_H__
#define __GTK_HIDING_BOX_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkcontainer.h>
G_BEGIN_DECLS
#define GTK_TYPE_HIDING_BOX (gtk_hiding_box_get_type())
#define GTK_HIDING_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_HIDING_BOX, GtkHidingBox))
#define GTK_HIDING_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_HIDING_BOX, GtkHidingBoxClass))
#define GTK_IS_HIDING_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_HIDING_BOX))
#define GTK_IS_HIDING_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_HIDING_BOX)
#define GTK_HIDING_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_HIDING_BOX, GtkHidingBoxClass))
typedef struct _GtkHidingBox GtkHidingBox;
typedef struct _GtkHidingBoxClass GtkHidingBoxClass;
typedef struct _GtkHidingBoxPrivate GtkHidingBoxPrivate;
struct _GtkHidingBoxClass
{
GtkContainerClass parent;
/* Padding for future expansion */
gpointer reserved[10];
};
struct _GtkHidingBox
{
GtkContainer parent_instance;
};
GDK_AVAILABLE_IN_3_20
GType gtk_hiding_box_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_20
GtkWidget *gtk_hiding_box_new (void);
GDK_AVAILABLE_IN_3_20
void gtk_hiding_box_set_spacing (GtkHidingBox *box,
gint spacing);
GDK_AVAILABLE_IN_3_20
gint gtk_hiding_box_get_spacing (GtkHidingBox *box);
GDK_AVAILABLE_IN_3_20
void gtk_hiding_box_set_inverted (GtkHidingBox *box,
gboolean inverted);
GDK_AVAILABLE_IN_3_20
gboolean gtk_hiding_box_get_inverted (GtkHidingBox *box);
GDK_AVAILABLE_IN_3_20
GList *gtk_hiding_box_get_overflow_children (GtkHidingBox *box);
G_END_DECLS
#endif /* GTK_HIDING_BOX_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -1,67 +1,94 @@
/* gtkpathbar.h
* Copyright (C) 2004 Red Hat, Inc., Jonathan Blandford <jrb@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
* Copyright (C) 2015 Red Hat
*
* This library is distributed in the hope that it will be useful,
* 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 2 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
* Library General Public License for more details.
* 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 Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Carlos Soriano <csoriano@gnome.org>
*/
#ifndef __GTK_PATH_BAR_H__
#define __GTK_PATH_BAR_H__
#include "gtkcontainer.h"
#include "gtkfilesystem.h"
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkbin.h>
G_BEGIN_DECLS
typedef struct _GtkPathBar GtkPathBar;
typedef struct _GtkPathBarClass GtkPathBarClass;
#define GTK_TYPE_PATH_BAR (gtk_path_bar_get_type())
#define GTK_PATH_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PATH_BAR, GtkPathBar))
#define GTK_PATH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PATH_BAR, GtkPathBarClass))
#define GTK_IS_PATH_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PATH_BAR))
#define GTK_IS_PATH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PATH_BAR)
#define GTK_PATH_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PATH_BAR, GtkPathBarClass))
typedef struct _GtkPathBar GtkPathBar;
typedef struct _GtkPathBarClass GtkPathBarClass;
typedef struct _GtkPathBarPrivate GtkPathBarPrivate;
#define GTK_TYPE_PATH_BAR (gtk_path_bar_get_type ())
#define GTK_PATH_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PATH_BAR, GtkPathBar))
#define GTK_PATH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PATH_BAR, GtkPathBarClass))
#define GTK_IS_PATH_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PATH_BAR))
#define GTK_IS_PATH_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PATH_BAR))
#define GTK_PATH_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PATH_BAR, GtkPathBarClass))
struct _GtkPathBar
{
GtkContainer parent;
GtkPathBarPrivate *priv;
};
struct _GtkPathBarClass
{
GtkContainerClass parent_class;
GtkBinClass parent;
void (* path_clicked) (GtkPathBar *path_bar,
GFile *file,
GFile *child_file,
gboolean child_is_hidden);
/*< public >*/
void (* populate_popup) (GtkPathBar *path_bar,
const gchar *selected_path);
/*< private >*/
/* Padding for future expansion */
gpointer reserved[10];
};
GDK_AVAILABLE_IN_ALL
GType gtk_path_bar_get_type (void) G_GNUC_CONST;
void _gtk_path_bar_set_file_system (GtkPathBar *path_bar,
GtkFileSystem *file_system);
void _gtk_path_bar_set_file (GtkPathBar *path_bar,
GFile *file,
gboolean keep_trail);
void _gtk_path_bar_up (GtkPathBar *path_bar);
void _gtk_path_bar_down (GtkPathBar *path_bar);
struct _GtkPathBar
{
GtkBin parent_instance;
};
GDK_AVAILABLE_IN_3_20
GType gtk_path_bar_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_20
GtkWidget* gtk_path_bar_new (void);
GDK_AVAILABLE_IN_3_20
void gtk_path_bar_set_path (GtkPathBar *path_bar,
const gchar *path);
GDK_AVAILABLE_IN_3_20
const gchar* gtk_path_bar_get_path (GtkPathBar *path_bar);
GDK_AVAILABLE_IN_3_20
void gtk_path_bar_set_path_extended (GtkPathBar *self,
const gchar *path,
const gchar *root_path,
const gchar *root_label,
GIcon *root_icon);
GDK_AVAILABLE_IN_3_20
void gtk_path_bar_set_selected_path (GtkPathBar *path_bar,
const gchar *path);
GDK_AVAILABLE_IN_3_20
const gchar* gtk_path_bar_get_selected_path (GtkPathBar *path_bar);
GDK_AVAILABLE_IN_3_20
void gtk_path_bar_set_inverted (GtkPathBar *path_bar,
gboolean inverted);
GDK_AVAILABLE_IN_3_20
gboolean gtk_path_bar_get_inverted (GtkPathBar *path_bar);
G_END_DECLS
#endif /* __GTK_PATH_BAR_H__ */

260
gtk/gtkpathbarcontainer.c Normal file
View File

@@ -0,0 +1,260 @@
/* gtkpathbarcontainer.c
*
* Copyright (C) 2015 Red Hat
*
* 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 2 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/>.
*
* Authors: Carlos Soriano <csoriano@gnome.org>
*/
#include "config.h"
#include "gtkpathbarcontainerprivate.h"
#include "gtkbuildable.h"
#include "gtkwidget.h"
#include "gtkmenubutton.h"
#include "gtksizerequest.h"
#include "gtkhidingbox.h"
#include "gtkwidgetprivate.h"
#include "glib-object.h"
struct _GtkPathBarContainerPrivate
{
GtkWidget *overflow_button;
GtkWidget *path_box;
};
static GtkBuildableIface *parent_buildable_iface;
static GObject *
buildable_get_internal_child (GtkBuildable *buildable,
GtkBuilder *builder,
const gchar *childname)
{
if (g_strcmp0 (childname, "overflow_button") == 0)
return G_OBJECT (gtk_path_bar_container_get_overflow_button (GTK_PATH_BAR_CONTAINER (buildable)));
if (g_strcmp0 (childname, "path_box") == 0)
return G_OBJECT (gtk_path_bar_container_get_path_box (GTK_PATH_BAR_CONTAINER (buildable)));
return parent_buildable_iface->get_internal_child (buildable, builder, childname);
}
static void
buildable_init (GtkBuildableIface *iface)
{
parent_buildable_iface = g_type_interface_peek_parent (iface);
iface->get_internal_child = buildable_get_internal_child;
}
G_DEFINE_TYPE_WITH_CODE (GtkPathBarContainer, gtk_path_bar_container, GTK_TYPE_CONTAINER,
G_ADD_PRIVATE (GtkPathBarContainer)
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_init))
static void
container_forall (GtkContainer *container,
gboolean include_internals,
GtkCallback callback,
gpointer callback_data)
{
GtkPathBarContainerPrivate *priv = gtk_path_bar_container_get_instance_private (GTK_PATH_BAR_CONTAINER (container));
if (include_internals)
{
(* callback) (priv->overflow_button, callback_data);
(* callback) (priv->path_box, callback_data);
}
}
static GtkSizeRequestMode
get_request_mode (GtkWidget *self)
{
return GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
}
static void
size_allocate (GtkWidget *self,
GtkAllocation *allocation)
{
GtkPathBarContainerPrivate *priv = gtk_path_bar_container_get_instance_private (GTK_PATH_BAR_CONTAINER (self));
gint path_min_width;
gint path_nat_width;
gint overflow_button_min_width;
GtkAllocation path_container_allocation;
GtkAllocation overflow_button_allocation;
GtkTextDirection direction;
gboolean overflow;
GList *overflow_children;
GList *children;
gtk_widget_set_allocation (self, allocation);
children = gtk_container_get_children (GTK_CONTAINER (priv->path_box));
gtk_widget_set_child_visible (priv->overflow_button, FALSE);
if (g_list_length (children) == 0)
return;
gtk_widget_get_preferred_width (priv->path_box, &path_min_width, &path_nat_width);
/* Try to allocate all children with our allocation so we can request if there
* is some overflow children */
path_container_allocation.x = allocation->x;
path_container_allocation.width = allocation->width;
path_container_allocation.y = allocation->y;
path_container_allocation.height = allocation->height;
gtk_widget_size_allocate (priv->path_box, &path_container_allocation);
gtk_widget_get_preferred_width (priv->overflow_button, &overflow_button_min_width, NULL);
overflow_children = gtk_hiding_box_get_overflow_children (GTK_HIDING_BOX (priv->path_box));
overflow = overflow_children != NULL;
g_list_free (overflow_children);
direction = gtk_widget_get_direction (self);
path_container_allocation.x = allocation->x;
path_container_allocation.width = allocation->width;
if (overflow)
{
if (direction == GTK_TEXT_DIR_LTR)
{
path_container_allocation.x = allocation->x + overflow_button_min_width;
path_container_allocation.width = allocation->width - overflow_button_min_width;
overflow_button_allocation.y = allocation->y;
overflow_button_allocation.height = allocation->height;
overflow_button_allocation.width = overflow_button_min_width;
overflow_button_allocation.x = allocation->x;
gtk_widget_set_child_visible (priv->overflow_button, TRUE);
gtk_widget_size_allocate (priv->overflow_button, &overflow_button_allocation);
}
else
{
path_container_allocation.width = allocation->width - overflow_button_min_width;
}
}
path_container_allocation.y = allocation->y;
path_container_allocation.height = allocation->height;
gtk_widget_size_allocate (priv->path_box, &path_container_allocation);
if (overflow && direction == GTK_TEXT_DIR_RTL)
{
overflow_button_allocation.y = allocation->y;
overflow_button_allocation.height = allocation->height;
overflow_button_allocation.width = overflow_button_min_width;
overflow_button_allocation.x = path_container_allocation.x +
path_container_allocation.width;
gtk_widget_set_child_visible (priv->overflow_button, TRUE);
gtk_widget_size_allocate (priv->overflow_button, &overflow_button_allocation);
}
_gtk_widget_set_simple_clip (self, NULL);
g_list_free (children);
}
static void
get_preferred_width (GtkWidget *self,
gint *minimum_width,
gint *natural_width)
{
GtkPathBarContainerPrivate *priv = gtk_path_bar_container_get_instance_private (GTK_PATH_BAR_CONTAINER (self));
gtk_widget_get_preferred_width (priv->path_box, minimum_width, natural_width);
}
static void
get_preferred_height (GtkWidget *self,
gint *minimum_height,
gint *natural_height)
{
GtkPathBarContainerPrivate *priv = gtk_path_bar_container_get_instance_private (GTK_PATH_BAR_CONTAINER (self));
gtk_widget_get_preferred_height (priv->path_box, minimum_height, natural_height);
}
static void
widget_destroy (GtkWidget *object)
{
GtkPathBarContainerPrivate *priv = gtk_path_bar_container_get_instance_private (GTK_PATH_BAR_CONTAINER (object));
if (priv->overflow_button && priv->path_box)
{
gtk_widget_unparent (priv->overflow_button);
gtk_widget_unparent (priv->path_box);
priv->overflow_button = NULL;
priv->path_box = NULL;
}
GTK_WIDGET_CLASS (gtk_path_bar_container_parent_class)->destroy (object);
}
static void
gtk_path_bar_container_class_init (GtkPathBarContainerClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
widget_class->get_request_mode = get_request_mode;
widget_class->get_preferred_width = get_preferred_width;
widget_class->get_preferred_height = get_preferred_height;
widget_class->size_allocate = size_allocate;
widget_class->destroy = widget_destroy;
// Neccesary to draw and realize children
container_class->forall = container_forall;
}
static void
gtk_path_bar_container_init (GtkPathBarContainer *self)
{
GtkPathBarContainerPrivate *priv = gtk_path_bar_container_get_instance_private (self);
gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
priv->overflow_button = gtk_menu_button_new ();
priv->path_box = gtk_hiding_box_new ();
gtk_widget_set_parent (priv->overflow_button, GTK_WIDGET (self));
gtk_widget_set_parent (priv->path_box, GTK_WIDGET (self));
}
GtkWidget *
gtk_path_bar_container_new (void)
{
return g_object_new (GTK_TYPE_PATH_BAR_CONTAINER, NULL);
}
GtkWidget *
gtk_path_bar_container_get_overflow_button (GtkPathBarContainer *self)
{
GtkPathBarContainerPrivate *priv;
g_return_val_if_fail (GTK_IS_PATH_BAR_CONTAINER (self), NULL);
priv = gtk_path_bar_container_get_instance_private (self);
return priv->overflow_button;
}
GtkWidget *
gtk_path_bar_container_get_path_box (GtkPathBarContainer *self)
{
GtkPathBarContainerPrivate *priv;
g_return_val_if_fail (GTK_IS_PATH_BAR_CONTAINER (self), NULL);
priv = gtk_path_bar_container_get_instance_private (self);
return priv->path_box;
}

View File

@@ -0,0 +1,66 @@
/* gtkpathbarcontainerprivate.h
*
* Copyright (C) 2015 Red Hat
*
* 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 2 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/>.
*
* Authors: Carlos Soriano <csoriano@gnome.org>
*/
#ifndef __GTK_PATH_BAR_CONTAINER_PRIVATE_H__
#define __GTK_PATH_BAR_CONTAINER_PRIVATE_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtkcontainer.h>
G_BEGIN_DECLS
#define GTK_TYPE_PATH_BAR_CONTAINER (gtk_path_bar_container_get_type())
#define GTK_PATH_BAR_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PATH_BAR_CONTAINER, GtkPathBarContainer))
#define GTK_PATH_BAR_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PATH_BAR_CONTAINER, GtkPathBarContainerClass))
#define GTK_IS_PATH_BAR_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PATH_BAR_CONTAINER))
#define GTK_IS_PATH_BAR_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PATH_BAR_CONTAINER)
#define GTK_PATH_BAR_CONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PATH_BAR_CONTAINER, GtkPathBarContainerClass))
typedef struct _GtkPathBarContainer GtkPathBarContainer;
typedef struct _GtkPathBarContainerClass GtkPathBarContainerClass;
typedef struct _GtkPathBarContainerPrivate GtkPathBarContainerPrivate;
struct _GtkPathBarContainerClass
{
GtkContainerClass parent;
/* Padding for future expansion */
gpointer reserved[10];
};
struct _GtkPathBarContainer
{
GtkContainer parent_instance;
};
GType gtk_path_bar_container_get_type (void) G_GNUC_CONST;
GtkWidget *gtk_path_bar_container_new (void);
GtkWidget *gtk_path_bar_container_get_path_box (GtkPathBarContainer *path_bar_container);
GtkWidget *gtk_path_bar_container_get_overflow_button (GtkPathBarContainer *path_bar_container);
G_END_DECLS
#endif /* GTK_PATH_BAR_CONTAINER_PRIVATE_H_ */

View File

@@ -456,6 +456,7 @@ gtk_revealer_real_size_allocate (GtkWidget *widget,
g_return_if_fail (allocation != NULL);
g_print ("revealer allocation %d %d %d %d\n", allocation->height, allocation->width, allocation->x, allocation->y);
gtk_widget_set_allocation (widget, allocation);
gtk_revealer_get_child_allocation (revealer, allocation, &child_allocation);

View File

@@ -446,6 +446,7 @@ gtk_public_h_sources = \
gtkpagesetup.h \
gtkpaned.h \
gtkpapersize.h \
gtkpathbar.h \
gtkplug.h \
gtkprintcontext.h \
gtkprintoperation.h \

View File

@@ -1594,31 +1594,45 @@ headerbar {
/************
* Pathbars *
************/
.path-bar button {
&.text-button, &.image-button, & {
padding-left: 4px;
padding-right: 4px;
}
&.text-button.image-button label {
padding-left: 0;
padding-right: 0;
}
path-bar button.flat, .path-bar-overflow-popover button.flat {
background-image: none;
border-radius: 0px;
border-color: transparent;
border-width: 2px 0px 2px 0px;
box-shadow: 0px 0px 0px;
margin: 0px;
opacity: 0.55;
padding: 3px 8px 4px;
background-color: transparent;
&.text-button.image-button, & {
label:last-child { padding-right: 8px; }
label:first-child { padding-left: 8px; }
}
&:checked {
opacity: 1;
}
image {
padding-left: 4px;
padding-right: 4px;
}
&:hover {
border-bottom-color: mix($selected_bg_color, $selected_fg_color, 75%);
}
&.slider-button {
padding-left: 0;
padding-right: 0;
}
&:backdrop, &:backdrop:checked {
background-color: transparent;
border-color: transparent;
background-image: none;
}
}
.pathbar-initial-opacity {
opacity: 0;
}
.pathbar-opacity-on {
opacity: 1;
transition-duration: 250ms;
}
.pathbar-opacity-off {
opacity: 0;
transition-duration: 250ms;
}
/**************

View File

@@ -2097,22 +2097,35 @@ window.csd > .titlebar:not(headerbar) {
/************
* Pathbars *
************/
.path-bar button.text-button, .path-bar button.image-button, .path-bar button {
padding-left: 4px;
padding-right: 4px; }
.path-bar button.text-button.image-button label {
padding-left: 0;
padding-right: 0; }
.path-bar button.text-button.image-button label:last-child, .path-bar button label:last-child {
padding-right: 8px; }
.path-bar button.text-button.image-button label:first-child, .path-bar button label:first-child {
padding-left: 8px; }
.path-bar button image {
padding-left: 4px;
padding-right: 4px; }
.path-bar button.slider-button {
padding-left: 0;
padding-right: 0; }
path-bar button.flat, .path-bar-overflow-popover button.flat {
background-image: none;
border-radius: 0px;
border-color: transparent;
border-width: 2px 0px 2px 0px;
box-shadow: 0px 0px 0px;
margin: 0px;
opacity: 0.55;
padding: 3px 8px 4px;
background-color: transparent; }
path-bar button.flat:checked, .path-bar-overflow-popover button.flat:checked {
opacity: 1; }
path-bar button.flat:hover, .path-bar-overflow-popover button.flat:hover {
border-bottom-color: #5986b5; }
path-bar button.flat:backdrop, path-bar button.flat:backdrop:checked, .path-bar-overflow-popover button.flat:backdrop, .path-bar-overflow-popover button.flat:backdrop:checked {
background-color: transparent;
border-color: transparent;
background-image: none; }
.pathbar-initial-opacity {
opacity: 0; }
.pathbar-opacity-on {
opacity: 1;
transition-duration: 250ms; }
.pathbar-opacity-off {
opacity: 0;
transition-duration: 250ms; }
/**************
* Tree Views *

View File

@@ -2104,22 +2104,35 @@ window.csd > .titlebar:not(headerbar) {
/************
* Pathbars *
************/
.path-bar button.text-button, .path-bar button.image-button, .path-bar button {
padding-left: 4px;
padding-right: 4px; }
.path-bar button.text-button.image-button label {
padding-left: 0;
padding-right: 0; }
.path-bar button.text-button.image-button label:last-child, .path-bar button label:last-child {
padding-right: 8px; }
.path-bar button.text-button.image-button label:first-child, .path-bar button label:first-child {
padding-left: 8px; }
.path-bar button image {
padding-left: 4px;
padding-right: 4px; }
.path-bar button.slider-button {
padding-left: 0;
padding-right: 0; }
path-bar button.flat, .path-bar-overflow-popover button.flat {
background-image: none;
border-radius: 0px;
border-color: transparent;
border-width: 2px 0px 2px 0px;
box-shadow: 0px 0px 0px;
margin: 0px;
opacity: 0.55;
padding: 3px 8px 4px;
background-color: transparent; }
path-bar button.flat:checked, .path-bar-overflow-popover button.flat:checked {
opacity: 1; }
path-bar button.flat:hover, .path-bar-overflow-popover button.flat:hover {
border-bottom-color: #77ace3; }
path-bar button.flat:backdrop, path-bar button.flat:backdrop:checked, .path-bar-overflow-popover button.flat:backdrop, .path-bar-overflow-popover button.flat:backdrop:checked {
background-color: transparent;
border-color: transparent;
background-image: none; }
.pathbar-initial-opacity {
opacity: 0; }
.pathbar-opacity-on {
opacity: 1;
transition-duration: 250ms; }
.pathbar-opacity-off {
opacity: 0;
transition-duration: 250ms; }
/**************
* Tree Views *

View File

@@ -56,9 +56,9 @@
<property name="spacing">6</property>
<property name="border-width">6</property>
<child>
<object class="GtkPathBar" id="browse_path_bar">
<object class="GtkFilesPathBar" id="browse_path_bar">
<property name="visible">True</property>
<signal name="path-clicked" handler="path_bar_clicked" after="yes" swapped="no"/>
<signal name="notify::file" handler="on_path_bar_file"/>
</object>
<packing>
<property name="expand">1</property>

View File

@@ -86,6 +86,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
testgtk \
testheaderbar \
testheightforwidth \
testhidingbox \
testiconview \
testiconview-keynav \
testicontheme \
@@ -108,6 +109,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
testorientable \
testoverlay \
testoverlaystyleclass \
testpathbar \
testprint \
testrecentchooser \
testrecentchoosermenu \
@@ -291,6 +293,8 @@ testanimation_DEPENDENCIES = $(TEST_DEPS)
testpixbuf_save_DEPENDENCIES = $(TEST_DEPS)
testpixbuf_color_DEPENDENCIES = $(TEST_DEPS)
testpixbuf_scale_DEPENDENCIES = $(TEST_DEPS)
testpathbar_DEPENDENCIES = $(TEST_DEPS)
testhidingbox_DEPENDENCIES = $(TEST_DEPS)
testgmenu_DEPENDENCIES = $(TEST_DEPS)
testlogout_DEPENDENCIES = $(TEST_DEPS)
teststack_DEPENDENCIES = $(TEST_DEPS)
@@ -391,6 +395,12 @@ testtoolbar_SOURCES = \
testmenubutton_SOURCES = \
testmenubutton.c
testpathbar_SOURCES = \
testpathbar.c
testhidingbox_SOURCES = \
testhidingbox.c
testprint_SOURCES = \
testprint.c \
testprintfileoperation.h \

152
tests/testhidingbox.c Normal file
View File

@@ -0,0 +1,152 @@
#include "config.h"
#include "glib.h"
#include <gtk/gtk.h>
#define N_BUTTONS 10
static GtkWidget *hiding_box;
static char *lorem_ipsum = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
static char*
get_lorem_ipsum ()
{
static char **lorem_ipsum_split;
static int n_lorem_ipsum_words;
if (!lorem_ipsum_split)
{
lorem_ipsum_split = g_strsplit (lorem_ipsum, " ", -1);
n_lorem_ipsum_words = g_strv_length (lorem_ipsum_split);
}
return lorem_ipsum_split [g_random_int_range (0, n_lorem_ipsum_words)];
}
static void
on_path_selected (GtkPathBar *path_bar,
GParamSpec *pspec,
gpointer *user_data)
{
g_print ("Path selected: %s\n", gtk_path_bar_get_selected_path (path_bar));
}
static void
on_button_clicked (GtkWidget *button,
gpointer user_data)
{
g_print ("button clicked\n");
gtk_container_remove (GTK_CONTAINER (user_data), button);
}
static void
on_reset_button_clicked (GtkButton *reset_button)
{
GtkWidget *button;
gtk_container_foreach (GTK_CONTAINER (hiding_box), (GtkCallback) gtk_widget_destroy, NULL);
for (int i = 0; i < N_BUTTONS; i++)
{
button = gtk_button_new_with_label (get_lorem_ipsum ());
g_signal_connect (button, "clicked", (GCallback) on_button_clicked, hiding_box);
gtk_container_add (GTK_CONTAINER (hiding_box), button);
}
gtk_widget_show_all (hiding_box);
}
static void
on_add_button (gint line)
{
GtkWidget *button;
button = gtk_button_new_with_label (get_lorem_ipsum ());
gtk_widget_show (button);
g_signal_connect (button, "clicked", (GCallback) on_button_clicked, hiding_box);
gtk_container_add (GTK_CONTAINER (hiding_box), button);
}
static void
on_remove_button (gint line)
{
GList *children;
GList *last;
children = gtk_container_get_children (hiding_box);
last = g_list_last (children);
if (last)
gtk_container_remove (hiding_box, GTK_WIDGET (last->data));
}
static void
on_invert_button (gint line)
{
gtk_hiding_box_set_inverted (GTK_HIDING_BOX (hiding_box),
!gtk_hiding_box_get_inverted (GTK_HIDING_BOX (hiding_box)));
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *reset_button;
GtkWidget *add_button;
GtkWidget *remove_button;
GtkWidget *invert_button;
GtkWidget *label;
GFile *file = NULL;
GIcon *icon;
gtk_init (&argc, &argv);
window = g_object_connect (g_object_new (gtk_window_get_type (),
"type", GTK_WINDOW_TOPLEVEL,
"title", "Test path bar",
"resizable", TRUE,
"default-height", 200,
NULL),
"signal::destroy", gtk_main_quit, NULL,
NULL);
grid = gtk_grid_new ();
g_type_ensure (GTK_TYPE_HIDING_BOX);
label = gtk_label_new ("Generic GtkPathBar tests");
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 2, 1);
/* ----------------------------------------------------------------------- */
hiding_box = gtk_hiding_box_new ();
gtk_grid_attach (GTK_GRID (grid), hiding_box, 0, 1, 1, 1);
gtk_widget_show_all (hiding_box);
/* Add/Remove buttons */
add_button = gtk_button_new_with_label ("Add");
gtk_widget_set_halign (add_button, GTK_ALIGN_END);
remove_button = gtk_button_new_with_label ("Remove");
gtk_widget_set_halign (remove_button, GTK_ALIGN_END);
gtk_grid_attach_next_to (GTK_GRID (grid), add_button, hiding_box, GTK_POS_RIGHT, 1, 1);
g_signal_connect_swapped (add_button, "clicked", (GCallback) on_add_button, GINT_TO_POINTER (0));
gtk_grid_attach_next_to (GTK_GRID (grid), remove_button, add_button, GTK_POS_RIGHT, 1, 1);
g_signal_connect_swapped (remove_button, "clicked", (GCallback) on_remove_button, GINT_TO_POINTER (0));
gtk_widget_show (add_button);
gtk_widget_show (remove_button);
/* Inverted button */
invert_button = gtk_button_new_with_label ("Invert");
gtk_widget_set_halign (invert_button, GTK_ALIGN_END);
gtk_grid_attach_next_to (GTK_GRID (grid), invert_button, remove_button, GTK_POS_RIGHT, 1, 1);
g_signal_connect_swapped (invert_button, "clicked", (GCallback) on_invert_button, GINT_TO_POINTER (0));
/* Reset button */
reset_button = gtk_button_new_with_label ("Reset State");
gtk_widget_set_hexpand (reset_button, TRUE);
g_signal_connect (GTK_BUTTON (reset_button), "clicked",
G_CALLBACK (on_reset_button_clicked), window);
gtk_grid_attach (GTK_GRID (grid), reset_button, 0, 11, 2, 1);
gtk_container_add (GTK_CONTAINER (window), grid);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}

330
tests/testpathbar.c Normal file
View File

@@ -0,0 +1,330 @@
#include "config.h"
#include "glib.h"
#include <gtk/gtk.h>
static GActionGroup *action_group;
static GtkWidget *path_bar;
static GtkWidget *path_bar_inverted;
static GtkWidget *path_bar_slash;
static GtkWidget *path_bar_custom_root_label;
static GtkWidget *path_bar_custom_root_icon;
static GtkWidget *files_path_bar_random;
static GtkWidget *files_path_bar_recent;
static const gchar* REAL_LOCATION_RANDOM = "file:///boot/efi/EFI/BOOT";
static const gchar* REAL_LOCATION_RECENT = "recent:///";
static const gchar* ORIGINAL_PATH = "/test/test 2/test 3/asda lkasdl/pppppppppppppppp/ alskd";
static const gchar* ROOT_PATH = "/test/test 2/test 3";
static const gchar* DISPLAY_PATH = "/test/test 2/This Is A Root/asda lkasdl/pppppppppppppppp/ alskd";
static void
action_menu_1 (GSimpleAction *action,
GVariant *variant,
gpointer user_data)
{
g_print ("Menu 1 action\n");
}
static void
action_menu_2 (GSimpleAction *action,
GVariant *variant,
gpointer user_data)
{
g_print ("Menu 2 action\n");
}
static void
action_special (GSimpleAction *action,
GVariant *variant,
gpointer user_data)
{
g_print ("Special action\n");
}
const GActionEntry entries[] = {
{ "menu_1", action_menu_1 },
{ "menu_2", action_menu_2 },
{ "special", action_special },
};
static void
on_populate_popup (GtkPathBar *path_bar,
GtkWidget *container,
const gchar *selected_path)
{
GtkWidget *menu_item;
menu_item = gtk_model_button_new ();
gtk_actionable_set_action_name (GTK_ACTIONABLE (menu_item),
"action_group.menu_1");
g_object_set (menu_item, "text", "Menu 1", NULL);
gtk_container_add (GTK_CONTAINER (container), menu_item);
menu_item = gtk_model_button_new ();
gtk_actionable_set_action_name (GTK_ACTIONABLE (menu_item),
"action_group.menu_2");
g_object_set (menu_item, "text", "Menu 2", NULL);
gtk_container_add (GTK_CONTAINER (container), menu_item);
if (g_strcmp0 (selected_path, "/test/test 2/test 3") == 0)
{
menu_item = gtk_model_button_new ();
gtk_actionable_set_action_name (GTK_ACTIONABLE (menu_item),
"action_group.special");
g_object_set (menu_item, "text", "Special", NULL);
gtk_container_add (GTK_CONTAINER (container), menu_item);
}
gtk_widget_show_all (container);
g_print ("Populate popup\n");
}
static void
on_path_selected (GtkPathBar *path_bar,
GParamSpec *pspec,
gpointer *user_data)
{
g_print ("Path selected: %s\n", gtk_path_bar_get_selected_path (path_bar));
}
static gchar*
get_display_path_from_selected (const gchar *selected_path)
{
gchar **splitted_path;
gchar **display_splitted_path;
gint i;
GString *display_path;
gchar *display_path_gchar;
splitted_path = g_strsplit (selected_path, "/", -1);
display_splitted_path = g_strsplit (DISPLAY_PATH, "/", -1);
display_path = g_string_new ("");
/* Skip the first empty split part */
for (i = 1; i < g_strv_length (splitted_path); i++)
{
g_string_append (display_path, "/");
g_string_append (display_path, display_splitted_path[i]);
}
display_path_gchar = display_path->str;
g_string_free (display_path, FALSE);
g_strfreev (splitted_path);
g_strfreev (display_splitted_path);
return display_path_gchar;
}
static void
on_path_selected_set_path (GtkPathBar *path_bar,
GParamSpec *pspec,
gpointer *user_data)
{
gchar *selected_path;
gchar *new_display_path;
selected_path = g_strdup (gtk_path_bar_get_selected_path (path_bar));
new_display_path = get_display_path_from_selected (selected_path);
g_print ("Path selected: %s, setting path to GtkPathBar and new display path %s\n", selected_path, new_display_path);
if (path_bar == GTK_PATH_BAR (path_bar_custom_root_label))
{
gtk_path_bar_set_path_extended (GTK_PATH_BAR (path_bar_custom_root_label),
selected_path, ROOT_PATH, "This Is A Root", NULL);
}
else if (path_bar == GTK_PATH_BAR (path_bar_custom_root_icon))
{
GIcon *icon;
icon = g_themed_icon_new ("drive-harddisk");
gtk_path_bar_set_path_extended (GTK_PATH_BAR (path_bar_custom_root_icon),
selected_path, "/", NULL, icon);
g_object_unref (icon);
}
else
{
gtk_path_bar_set_path (path_bar, selected_path);
}
g_free (selected_path);
g_free (new_display_path);
}
static void
on_file_changed (GtkFilesPathBar *path_bar,
GParamSpec *pspec,
gpointer *user_data)
{
GFile *file;
gchar *uri;
file = gtk_files_path_bar_get_file (path_bar);
uri = g_file_get_uri (file);
g_print ("File selected: %s in GtkFilesPathBar\n", uri);
g_free (uri);
}
static void
connect_path_bar (GtkPathBar *path_bar)
{
g_signal_connect (GTK_PATH_BAR (path_bar), "populate-popup",
G_CALLBACK (on_populate_popup), NULL);
g_signal_connect (GTK_PATH_BAR (path_bar), "notify::selected-path",
G_CALLBACK (on_path_selected), NULL);
}
static void
connect_path_bar_set_path (GtkPathBar *path_bar)
{
g_signal_connect (GTK_PATH_BAR (path_bar), "populate-popup",
G_CALLBACK (on_populate_popup), NULL);
g_signal_connect (GTK_PATH_BAR (path_bar), "notify::selected-path",
G_CALLBACK (on_path_selected_set_path), NULL);
}
static void
connect_files_path_bar (GtkFilesPathBar *files_path_bar)
{
g_signal_connect (GTK_FILES_PATH_BAR (files_path_bar), "populate-popup",
G_CALLBACK (on_populate_popup), NULL);
g_signal_connect (GTK_FILES_PATH_BAR (files_path_bar), "notify::file",
G_CALLBACK (on_file_changed), NULL);
}
static void
on_reset_button_clicked (GtkButton *reset_button)
{
GFile *file;
GIcon *icon;
gtk_path_bar_set_path (GTK_PATH_BAR (path_bar), ORIGINAL_PATH);
gtk_path_bar_set_path (GTK_PATH_BAR (path_bar_inverted), ORIGINAL_PATH);
gtk_path_bar_set_path (GTK_PATH_BAR (path_bar_slash), "/");
gtk_path_bar_set_path_extended (GTK_PATH_BAR (path_bar_custom_root_label),
ORIGINAL_PATH, ROOT_PATH, "This Is A Root", NULL);
icon = g_themed_icon_new ("drive-harddisk");
gtk_path_bar_set_path_extended (GTK_PATH_BAR (path_bar_custom_root_icon),
ORIGINAL_PATH, "/", NULL, icon);
g_object_unref (icon);
file = g_file_new_for_uri (REAL_LOCATION_RANDOM);
gtk_files_path_bar_set_file (GTK_FILES_PATH_BAR (files_path_bar_random), file);
g_object_unref (file);
file = g_file_new_for_uri (REAL_LOCATION_RECENT);
gtk_files_path_bar_set_file (GTK_FILES_PATH_BAR (files_path_bar_recent), file);
g_object_unref (file);
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *reset_button;
GtkWidget *label;
GFile *file = NULL;
GIcon *icon;
gtk_init (&argc, &argv);
window = g_object_connect (g_object_new (gtk_window_get_type (),
"type", GTK_WINDOW_TOPLEVEL,
"title", "Test path bar",
"resizable", TRUE,
"default-height", 200,
NULL),
"signal::destroy", gtk_main_quit, NULL,
NULL);
action_group = G_ACTION_GROUP (g_simple_action_group_new ());
g_action_map_add_action_entries (G_ACTION_MAP (action_group), entries,
G_N_ELEMENTS (entries), window);
gtk_widget_insert_action_group (window, "action_group", action_group);
grid = gtk_grid_new ();
g_type_ensure (GTK_TYPE_PATH_BAR);
label = gtk_label_new ("Generic GtkPathBar tests");
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 2, 1);
/* ----------------------------------------------------------------------- */
path_bar = gtk_path_bar_new ();
gtk_grid_attach (GTK_GRID (grid), path_bar, 0, 1, 1, 1);
gtk_path_bar_set_path (GTK_PATH_BAR (path_bar), ORIGINAL_PATH);
connect_path_bar (GTK_PATH_BAR (path_bar));
/* ----------------------------------------------------------------------- */
path_bar_inverted = gtk_path_bar_new ();
gtk_path_bar_set_inverted (GTK_PATH_BAR (path_bar_inverted), TRUE);
gtk_path_bar_set_path (GTK_PATH_BAR (path_bar_inverted), ORIGINAL_PATH);
connect_path_bar (GTK_PATH_BAR (path_bar_inverted));
gtk_grid_attach (GTK_GRID (grid), path_bar_inverted, 0, 2, 1, 1);
label = gtk_label_new ("“/” a.k.a root, special case");
gtk_grid_attach (GTK_GRID (grid), label, 0, 3, 2, 1);
/* ----------------------------------------------------------------------- */
path_bar_slash = gtk_path_bar_new ();
gtk_path_bar_set_inverted (GTK_PATH_BAR (path_bar_slash), TRUE);
gtk_path_bar_set_path (GTK_PATH_BAR (path_bar_slash), "/");
connect_path_bar_set_path (GTK_PATH_BAR (path_bar_slash));
gtk_grid_attach (GTK_GRID (grid), path_bar_slash, 0, 4, 1, 1);
label = gtk_label_new ("GtkPathBar with special roots");
gtk_grid_attach (GTK_GRID (grid), label, 0, 5, 2, 1);
/* ----------------------------------------------------------------------- */
path_bar_custom_root_label = gtk_path_bar_new ();
gtk_path_bar_set_inverted (GTK_PATH_BAR (path_bar_custom_root_label), TRUE);
gtk_path_bar_set_path_extended (GTK_PATH_BAR (path_bar_custom_root_label),
ORIGINAL_PATH, ROOT_PATH, "This Is A Root", NULL);
connect_path_bar_set_path (GTK_PATH_BAR (path_bar_custom_root_label));
gtk_grid_attach (GTK_GRID (grid), path_bar_custom_root_label, 0, 6, 1, 1);
/* ----------------------------------------------------------------------- */
path_bar_custom_root_icon = gtk_path_bar_new ();
gtk_path_bar_set_inverted (GTK_PATH_BAR (path_bar_custom_root_icon), TRUE);
icon = g_themed_icon_new ("drive-harddisk");
gtk_path_bar_set_path_extended (GTK_PATH_BAR (path_bar_custom_root_icon),
ORIGINAL_PATH, "/", NULL, icon);
g_object_unref (icon);
connect_path_bar_set_path (GTK_PATH_BAR (path_bar_custom_root_icon));
gtk_grid_attach (GTK_GRID (grid), path_bar_custom_root_icon, 0, 7, 1, 1);
/* GtkFilesPathBar tests */
label = gtk_label_new ("GtkFilesPathBar tests");
gtk_grid_attach (GTK_GRID (grid), label, 0, 8, 2, 1);
/* ----------------------------------------------------------------------- */
files_path_bar_random = gtk_files_path_bar_new ();
file = g_file_new_for_uri (REAL_LOCATION_RANDOM);
gtk_files_path_bar_set_file (GTK_FILES_PATH_BAR (files_path_bar_random), file);
connect_files_path_bar (GTK_FILES_PATH_BAR (files_path_bar_random));
gtk_grid_attach (GTK_GRID (grid), files_path_bar_random, 0, 9, 1, 1);
g_clear_object (&file);
files_path_bar_recent = gtk_files_path_bar_new ();
file = g_file_new_for_uri (REAL_LOCATION_RECENT);
gtk_files_path_bar_set_file (GTK_FILES_PATH_BAR (files_path_bar_recent), file);
connect_files_path_bar (GTK_FILES_PATH_BAR (files_path_bar_recent));
gtk_grid_attach (GTK_GRID (grid), files_path_bar_recent, 0, 10, 1, 1);
g_clear_object (&file);
/* Reset button */
reset_button = gtk_button_new_with_label ("Reset State");
gtk_widget_set_hexpand (reset_button, TRUE);
g_signal_connect (GTK_BUTTON (reset_button), "clicked",
G_CALLBACK (on_reset_button_clicked), window);
gtk_grid_attach (GTK_GRID (grid), reset_button, 0, 11, 2, 1);
gtk_container_add (GTK_CONTAINER (window), grid);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}