[gnome-builder: 1/3] ide: add light bulb
- From: Günther Wagner <gwagner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder: 1/3] ide: add light bulb
- Date: Sat, 4 Dec 2021 10:52:11 +0000 (UTC)
commit d6f11c7288443f38367f08bf0217f64ee0961a0d
Author: Georg Vienna <georg vienna himbarsoft com>
Date: Fri Nov 12 16:24:51 2021 +0100
ide: add light bulb
src/libide/sourceview/ide-light-bulb-private.h | 36 ++
src/libide/sourceview/ide-light-bulb.c | 533 +++++++++++++++++++++
src/libide/sourceview/ide-source-view.c | 20 +
src/libide/sourceview/meson.build | 2 +
src/libide/themes/libide-themes.gresource.xml | 1 +
src/libide/themes/themes/shared.css | 1 +
.../themes/themes/shared/shared-light-bulb.css | 25 +
7 files changed, 618 insertions(+)
---
diff --git a/src/libide/sourceview/ide-light-bulb-private.h b/src/libide/sourceview/ide-light-bulb-private.h
new file mode 100644
index 000000000..743f49418
--- /dev/null
+++ b/src/libide/sourceview/ide-light-bulb-private.h
@@ -0,0 +1,36 @@
+/* ide-light-bulb-private.h
+ *
+ * Copyright 2021 Georg Vienna <georg vienna himbarsoft 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include "ide-source-view.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_LIGHT_BULB (ide_light_bulb_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeLightBulb, ide_light_bulb, IDE, LIGHT_BULB, GtkEventBox)
+
+IdeLightBulb *_ide_light_bulb_new (IdeSourceView *source_view);
+void _ide_light_bulb_show (IdeLightBulb *self);
+
+G_END_DECLS
diff --git a/src/libide/sourceview/ide-light-bulb.c b/src/libide/sourceview/ide-light-bulb.c
new file mode 100644
index 000000000..f76868a95
--- /dev/null
+++ b/src/libide/sourceview/ide-light-bulb.c
@@ -0,0 +1,533 @@
+/* ide-light-bulb.c
+ *
+ * Copyright 2021 Georg Vienna <georg vienna himbarsoft 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-light-bulb"
+
+#define CURSOR_SETTLE_TIMEOUT_MSEC 250
+
+#include "config.h"
+
+#include <dazzle.h>
+#include <libide-code.h>
+#include <libide-gui.h>
+#include <string.h>
+
+#include "ide-light-bulb-private.h"
+
+struct _IdeLightBulb
+{
+ GtkEventBox parent_instance;
+
+ /*
+ * This is our cancellable to cancel any in-flight requests to the
+ * code action providers when the cursor is moved. That could happen
+ * before we've even really been displayed to the user.
+ */
+ GCancellable *cancellable;
+
+ /*
+ * Our source which is continually delayed until the cursor moved event has
+ * settled somewhere we can potentially query for code actions.
+ */
+ guint delay_query_source;
+
+ IdeSourceView* source_view;
+
+ GtkWidget* popup_menu;
+
+ GtkTextIter* last_range_start;
+ GtkTextIter* last_range_end;
+};
+
+G_DEFINE_FINAL_TYPE (IdeLightBulb, ide_light_bulb, GTK_TYPE_EVENT_BOX)
+
+static void
+ide_light_bulb_realize (GtkWidget *widget)
+{
+ GdkWindow *window;
+ GdkDisplay *display;
+
+ g_autoptr(GdkCursor) cursor = NULL;
+
+ g_assert(GTK_IS_WIDGET(widget));
+
+ GTK_WIDGET_CLASS (ide_light_bulb_parent_class)->realize(widget);
+
+ window = gtk_widget_get_window (GTK_WIDGET(widget));
+ display = gtk_widget_get_display (GTK_WIDGET(widget));
+ cursor = gdk_cursor_new_from_name (display, "default");
+
+ gdk_window_set_events (window, GDK_ALL_EVENTS_MASK);
+ gdk_window_set_cursor (window, cursor);
+}
+
+static void
+ide_light_bulb_destroy (GtkWidget *widget)
+{
+ IdeLightBulb *self = (IdeLightBulb *)widget;
+
+ g_cancellable_cancel (self->cancellable);
+ g_clear_object (&self->cancellable);
+
+ dzl_clear_source (&self->delay_query_source);
+
+ if (self->last_range_start)
+ {
+ gtk_text_iter_free (self->last_range_start);
+ }
+ if (self->last_range_end)
+ {
+ gtk_text_iter_free (self->last_range_end);
+ }
+
+ GTK_WIDGET_CLASS (ide_light_bulb_parent_class)->destroy(widget);
+}
+
+static void
+ide_light_bulb_class_init (IdeLightBulbClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+ widget_class->realize = ide_light_bulb_realize;
+ widget_class->destroy = ide_light_bulb_destroy;
+}
+
+static void
+popup_menu_detach (GtkWidget *attach_widget,
+ GtkMenu *menu)
+{
+}
+
+static void
+button_clicked_cb (IdeLightBulb *self,
+ GtkButton *button)
+{
+ gtk_menu_popup_at_widget (GTK_MENU(self->popup_menu),
+ GTK_WIDGET(button),
+ GDK_GRAVITY_SOUTH_EAST,
+ GDK_GRAVITY_NORTH_WEST,
+ NULL);
+}
+
+static void
+popup_menu_hide_cb (GtkButton *button,
+ GtkMenu *menu)
+{
+ gtk_widget_unset_state_flags (GTK_WIDGET(button), GTK_STATE_FLAG_PRELIGHT);
+}
+
+static void
+ide_light_bulb_init(IdeLightBulb *self)
+{
+ GtkStyleContext *style_context;
+ GtkWidget* button;
+ GtkWidget* box;
+ GtkWidget* bulb;
+ GtkWidget* arrow;
+
+ self->cancellable = g_cancellable_new ();
+
+ style_context = gtk_widget_get_style_context (GTK_WIDGET(self));
+ gtk_style_context_add_class (style_context, "light-bulb");
+
+ button = gtk_button_new ();
+ gtk_widget_set_focus_on_click (button, FALSE);
+ gtk_widget_show (button);
+ gtk_container_add (GTK_CONTAINER(self), button);
+
+ g_signal_connect_swapped (button,
+ "clicked",
+ G_CALLBACK(button_clicked_cb),
+ self);
+
+ gtk_container_set_border_width (GTK_CONTAINER(self), 0);
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
+ gtk_widget_show (box);
+ gtk_container_add (GTK_CONTAINER(button), box);
+
+ bulb = gtk_image_new_from_icon_name ("dialog-information-symbolic", GTK_ICON_SIZE_BUTTON);
+ gtk_image_set_pixel_size (GTK_IMAGE(bulb), 12);
+ gtk_widget_show (bulb);
+ gtk_container_add (GTK_CONTAINER(box), bulb);
+
+ arrow = gtk_image_new_from_icon_name ("pan-down-symbolic", GTK_ICON_SIZE_BUTTON);
+ gtk_image_set_pixel_size (GTK_IMAGE(arrow), 12);
+ gtk_widget_show (arrow);
+ gtk_container_add (GTK_CONTAINER(box), arrow);
+
+ self->popup_menu = gtk_menu_new ();
+ g_object_set (self->popup_menu,
+ "rect-anchor-dx", -10,
+ "rect-anchor-dy", -10,
+ NULL);
+ g_signal_connect_swapped (self->popup_menu, "hide",
+ G_CALLBACK(popup_menu_hide_cb),
+ button);
+
+ gtk_style_context_add_class (gtk_widget_get_style_context(self->popup_menu),
+ GTK_STYLE_CLASS_CONTEXT_MENU);
+
+ gtk_menu_attach_to_widget (GTK_MENU(self->popup_menu),
+ GTK_WIDGET(self),
+ popup_menu_detach);
+}
+
+static void
+ide_source_view_code_action_executed_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+}
+
+static void
+execute_code_action_cb(IdeCodeAction *code_action)
+{
+ ide_code_action_execute_async (code_action,
+ NULL,
+ ide_source_view_code_action_executed_cb,
+ code_action);
+}
+
+static void
+ide_light_bulb_place_at_iter(IdeLightBulb* self, GtkTextIter* iter_cursor)
+{
+ g_autoptr(GtkTextIter) iter = NULL;
+ g_autoptr(GtkTextIter) iter_end = NULL;
+ GdkRectangle rect;
+ guint chars_in_line;
+ g_autofree gchar* first_chars_in_line = NULL;
+ gboolean place_above_iter;
+ gint button_height = 24;
+ gint y_pos = 0;
+
+ iter = gtk_text_iter_copy (iter_cursor);
+
+ /* move iter to first position */
+ gtk_text_iter_set_line_offset (iter, 0);
+
+ chars_in_line = gtk_text_iter_get_chars_in_line (iter);
+ iter_end = gtk_text_iter_copy (iter);
+ gtk_text_iter_set_line_offset (iter_end, MIN(chars_in_line - 1, 4));
+ first_chars_in_line = gtk_text_iter_get_text (iter, iter_end);
+ place_above_iter = !ide_str_empty0 (g_strstrip (first_chars_in_line));
+
+ if (place_above_iter)
+ {
+ gint line = gtk_text_iter_get_line (iter);
+ if (line)
+ {
+ gtk_text_iter_set_line (iter, line - 1);
+ }
+ else
+ {
+ gtk_text_iter_set_line (iter, line + 1);
+ }
+ }
+
+ gtk_text_view_get_iter_location (GTK_TEXT_VIEW(self->source_view), iter, &rect);
+
+ if (place_above_iter)
+ {
+ /* align with top of the line below */
+ y_pos = rect.y + rect.height - button_height;
+ }
+ else
+ {
+ /* center verically in line */
+ y_pos = rect.y + (rect.height / 2) - (button_height / 2);
+ }
+ gtk_text_view_move_child (GTK_TEXT_VIEW(self->source_view),
+ GTK_WIDGET(self),
+ 0,
+ y_pos);
+ gtk_widget_show (GTK_WIDGET(self));
+}
+
+static void
+ide_light_bulb_code_action_query_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeBuffer *buffer = (IdeBuffer *)object;
+
+ g_autoptr(IdeLightBulb) self = user_data;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GPtrArray) code_actions = NULL;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_BUFFER (buffer));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_LIGHT_BULB (self));
+
+ code_actions = ide_buffer_code_action_query_finish (buffer, result, &error);
+ if (!code_actions)
+ {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
+ g_warning ("%s", error->message);
+ IDE_EXIT;
+ }
+
+ if (code_actions->len)
+ {
+ GtkTextIter iter;
+ g_autoptr(IdeContext) context = NULL;
+
+ ide_buffer_get_selection_bounds (buffer, &iter, NULL);
+
+ ide_light_bulb_place_at_iter (self, &iter);
+
+ gtk_container_foreach (GTK_CONTAINER(self->popup_menu),
+ (GtkCallback)gtk_widget_destroy,
+ NULL);
+ context = ide_buffer_ref_context (buffer);
+
+ for (gsize i = 0; i < code_actions->len; i++)
+ {
+ IdeCodeAction* code_action;
+ GtkWidget* menu_item;
+
+ code_action = g_ptr_array_index (code_actions, i);
+ ide_object_append (IDE_OBJECT(context), IDE_OBJECT(code_action));
+ menu_item = gtk_menu_item_new_with_label (ide_code_action_get_title(code_action));
+
+ g_signal_connect_swapped (menu_item,
+ "activate",
+ G_CALLBACK(execute_code_action_cb),
+ code_action);
+
+
+ gtk_widget_show (menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL(self->popup_menu), menu_item);
+ }
+ }
+ else
+ {
+ gtk_widget_hide (GTK_WIDGET(self));
+ }
+}
+
+static gboolean
+ide_source_get_word_from_iter(const GtkTextIter *iter,
+ GtkTextIter *word_start,
+ GtkTextIter *word_end)
+{
+ /* Just using forward/backward to word start/end is not enough
+ * because _ break words when using those functions while they
+ * are commonly used in the same word in code */
+ *word_start = *iter;
+ *word_end = *iter;
+
+ do
+ {
+ const gunichar c = gtk_text_iter_get_char (word_end);
+ if (!(g_unichar_isalnum(c) || c == '_'))
+ break;
+ }while (gtk_text_iter_forward_char (word_end));
+
+ if (gtk_text_iter_equal (word_start, word_end))
+ {
+ /* Iter is not inside a word */
+ return FALSE;
+ }
+
+ while (gtk_text_iter_backward_char (word_start))
+ {
+ const gunichar c = gtk_text_iter_get_char (word_start);
+ if (!(g_unichar_isalnum (c) || c == '_'))
+ {
+ gtk_text_iter_forward_char (word_start);
+ break;
+ }
+ }
+
+ return(!gtk_text_iter_equal (word_start, word_end));
+}
+
+static gboolean
+ide_light_bulb_get_trigger_bound (IdeBuffer *buffer,
+ GtkTextIter **trigger_start,
+ GtkTextIter **trigger_end)
+{
+ GtkTextIter insert;
+ GtkTextIter selection;
+ GtkTextIter insert_word_start;
+ GtkTextIter insert_word_end;
+
+ ide_buffer_get_selection_bounds (buffer, &insert, &selection);
+
+ if (gtk_text_iter_equal (&insert, &selection))
+ {
+ gint chars_in_line;
+ gunichar character;
+
+ chars_in_line = gtk_text_iter_get_chars_in_line (&insert);
+ if (chars_in_line == 0)
+ {
+ return FALSE;
+ }
+ character = gtk_text_iter_get_char (&insert);
+ if (g_unichar_isspace (character))
+ {
+ return FALSE;
+ }
+
+ if (ide_source_get_word_from_iter (&insert, &insert_word_start, &insert_word_end))
+ {
+ *trigger_start = gtk_text_iter_copy(&insert_word_start);
+ *trigger_end = gtk_text_iter_copy(&insert_word_end);
+ return TRUE;
+ }
+ }
+
+
+ if (ide_source_get_word_from_iter (&insert, &insert_word_start, &insert_word_end))
+ {
+ GtkTextIter selection_word_start;
+ GtkTextIter selection_word_end;
+
+ insert = insert_word_start;
+
+ if (ide_source_get_word_from_iter (&selection, &selection_word_start, &selection_word_end))
+ {
+ selection = selection_word_end;
+ }
+ }
+
+ *trigger_start = gtk_text_iter_copy(&insert);
+ *trigger_end = gtk_text_iter_copy(&selection);
+
+ return TRUE;
+}
+
+static gboolean
+ide_light_bulb_delay_timeout_cb (gpointer data)
+{
+ IdeLightBulb *self = data;
+ IdeBuffer* buffer = IDE_BUFFER(gtk_text_view_get_buffer (GTK_TEXT_VIEW(self->source_view)));
+
+ self->delay_query_source = 0;
+
+ ide_buffer_code_action_query_async (buffer,
+ self->cancellable,
+ ide_light_bulb_code_action_query_cb,
+ g_object_ref(self));
+ return G_SOURCE_REMOVE;
+}
+
+static
+void ide_light_bulb_cancel (IdeLightBulb *self)
+{
+ g_autoptr(GCancellable) cancellable = NULL;
+
+ cancellable = g_steal_pointer (&self->cancellable);
+ if (!g_cancellable_is_cancelled (cancellable))
+ {
+ g_cancellable_cancel (cancellable);
+ }
+ if (self->delay_query_source)
+ {
+ g_source_remove (self->delay_query_source);
+ }
+}
+
+void
+_ide_light_bulb_show (IdeLightBulb *self)
+{
+ IdeBuffer* buffer;
+
+ g_autoptr(GtkTextIter) trigger_start = NULL;
+ g_autoptr(GtkTextIter) trigger_end = NULL;
+ gboolean contains_word = FALSE;
+
+ g_return_if_fail (IDE_IS_LIGHT_BULB(self));
+ g_return_if_fail (GTK_IS_TEXT_VIEW(self->source_view));
+
+ buffer = IDE_BUFFER(gtk_text_view_get_buffer (GTK_TEXT_VIEW(self->source_view)));
+
+ contains_word = ide_light_bulb_get_trigger_bound (buffer, &trigger_start, &trigger_end);
+
+ /* ignore and cancel if triggered in whitespace */
+ if (!contains_word)
+ {
+ ide_light_bulb_cancel (self);
+ if (self->last_range_start)
+ {
+ gtk_text_iter_free (self->last_range_start);
+ self->last_range_start = NULL;
+ }
+ if (self->last_range_end)
+ {
+ gtk_text_iter_free (self->last_range_end);
+ self->last_range_end = NULL;
+ }
+ gtk_widget_hide (GTK_WIDGET(self));
+ return;
+ }
+
+ /* ignore if triggered in the same range/word again */
+ if (self->last_range_start &&
+ gtk_text_iter_equal (self->last_range_start, trigger_start) &&
+ self->last_range_end &&
+ gtk_text_iter_equal (self->last_range_end, trigger_end))
+ {
+ return;
+ }
+
+ /* cancel old request */
+ ide_light_bulb_cancel (self);
+ self->cancellable = g_cancellable_new ();
+
+ /* safe current trigger range */
+ if (self->last_range_start)
+ {
+ gtk_text_iter_free (self->last_range_start);
+ }
+ self->last_range_start = gtk_text_iter_copy (trigger_start);
+ if (self->last_range_end)
+ {
+ gtk_text_iter_free (self->last_range_end);
+ }
+ self->last_range_end = gtk_text_iter_copy (trigger_end);
+
+
+ self->delay_query_source =
+ gdk_threads_add_timeout_full (G_PRIORITY_LOW,
+ CURSOR_SETTLE_TIMEOUT_MSEC,
+ ide_light_bulb_delay_timeout_cb,
+ self,
+ NULL);
+}
+
+IdeLightBulb *
+_ide_light_bulb_new(IdeSourceView* source_view)
+{
+ IdeLightBulb* bulb = g_object_new (IDE_TYPE_LIGHT_BULB, NULL);
+
+ bulb->source_view = source_view;
+
+ gtk_text_view_add_child_in_window (GTK_TEXT_VIEW(source_view),
+ GTK_WIDGET(g_object_ref(GTK_WIDGET(bulb))),
+ GTK_TEXT_WINDOW_TEXT,
+ 0,
+ 100);
+ return bulb;
+}
diff --git a/src/libide/sourceview/ide-source-view.c b/src/libide/sourceview/ide-source-view.c
index 34b73af31..e50b3792f 100644
--- a/src/libide/sourceview/ide-source-view.c
+++ b/src/libide/sourceview/ide-source-view.c
@@ -38,6 +38,7 @@
#include "ide-cursor.h"
#include "ide-hover-private.h"
#include "ide-indenter.h"
+#include "ide-light-bulb-private.h"
#include "ide-snippet-chunk.h"
#include "ide-snippet-context.h"
#include "ide-snippet-private.h"
@@ -97,6 +98,7 @@ typedef struct
IdeCompletion *completion;
IdeHover *hover;
+ IdeLightBulb *light_bulb;
DzlBindingGroup *file_setting_bindings;
DzlSignalGroup *buffer_signals;
@@ -866,6 +868,17 @@ ide_source_view__buffer_changed_cb (IdeSourceView *self,
priv->change_sequence++;
}
+static void
+ide_source_view__buffer_cursor_moved_cb (IdeSourceView *self,
+ IdeBuffer *buffer)
+{
+ IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+
+ g_assert (IDE_IS_SOURCE_VIEW (self));
+
+ _ide_light_bulb_show(priv->light_bulb);
+}
+
static void
ide_source_view_rebuild_css (IdeSourceView *self)
{
@@ -5581,6 +5594,7 @@ ide_source_view_dispose (GObject *object)
g_clear_handle_id (&priv->delay_size_allocate_chainup, g_source_remove);
g_clear_object (&priv->hover);
+ g_clear_object (&priv->light_bulb);
g_clear_object (&priv->completion);
g_clear_object (&priv->capture);
ide_clear_and_destroy_object (&priv->indenter_adapter);
@@ -6787,6 +6801,7 @@ ide_source_view_init (IdeSourceView *self)
priv->overscroll_num_lines = DEFAULT_OVERSCROLL_NUM_LINES;
priv->hover = _ide_hover_new (self);
+ priv->light_bulb = _ide_light_bulb_new (self);
priv->file_setting_bindings = dzl_binding_group_new ();
dzl_binding_group_bind (priv->file_setting_bindings, "auto-indent",
@@ -6813,6 +6828,11 @@ ide_source_view_init (IdeSourceView *self)
G_CALLBACK (ide_source_view__buffer_changed_cb),
self,
G_CONNECT_SWAPPED);
+ dzl_signal_group_connect_object (priv->buffer_signals,
+ "cursor-moved",
+ G_CALLBACK (ide_source_view__buffer_cursor_moved_cb),
+ self,
+ G_CONNECT_SWAPPED);
dzl_signal_group_connect_object (priv->buffer_signals,
"request-scroll-to-insert",
G_CALLBACK (ide_source_view__buffer_request_scroll_to_insert_cb),
diff --git a/src/libide/sourceview/meson.build b/src/libide/sourceview/meson.build
index 99641298b..e0d810578 100644
--- a/src/libide/sourceview/meson.build
+++ b/src/libide/sourceview/meson.build
@@ -18,6 +18,7 @@ libide_sourceview_private_headers = [
'ide-cursor.h',
'ide-hover-popover-private.h',
'ide-hover-private.h',
+ 'ide-light-bulb-private.h',
'ide-source-view-capture.h',
'ide-source-view-mode.h',
'ide-source-view-movements.h',
@@ -68,6 +69,7 @@ libide_sourceview_private_sources = [
'ide-cursor.c',
'ide-hover.c',
'ide-hover-popover.c',
+ 'ide-light-bulb.c',
'ide-line-change-gutter-renderer.c',
'ide-source-view-capture.c',
'ide-source-view-mode.c',
diff --git a/src/libide/themes/libide-themes.gresource.xml b/src/libide/themes/libide-themes.gresource.xml
index 2d22cd6b7..c844a643a 100644
--- a/src/libide/themes/libide-themes.gresource.xml
+++ b/src/libide/themes/libide-themes.gresource.xml
@@ -23,6 +23,7 @@
<file compressed="true">themes/shared/shared-greeter.css</file>
<file compressed="true">themes/shared/shared-hoverer.css</file>
<file compressed="true">themes/shared/shared-layout.css</file>
+ <file compressed="true">themes/shared/shared-light-bulb.css</file>
<file compressed="true">themes/shared/shared-omnibar.css</file>
<file compressed="true">themes/shared/shared-search.css</file>
<file compressed="true">themes/shared/shared-treeview.css</file>
diff --git a/src/libide/themes/themes/shared.css b/src/libide/themes/themes/shared.css
index e14da6f0b..a305fc779 100644
--- a/src/libide/themes/themes/shared.css
+++ b/src/libide/themes/themes/shared.css
@@ -5,6 +5,7 @@
@import url("resource:///org/gnome/builder/themes/shared/shared-editor.css");
@import url("resource:///org/gnome/builder/themes/shared/shared-greeter.css");
@import url("resource:///org/gnome/builder/themes/shared/shared-hoverer.css");
+@import url("resource:///org/gnome/builder/themes/shared/shared-light-bulb.css");
@import url("resource:///org/gnome/builder/themes/shared/shared-omnibar.css");
@import url("resource:///org/gnome/builder/themes/shared/shared-search.css");
@import url("resource:///org/gnome/builder/themes/shared/shared-treeview.css");
diff --git a/src/libide/themes/themes/shared/shared-light-bulb.css
b/src/libide/themes/themes/shared/shared-light-bulb.css
new file mode 100644
index 000000000..f514deda2
--- /dev/null
+++ b/src/libide/themes/themes/shared/shared-light-bulb.css
@@ -0,0 +1,25 @@
+
+.light-bulb image {
+ color: #f9f06b;
+}
+
+
+.light-bulb button {
+ padding: 0px 4px;
+ background: none;
+ border: none;
+ box-shadow: none;
+}
+
+.light-bulb button:hover {
+ background: @theme_bg_color;
+ box-shadow: 0 0 3px 3px alpha(#000, .3);
+}
+
+.light-bulb button image:last-child {
+ opacity: 0;
+}
+
+.light-bulb button:hover image:last-child {
+ opacity: 1;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]