Commit 75e1e546 authored by Christian Hergert's avatar Christian Hergert

messages: add IdeWorkbenchMessage

This is a new widget that can be pushed onto a workbench so that toplevel
messages are visible to the user. You might use this to show a warning
that a package needs to be installed, such as flatpak-builder.
parent dd6997fe
......@@ -191,6 +191,7 @@ libide_1_0_la_public_headers = \
workbench/ide-omni-bar.h \
workbench/ide-perspective.h \
workbench/ide-workbench-addin.h \
workbench/ide-workbench-message.h \
workbench/ide-workbench-header-bar.h \
workbench/ide-workbench.h \
workers/ide-worker.h \
......@@ -370,6 +371,7 @@ libide_1_0_la_public_sources = \
workbench/ide-perspective.c \
workbench/ide-workbench-addin.c \
workbench/ide-workbench-header-bar.c \
workbench/ide-workbench-message.c \
workbench/ide-workbench-open.c \
workbench/ide-workbench.c \
workers/ide-worker.c \
......
......@@ -172,6 +172,7 @@ G_BEGIN_DECLS
#include "workbench/ide-layout.h"
#include "workbench/ide-perspective.h"
#include "workbench/ide-workbench-addin.h"
#include "workbench/ide-workbench-message.h"
#include "workbench/ide-workbench-header-bar.h"
#include "workbench/ide-workbench.h"
......
......@@ -83,6 +83,7 @@
<file compressed="true" alias="ide-shortcuts-window.ui">../keybindings/ide-shortcuts-window.ui</file>
<file compressed="true" alias="ide-workbench-header-bar.ui">../workbench/ide-workbench-header-bar.ui</file>
<file compressed="true" alias="ide-workbench.ui">../workbench/ide-workbench.ui</file>
<file compressed="true" alias="ide-workbench-message.ui">../workbench/ide-workbench-message.ui</file>
</gresource>
<gresource prefix="/org/gnome/builder/plugins/buildconfig">
......
/* ide-workbench-message.c
*
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define G_LOG_DOMAIN "ide-workbench-message"
#include "ide-workbench-message.h"
struct _IdeWorkbenchMessage
{
GtkInfoBar parent_instance;
gchar *id;
GtkLabel *title;
GtkLabel *subtitle;
};
enum {
PROP_0,
PROP_ID,
PROP_TITLE,
PROP_SUBTITLE,
N_PROPS
};
G_DEFINE_TYPE (IdeWorkbenchMessage, ide_workbench_message, GTK_TYPE_INFO_BAR)
static GParamSpec *properties [N_PROPS];
static void
ide_workbench_message_finalize (GObject *object)
{
IdeWorkbenchMessage *self = (IdeWorkbenchMessage *)object;
g_clear_pointer (&self->id, g_free);
G_OBJECT_CLASS (ide_workbench_message_parent_class)->finalize (object);
}
static void
ide_workbench_message_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
IdeWorkbenchMessage *self = IDE_WORKBENCH_MESSAGE (object);
switch (prop_id)
{
case PROP_ID:
g_value_set_string (value, ide_workbench_message_get_id (self));
break;
case PROP_TITLE:
g_value_set_string (value, ide_workbench_message_get_title (self));
break;
case PROP_SUBTITLE:
g_value_set_string (value, ide_workbench_message_get_subtitle (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
ide_workbench_message_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
IdeWorkbenchMessage *self = IDE_WORKBENCH_MESSAGE (object);
switch (prop_id)
{
case PROP_ID:
ide_workbench_message_set_id (self, g_value_get_string (value));
break;
case PROP_TITLE:
ide_workbench_message_set_title (self, g_value_get_string (value));
break;
case PROP_SUBTITLE:
ide_workbench_message_set_subtitle (self, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
ide_workbench_message_class_init (IdeWorkbenchMessageClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = ide_workbench_message_finalize;
object_class->get_property = ide_workbench_message_get_property;
object_class->set_property = ide_workbench_message_set_property;
properties [PROP_ID] =
g_param_spec_string ("id", NULL, NULL, NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties [PROP_TITLE] =
g_param_spec_string ("title", NULL, NULL, NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties [PROP_SUBTITLE] =
g_param_spec_string ("subtitle", NULL, NULL, NULL,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/builder/ui/ide-workbench-message.ui");
gtk_widget_class_bind_template_child (widget_class, IdeWorkbenchMessage, title);
gtk_widget_class_bind_template_child (widget_class, IdeWorkbenchMessage, subtitle);
}
static void
ide_workbench_message_init (IdeWorkbenchMessage *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
}
const gchar *
ide_workbench_message_get_id (IdeWorkbenchMessage *self)
{
g_return_val_if_fail (IDE_IS_WORKBENCH_MESSAGE (self), NULL);
return self->id;
}
void
ide_workbench_message_set_id (IdeWorkbenchMessage *self,
const gchar *id)
{
g_return_if_fail (IDE_IS_WORKBENCH_MESSAGE (self));
if (g_strcmp0 (id, self->id) != 0)
{
g_free (self->id);
self->id = g_strdup (id);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ID]);
}
}
const gchar *
ide_workbench_message_get_title (IdeWorkbenchMessage *self)
{
g_return_val_if_fail (IDE_IS_WORKBENCH_MESSAGE (self), NULL);
return gtk_label_get_label (self->title);
}
void
ide_workbench_message_set_title (IdeWorkbenchMessage *self,
const gchar *title)
{
g_return_if_fail (IDE_IS_WORKBENCH_MESSAGE (self));
gtk_label_set_label (self->title, title);
gtk_widget_set_visible (GTK_WIDGET (self->title), title || *title);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
}
const gchar *
ide_workbench_message_get_subtitle (IdeWorkbenchMessage *self)
{
g_return_val_if_fail (IDE_IS_WORKBENCH_MESSAGE (self), NULL);
return gtk_label_get_label (self->subtitle);
}
void
ide_workbench_message_set_subtitle (IdeWorkbenchMessage *self,
const gchar *subtitle)
{
g_return_if_fail (IDE_IS_WORKBENCH_MESSAGE (self));
gtk_label_set_label (self->subtitle, subtitle);
gtk_widget_set_visible (GTK_WIDGET (self->subtitle), subtitle || *subtitle);
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SUBTITLE]);
}
void
ide_workbench_message_add_action (IdeWorkbenchMessage *self,
const gchar *title,
const gchar *action_name)
{
GtkWidget *button;
g_return_if_fail (IDE_IS_WORKBENCH_MESSAGE (self));
g_return_if_fail (title);
button = g_object_new (GTK_TYPE_BUTTON,
"action-name", action_name,
"label", title,
"visible", TRUE,
NULL);
gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_action_area (GTK_INFO_BAR (self))), button);
}
/* ide-workbench-message.h
*
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef IDE_WORKBENCH_MESSAGE_H
#define IDE_WORKBENCH_MESSAGE_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define IDE_TYPE_WORKBENCH_MESSAGE (ide_workbench_message_get_type())
G_DECLARE_FINAL_TYPE (IdeWorkbenchMessage, ide_workbench_message, IDE, WORKBENCH_MESSAGE, GtkInfoBar)
GtkWidget *ide_workbench_message_new (void);
const gchar *ide_workbench_message_get_id (IdeWorkbenchMessage *self);
void ide_workbench_message_set_id (IdeWorkbenchMessage *self,
const gchar *id);
const gchar *ide_workbench_message_get_title (IdeWorkbenchMessage *self);
void ide_workbench_message_set_title (IdeWorkbenchMessage *self,
const gchar *title);
const gchar *ide_workbench_message_get_subtitle (IdeWorkbenchMessage *self);
void ide_workbench_message_set_subtitle (IdeWorkbenchMessage *self,
const gchar *subtitle);
void ide_workbench_message_add_action (IdeWorkbenchMessage *self,
const gchar *label,
const gchar *action_name);
G_END_DECLS
#endif /* IDE_WORKBENCH_MESSAGE_H */
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.22 -->
<template class="IdeWorkbenchMessage" parent="GtkInfoBar">
<property name="show-close-button">true</property>
<child internal-child="content_area">
<object class="GtkBox" id="hbox">
<property name="orientation">horizontal</property>
<property name="hexpand">true</property>
<property name="visible">true</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="visible">true</property>
<child>
<object class="GtkLabel" id="title">
<property name="visible">true</property>
<property name="xalign">0.0</property>
<property name="wrap">true</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="GtkLabel" id="subtitle">
<property name="visible">true</property>
<property name="xalign">0.0</property>
<property name="wrap">true</property>
<style>
<class name="dim-label"/>
</style>
<attributes>
<attribute name="scale" value="0.833333"/>
</attributes>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>
......@@ -51,6 +51,7 @@ struct _IdeWorkbench
IdePerspectiveMenuButton *perspective_menu_button;
GtkStack *perspectives_stack;
GtkSizeGroup *header_size_group;
GtkBox *message_box;
GObject *selection_owner;
};
......
......@@ -409,6 +409,7 @@ ide_workbench_class_init (IdeWorkbenchClass *klass)
gtk_widget_class_bind_template_child (widget_class, IdeWorkbench, header_bar);
gtk_widget_class_bind_template_child (widget_class, IdeWorkbench, header_size_group);
gtk_widget_class_bind_template_child (widget_class, IdeWorkbench, header_stack);
gtk_widget_class_bind_template_child (widget_class, IdeWorkbench, message_box);
gtk_widget_class_bind_template_child (widget_class, IdeWorkbench, perspective_menu_button);
gtk_widget_class_bind_template_child (widget_class, IdeWorkbench, perspectives_stack);
}
......@@ -979,3 +980,76 @@ ide_workbench_get_headerbar (IdeWorkbench *self)
return self->header_bar;
}
static void
ide_workbench_message_response (IdeWorkbench *self,
gint response_id,
IdeWorkbenchMessage *message)
{
g_assert (IDE_IS_WORKBENCH (self));
g_assert (IDE_IS_WORKBENCH_MESSAGE (message));
if (response_id == GTK_RESPONSE_CLOSE)
gtk_widget_hide (GTK_WIDGET (message));
}
void
ide_workbench_push_message (IdeWorkbench *self,
IdeWorkbenchMessage *message)
{
g_return_if_fail (IDE_IS_WORKBENCH (self));
g_return_if_fail (IDE_IS_WORKBENCH_MESSAGE (message));
g_signal_connect_object (message,
"response",
G_CALLBACK (ide_workbench_message_response),
self,
G_CONNECT_SWAPPED);
gtk_container_add (GTK_CONTAINER (self->message_box), GTK_WIDGET (message));
}
static void
locate_widget_for_message_id (GtkWidget *widget,
gpointer user_data)
{
struct {
const gchar *id;
GtkWidget *widget;
} *lookup = user_data;
if (IDE_IS_WORKBENCH_MESSAGE (widget))
{
const gchar *id;
id = ide_workbench_message_get_id (IDE_WORKBENCH_MESSAGE (widget));
if (g_strcmp0 (id, lookup->id) == 0)
lookup->widget = widget;
}
}
gboolean
ide_workbench_pop_message (IdeWorkbench *self,
const gchar *message_id)
{
struct {
const gchar *id;
GtkWidget *widget;
} lookup = { message_id };
g_return_val_if_fail (IDE_IS_WORKBENCH (self), FALSE);
g_return_val_if_fail (message_id != NULL, FALSE);
gtk_container_foreach (GTK_CONTAINER (self->message_box),
locate_widget_for_message_id,
&lookup);
if (lookup.widget)
{
gtk_widget_destroy (lookup.widget);
return TRUE;
}
return FALSE;
}
......@@ -26,6 +26,7 @@
#include "util/ide-uri.h"
#include "workbench/ide-perspective.h"
#include "workbench/ide-workbench-header-bar.h"
#include "workbench/ide-workbench-message.h"
G_BEGIN_DECLS
......@@ -98,6 +99,10 @@ void ide_workbench_views_foreach (IdeWorkbench
GtkCallback callback,
gpointer user_data);
IdeWorkbenchHeaderBar *ide_workbench_get_headerbar (IdeWorkbench *self);
void ide_workbench_push_message (IdeWorkbench *self,
IdeWorkbenchMessage *message);
gboolean ide_workbench_pop_message (IdeWorkbench *self,
const gchar *message_id);
G_END_DECLS
......
......@@ -33,12 +33,28 @@
<object class="GtkOverlay">
<property name="visible">true</property>
<child>
<object class="GtkStack" id="perspectives_stack">
<property name="hexpand">true</property>
<property name="homogeneous">false</property>
<property name="transition-type">crossfade</property>
<property name="transition-duration">333</property>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="visible">true</property>
<child>
<object class="GtkBox" id="message_box">
<property name="orientation">vertical</property>
<property name="hexpand">false</property>
<property name="visible">true</property>
<style>
<class name="message-box"/>
</style>
</object>
</child>
<child>
<object class="GtkStack" id="perspectives_stack">
<property name="hexpand">true</property>
<property name="homogeneous">false</property>
<property name="transition-type">crossfade</property>
<property name="transition-duration">333</property>
<property name="visible">true</property>
</object>
</child>
</object>
</child>
</object>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment