[gtksourceview/wip/chergert/gsv-gtk4: 231/259] informative: add informative tooltip class




commit 28b8215dca4b67467ef5c3701fa265f45da8685f
Author: Christian Hergert <chergert redhat com>
Date:   Wed Sep 9 12:47:46 2020 -0700

    informative: add informative tooltip class
    
    This can be used to display information with the sourceview, such as
    tooltips related to cursor position.

 gtksourceview/GtkSourceView.css              |  52 +++++
 gtksourceview/gtksourceinformative-private.h |  47 ++++
 gtksourceview/gtksourceinformative.c         | 316 +++++++++++++++++++++++++++
 gtksourceview/gtksourceinformative.ui        |  25 +++
 gtksourceview/gtksourceview.gresource.xml    |   1 +
 gtksourceview/meson.build                    |   1 +
 6 files changed, 442 insertions(+)
---
diff --git a/gtksourceview/GtkSourceView.css b/gtksourceview/GtkSourceView.css
index b3e1787d..ff49f32c 100644
--- a/gtksourceview/GtkSourceView.css
+++ b/gtksourceview/GtkSourceView.css
@@ -93,3 +93,55 @@ GtkSourceAssistant.completion box.details button.flat {
 GtkSourceAssistant.completion-info {
   padding: 6px;
 }
+
+GtkSourceAssistant.informative label {
+  padding-right: 10px;
+}
+GtkSourceAssistant.informative image {
+  margin: 0 6px 0 0;
+  padding: 6px 10px 6px 9px;
+  border-top-left-radius: 7px;
+  border-bottom-left-radius: 7px;
+}
+
+GtkSourceAssistant.informative.warning {
+  background-color: @warning_color;
+  color: @theme_selected_fg_color;
+  border-color: shade(@warning_color, 0.8);
+  text-shadow: 0 1px shade(@warning_color, 0.8);
+  -gtk-icon-shadow: 0 1px shade(@warning_color, 0.8);
+}
+GtkSourceAssistant.informative.warning image {
+  background-color: shade(@warning_color, 0.8);
+}
+
+GtkSourceAssistant.informative.error {
+  background-color: @error_color;
+  color: @theme_selected_fg_color;
+  border-color: shade(@error_color, 0.8);
+  text-shadow: 0 1px shade(@error_color, 0.8);
+  -gtk-icon-shadow: 0 1px shade(@error_color, 0.8);
+}
+GtkSourceAssistant.informative.error image {
+  background-color: shade(@error_color, 0.8);
+}
+
+GtkSourceAssistant.informative.info {
+  background-color: @success_color;
+  color: @theme_selected_fg_color;
+  border-color: shade(@success_color, 0.8);
+  text-shadow: 0 1px shade(@success_color, 0.8);
+  -gtk-icon-shadow: 0 1px shade(@success_color, 0.8);
+}
+GtkSourceAssistant.informative.info image {
+  background-color: shade(@success_color, 0.8);
+}
+
+GtkSourceAssistant.informative.question {
+  background-color: @theme_bg_color;
+  color: @theme_fg_color;
+  border-color: @borders;
+}
+GtkSourceAssistant.informative.question image {
+  background-color: @borders;
+}
diff --git a/gtksourceview/gtksourceinformative-private.h b/gtksourceview/gtksourceinformative-private.h
new file mode 100644
index 00000000..ac72e25d
--- /dev/null
+++ b/gtksourceview/gtksourceinformative-private.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * GtkSourceView is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+#include "gtksourceassistant-private.h"
+
+G_BEGIN_DECLS
+
+#define GTK_SOURCE_TYPE_INFORMATIVE (gtk_source_informative_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (GtkSourceInformative, gtk_source_informative, GTK_SOURCE, INFORMATIVE, 
GtkSourceAssistant)
+
+struct _GtkSourceInformativeClass
+{
+       GtkSourceAssistantClass parent_class;
+};
+
+const char     *gtk_source_informative_get_message      (GtkSourceInformative *self);
+void            gtk_source_informative_set_message      (GtkSourceInformative *self,
+                                                         const char           *message);
+void            gtk_source_informative_set_message_type (GtkSourceInformative *self,
+                                                         GtkMessageType        message_type);
+GtkMessageType  gtk_source_informative_get_message_type (GtkSourceInformative *self);
+const char     *gtk_source_informative_get_icon_name    (GtkSourceInformative *self);
+void            gtk_source_informative_set_icon_name    (GtkSourceInformative *self,
+                                                         const char           *icon_name);
+
+G_END_DECLS
diff --git a/gtksourceview/gtksourceinformative.c b/gtksourceview/gtksourceinformative.c
new file mode 100644
index 00000000..2201ef44
--- /dev/null
+++ b/gtksourceview/gtksourceinformative.c
@@ -0,0 +1,316 @@
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * GtkSourceView is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * GtkSourceView 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include "gtksourceinformative-private.h"
+#include "gtksourceview.h"
+
+typedef struct
+{
+       GtkImage *icon;
+       GtkLabel *message;
+       GtkMessageType message_type;
+} GtkSourceInformativePrivate;
+
+enum {
+       PROP_0,
+       PROP_ICON_NAME,
+       PROP_MESSAGE,
+       PROP_MESSAGE_TYPE,
+       N_PROPS
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceInformative, gtk_source_informative, GTK_SOURCE_TYPE_ASSISTANT)
+
+static GParamSpec *properties [N_PROPS];
+
+const char *
+gtk_source_informative_get_message (GtkSourceInformative *self)
+{
+       GtkSourceInformativePrivate *priv = gtk_source_informative_get_instance_private (self);
+
+       g_return_val_if_fail (GTK_SOURCE_IS_INFORMATIVE (self), NULL);
+
+       return gtk_label_get_label (priv->message);
+}
+
+void
+gtk_source_informative_set_message (GtkSourceInformative *self,
+                                    const char           *message)
+{
+       GtkSourceInformativePrivate *priv = gtk_source_informative_get_instance_private (self);
+
+       g_return_if_fail (GTK_SOURCE_IS_INFORMATIVE (self));
+
+       gtk_label_set_label (priv->message, message);
+       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MESSAGE]);
+}
+
+GtkMessageType
+gtk_source_informative_get_message_type (GtkSourceInformative *self)
+{
+       GtkSourceInformativePrivate *priv = gtk_source_informative_get_instance_private (self);
+
+       g_return_val_if_fail (GTK_SOURCE_IS_INFORMATIVE (self), GTK_MESSAGE_OTHER);
+
+       return priv->message_type;
+}
+
+void
+gtk_source_informative_set_message_type (GtkSourceInformative *self,
+                                         GtkMessageType        message_type)
+{
+       GtkSourceInformativePrivate *priv = gtk_source_informative_get_instance_private (self);
+
+       g_assert (GTK_SOURCE_IS_INFORMATIVE (self));
+
+       priv->message_type = message_type;
+
+       gtk_widget_remove_css_class (GTK_WIDGET (self), "error");
+       gtk_widget_remove_css_class (GTK_WIDGET (self), "info");
+       gtk_widget_remove_css_class (GTK_WIDGET (self), "question");
+       gtk_widget_remove_css_class (GTK_WIDGET (self), "warning");
+
+       switch (priv->message_type)
+       {
+       case GTK_MESSAGE_INFO:
+               gtk_widget_add_css_class (GTK_WIDGET (self), "info");
+               break;
+
+       case GTK_MESSAGE_WARNING:
+               gtk_widget_add_css_class (GTK_WIDGET (self), "warning");
+               break;
+
+       case GTK_MESSAGE_QUESTION:
+               gtk_widget_add_css_class (GTK_WIDGET (self), "question");
+               break;
+
+       case GTK_MESSAGE_ERROR:
+               gtk_widget_add_css_class (GTK_WIDGET (self), "error");
+               break;
+
+       case GTK_MESSAGE_OTHER:
+       default:
+               break;
+       }
+
+       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MESSAGE_TYPE]);
+}
+
+const char *
+gtk_source_informative_get_icon_name (GtkSourceInformative *self)
+{
+       GtkSourceInformativePrivate *priv = gtk_source_informative_get_instance_private (self);
+
+       g_assert (GTK_SOURCE_IS_INFORMATIVE (self));
+
+       return gtk_image_get_icon_name (priv->icon);
+}
+
+void
+gtk_source_informative_set_icon_name (GtkSourceInformative *self,
+                                      const char           *icon_name)
+{
+       GtkSourceInformativePrivate *priv = gtk_source_informative_get_instance_private (self);
+
+       g_assert (GTK_SOURCE_IS_INFORMATIVE (self));
+
+       gtk_image_set_from_icon_name (priv->icon, icon_name);
+       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ICON_NAME]);
+}
+
+static void
+gtk_source_informative_get_offset (GtkSourceAssistant *assistant,
+                                   int                *x_offset,
+                                   int                *y_offset)
+{
+       GtkSourceInformative *self = GTK_SOURCE_INFORMATIVE (assistant);
+       GtkSourceInformativePrivate *priv = gtk_source_informative_get_instance_private (self);
+       GtkRequisition min;
+
+       GTK_SOURCE_ASSISTANT_CLASS (gtk_source_informative_parent_class)->get_offset (assistant, x_offset, 
y_offset);
+
+       gtk_widget_get_preferred_size (GTK_WIDGET (priv->icon), &min, NULL);
+
+       *x_offset -= min.width;
+}
+
+static gboolean
+key_press_propagate_cb (GtkSourceInformative  *self,
+                        guint                  keyval,
+                        guint                  keycode,
+                        GdkModifierType        modifiers,
+                        GtkEventControllerKey *key)
+{
+       GtkWidget *parent;
+
+       g_assert (GTK_SOURCE_IS_INFORMATIVE (self));
+       g_assert (GTK_IS_EVENT_CONTROLLER_KEY (key));
+
+       parent = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_SOURCE_TYPE_VIEW);
+
+       if (GTK_SOURCE_IS_VIEW (parent))
+       {
+               return gtk_event_controller_key_forward (key, parent);
+       }
+
+       return GDK_EVENT_PROPAGATE;
+}
+
+static gboolean
+key_release_propagate_cb (GtkSourceInformative  *self,
+                          guint                  keyval,
+                          guint                  keycode,
+                          GdkModifierType        modifiers,
+                          GtkEventControllerKey *key)
+{
+       GtkWidget *parent;
+
+       g_assert (GTK_SOURCE_IS_INFORMATIVE (self));
+       g_assert (GTK_IS_EVENT_CONTROLLER_KEY (key));
+
+       parent = gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_SOURCE_TYPE_VIEW);
+
+       if (GTK_SOURCE_IS_VIEW (parent))
+       {
+               return gtk_event_controller_key_forward (key, parent);
+       }
+
+       return GDK_EVENT_PROPAGATE;
+}
+
+static void
+gtk_source_informative_get_property (GObject    *object,
+                                     guint       prop_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+       GtkSourceInformative *self = GTK_SOURCE_INFORMATIVE (object);
+
+       switch (prop_id)
+       {
+       case PROP_ICON_NAME:
+               g_value_set_string (value, gtk_source_informative_get_icon_name (self));
+               break;
+
+       case PROP_MESSAGE:
+               g_value_set_string (value, gtk_source_informative_get_message (self));
+               break;
+
+       case PROP_MESSAGE_TYPE:
+               g_value_set_enum (value, gtk_source_informative_get_message_type (self));
+               break;
+
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+gtk_source_informative_set_property (GObject      *object,
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+       GtkSourceInformative *self = GTK_SOURCE_INFORMATIVE (object);
+
+       switch (prop_id)
+       {
+       case PROP_ICON_NAME:
+               gtk_source_informative_set_icon_name (self, g_value_get_string (value));
+               break;
+
+       case PROP_MESSAGE:
+               gtk_source_informative_set_message (self, g_value_get_string (value));
+               break;
+
+       case PROP_MESSAGE_TYPE:
+               gtk_source_informative_set_message_type (self, g_value_get_enum (value));
+               break;
+
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       }
+}
+
+static void
+gtk_source_informative_class_init (GtkSourceInformativeClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+       GtkSourceAssistantClass *assistant_class = GTK_SOURCE_ASSISTANT_CLASS (klass);
+
+       object_class->get_property = gtk_source_informative_get_property;
+       object_class->set_property = gtk_source_informative_set_property;
+
+       assistant_class->get_offset = gtk_source_informative_get_offset;
+
+       properties [PROP_ICON_NAME] =
+               g_param_spec_string ("icon-name",
+                                    "Icon Name",
+                                    "Icon Name",
+                                    NULL,
+                                    (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+       properties [PROP_MESSAGE] =
+               g_param_spec_string ("message",
+                                    "Message",
+                                    "The message for the popover",
+                                    NULL,
+                                    (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+       properties [PROP_MESSAGE_TYPE] =
+               g_param_spec_enum ("message-type",
+                                  "Message Type",
+                                  "The message type for the popover",
+                                  GTK_TYPE_MESSAGE_TYPE,
+                                  GTK_MESSAGE_INFO,
+                                  (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/gtksourceview/ui/gtksourceinformative.ui");
+       gtk_widget_class_bind_template_child_private (widget_class, GtkSourceInformative, icon);
+       gtk_widget_class_bind_template_child_private (widget_class, GtkSourceInformative, message);
+}
+
+static void
+gtk_source_informative_init (GtkSourceInformative *self)
+{
+       GtkEventController *key;
+
+       gtk_widget_init_template (GTK_WIDGET (self));
+
+       key = gtk_event_controller_key_new ();
+       gtk_event_controller_set_propagation_phase (key, GTK_PHASE_BUBBLE);
+       g_signal_connect_object (key,
+                                "key-pressed",
+                                G_CALLBACK (key_press_propagate_cb),
+                                self,
+                                G_CONNECT_SWAPPED);
+       g_signal_connect_object (key,
+                                "key-released",
+                                G_CALLBACK (key_release_propagate_cb),
+                                self,
+                                G_CONNECT_SWAPPED);
+       gtk_widget_add_controller (GTK_WIDGET (self), g_steal_pointer (&key));
+}
diff --git a/gtksourceview/gtksourceinformative.ui b/gtksourceview/gtksourceinformative.ui
new file mode 100644
index 00000000..f418cca0
--- /dev/null
+++ b/gtksourceview/gtksourceinformative.ui
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GtkSourceInformative" parent="GtkSourceAssistant">
+    <property name="can-focus">false</property>
+    <style>
+      <class name="informative"/>
+    </style>
+    <child>
+      <object class="GtkBox">
+        <property name="orientation">horizontal</property>
+        <property name="can-focus">false</property>
+        <child>
+          <object class="GtkImage" id="icon">
+          </object>
+        </child>
+        <child>
+          <object class="GtkLabel" id="message">
+            <property name="hexpand">true</property>
+            <property name="xalign">0</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/gtksourceview/gtksourceview.gresource.xml b/gtksourceview/gtksourceview.gresource.xml
index 68256313..ccf6f5c1 100644
--- a/gtksourceview/gtksourceview.gresource.xml
+++ b/gtksourceview/gtksourceview.gresource.xml
@@ -6,6 +6,7 @@
   <gresource prefix="/org/gnome/gtksourceview/ui">
     <file preprocess="xml-stripblanks">gtksourcecompletionlist.ui</file>
     <file preprocess="xml-stripblanks">gtksourcecompletionlistboxrow.ui</file>
+    <file preprocess="xml-stripblanks">gtksourceinformative.ui</file>
     <file preprocess="xml-stripblanks">gtksourcestyleschemechooserwidget.ui</file>
   </gresource>
 </gresources>
diff --git a/gtksourceview/meson.build b/gtksourceview/meson.build
index 7e7fef3b..d7f923a0 100644
--- a/gtksourceview/meson.build
+++ b/gtksourceview/meson.build
@@ -107,6 +107,7 @@ core_private_c = files([
   'gtksourceengine.c',
   'gtksourcegutterrendererlines.c',
   'gtksourcegutterrenderermarks.c',
+  'gtksourceinformative.c',
   'gtksourceiter.c',
   'gtksourcelanguage-parser-2.c',
   'gtksourcemarkssequence.c',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]