Verified Commit 11eda5e3 authored by Zander Brown's avatar Zander Brown
Browse files

Use handy's searchbar

parent 96c56a74
......@@ -34,7 +34,6 @@
<xi:include href="xml/kgx-window.xml"/>
<xi:include href="xml/kgx-terminal.xml"/>
<xi:include href="xml/kgx-process.xml"/>
<xi:include href="xml/kgx-search-box.xml"/>
<chapter>
<title>Confirm Close Dialog</title>
<xi:include href="xml/kgx-close-dialog.xml"/>
......
......@@ -37,7 +37,6 @@
#include "kgx-config.h"
#include "kgx-application.h"
#include "kgx-search-box.h"
#include "kgx-window.h"
#define LOGO_COL_SIZE 28
......@@ -271,7 +270,6 @@ kgx_application_startup (GApplication *app)
const char *const zoom_out_accels[] = { "<primary>minus", NULL };
g_type_ensure (KGX_TYPE_TERMINAL);
g_type_ensure (KGX_TYPE_SEARCH_BOX);
G_APPLICATION_CLASS (kgx_application_parent_class)->startup (app);
......
/* kgx-search-box.c
*
* Copyright 2019 Zander Brown
*
* 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/>.
*/
/**
* SECTION:kgx-search-box
* @title: KgxSearchBox
* @short_description: The dynamically sized search box
*
* #GtkSearchBar has a weird way of sizing its children which results in a
* tiny #GtkSearchEntry, we could set #GtkWidget:width-request but then the
* entry wouldn't go small enough for the
* [librem5](https://puri.sm/products/librem-5/) and would still be small on
* in larger windows, sigh
*
* So here we are with a custom widget that does almost nothing but allows
* the entry to grow up to 500px wide whilst still going as small as possible
* as the window gets smaller, it also proxies various signals from
* #GtkSearchEntry up for consumers to listen to
*
* This *must* be inside a #GtkSearchBar, it may still work outside one but
* that's very much undefined behaviour
*
* Since: 0.1.0
*/
#include <glib/gi18n.h>
#include "kgx-config.h"
#include "kgx-search-box.h"
G_DEFINE_TYPE (KgxSearchBox, kgx_search_box, GTK_TYPE_BOX)
enum {
NEXT,
PREVIOUS,
CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
static void
kgx_search_box_get_preferred_width (GtkWidget *widget,
gint *minimum_width,
gint *natural_width)
{
KgxSearchBox *self = KGX_SEARCH_BOX (widget);
int min = 0;
GTK_WIDGET_CLASS (kgx_search_box_parent_class)->get_preferred_width (widget,
&min,
NULL);
if (minimum_width)
*minimum_width = min;
if (natural_width) {
int request = 400;
if (self->parent_width < 400) {
// Nothing like a good, arbitrary, magic value
request = self->parent_width - 50;
} else if (G_LIKELY (self->parent_width > 500)) {
request = 500;
} else {
// Effectivly provides a nice transition between states
request = (self->parent_width - 50) * 0.9;
}
// Seems unlikly to happen, but not impossible
if (G_UNLIKELY (min > request)) {
*natural_width = min;
} else {
*natural_width = request;
}
}
}
static void
search_changed (GtkEntry *entry,
KgxSearchBox *self)
{
g_signal_emit (self, signals[CHANGED], 0, kgx_search_box_get_search (self));
}
static void
search_next (gpointer entry_or_button,
KgxSearchBox *self)
{
g_signal_emit (self, signals[NEXT], 0);
}
static void
search_prev (gpointer entry_or_button,
KgxSearchBox *self)
{
g_signal_emit (self, signals[PREVIOUS], 0);
}
static void
kgx_search_box_class_init (KgxSearchBoxClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
widget_class->get_preferred_width = kgx_search_box_get_preferred_width;
/**
* KgxSearchBox::next:
*
* Straight proxy to #GtkSearchEntry::next-match so check that for details
* (also includes #GtkButton::clicked for the relevent button)
*
* Since: 0.1.0
*/
signals[NEXT] = g_signal_new ("next",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* KgxSearchBox::previous:
*
* Straight proxy to #GtkSearchEntry::previous-match so check that for
* details (also includes #GtkButton::clicked for the relevent button)
*
* Since: 0.1.0
*/
signals[PREVIOUS] = g_signal_new ("previous",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* KgxSearchBox::changed:
* @self: the #KgxSearchBox
* @search: The current contents of the #GtkSearchEntry
*
* Proxy to #GtkSearchEntry::search-changed but with the current search
* as a parameter
*
* Since: 0.1.0
*/
signals[CHANGED] = g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_STRING);
gtk_widget_class_set_template_from_resource (widget_class,
RES_PATH "kgx-search-box.ui");
gtk_widget_class_bind_template_child (widget_class, KgxSearchBox, entry);
gtk_widget_class_bind_template_callback (widget_class, search_changed);
gtk_widget_class_bind_template_callback (widget_class, search_next);
gtk_widget_class_bind_template_callback (widget_class, search_prev);
}
static void
parent_size_changed (GtkWidget *parent,
GdkRectangle *allocation,
KgxSearchBox *self)
{
// Cache the value for get_preferred_width to use later
self->parent_width = allocation->width;
// Ask to be reallocated so get_preferred_width can work out how big
// we should be now the parent has been resized
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
static void
set_parent (KgxSearchBox *self)
{
GtkWidget *new_parent = gtk_widget_get_parent (GTK_WIDGET (self));
// We may not have a valid parent yet (or it's been destroyed)
if (self->parent && G_IS_OBJECT (self->parent))
g_signal_handlers_disconnect_by_func (self->parent, parent_size_changed, self);
// GtkSearchBar has various internal widgets, we dont really care about them
// and unless some theme has done something really weird they shouldn't
// effect the available width
if (new_parent)
new_parent = gtk_widget_get_ancestor (new_parent, GTK_TYPE_SEARCH_BAR);
// Listen for the parent to be given a size
if (new_parent)
g_signal_connect (new_parent,
"size-allocate",
G_CALLBACK (parent_size_changed),
self);
// Cache the parent
self->parent = new_parent;
}
static void
kgx_search_box_init (KgxSearchBox *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
self->parent = NULL;
// Not even construct properties are set yet thus parent will
// only be set after we connect to no need for initial sync
g_signal_connect (self, "notify::parent", G_CALLBACK (set_parent), NULL);
}
/**
* kgx_search_box_get_search:
* @self: The #KgxSearchBox
*
* Gets the current search, aka #GtkEntry:text on the #GtkSearchEntry
*
* Since: 0.1.0
*/
const char *
kgx_search_box_get_search (KgxSearchBox *self)
{
g_return_val_if_fail (KGX_IS_SEARCH_BOX (self), NULL);
return gtk_entry_get_text (GTK_ENTRY (self->entry));
}
/**
* kgx_search_box_focus:
* @self: the #KgxSearchBox
*
* gtk_widget_grab_focus() the #GtkSearchEntry
*
* Since: 0.2.0
*/
void
kgx_search_box_focus (KgxSearchBox *self)
{
g_return_if_fail (KGX_IS_SEARCH_BOX (self));
gtk_widget_grab_focus (self->entry);
}
/* kgx-search-box.h
*
* Copyright 2019 Zander Brown
*
* 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/>.
*/
#pragma once
#include <gtk/gtk.h>
#include <vte/vte.h>
G_BEGIN_DECLS
#define KGX_TYPE_SEARCH_BOX (kgx_search_box_get_type())
/**
* KgxSearchBox:
* @parent: The #GtkSearchBar that contains the box
* @entry: The #GtkSearchEntry we contain
* @parent_width: Width of the @parent
*
* Stability: Private
*
* Since: 0.1.0
*/
struct _KgxSearchBox
{
/*< private >*/
GtkBox parent_instance;
/*< public >*/
GtkWidget *parent;
GtkWidget *entry;
int parent_width;
};
G_DECLARE_FINAL_TYPE (KgxSearchBox, kgx_search_box, KGX, SEARCH_BOX, GtkBox)
const char *kgx_search_box_get_search (KgxSearchBox *self);
void kgx_search_box_focus (KgxSearchBox *self);
G_END_DECLS
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="KgxSearchBox" parent="GtkBox">
<child>
<object class="GtkSearchEntry" id="entry">
<property name="visible">1</property>
<property name="can-focus">1</property>
<property name="hexpand">1</property>
<signal name="next-match" handler="search_next" swapped="no"/>
<signal name="previous-match" handler="search_prev" swapped="no"/>
<signal name="search-changed" handler="search_changed" swapped="no"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="visible">1</property>
<property name="can-focus">1</property>
<property name="receives-default">1</property>
<child>
<object class="GtkImage">
<property name="visible">1</property>
<property name="icon-name">go-down-symbolic</property>
</object>
</child>
<signal name="clicked" handler="search_next" swapped="no"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="visible">1</property>
<property name="can-focus">1</property>
<property name="receives-default">1</property>
<child>
<object class="GtkImage">
<property name="visible">1</property>
<property name="icon-name">go-up-symbolic</property>
</object>
</child>
<signal name="clicked" handler="search_prev" swapped="no"/>
</object>
</child>
<style>
<class name="linked"/>
</style>
</template>
</interface>
......@@ -33,6 +33,8 @@
#define PCRE2_CODE_UNIT_WIDTH 0
#include <pcre2.h>
#include <math.h>
#define HANDY_USE_UNSTABLE_API
#include <handy.h>
#include "rgba.h"
#include "fp-vte-util.h"
......@@ -40,7 +42,6 @@
#include "kgx-config.h"
#include "kgx-window.h"
#include "kgx-application.h"
#include "kgx-search-box.h"
#include "kgx-process.h"
#include "kgx-close-dialog.h"
......@@ -453,20 +454,20 @@ search_enabled (GObject *object,
GParamSpec *pspec,
KgxWindow *self)
{
if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (self->search_bar))) {
kgx_search_box_focus (KGX_SEARCH_BOX (self->search_wrap));
} else {
if (!hdy_search_bar_get_search_mode (HDY_SEARCH_BAR (self->search_bar))) {
gtk_widget_grab_focus (self->terminal);
}
}
static void
search_changed (KgxSearchBox *box,
const gchar *search,
search_changed (HdySearchBar *bar,
KgxWindow *self)
{
VteRegex *regex;
GError *error = NULL;
const char *search = NULL;
search = gtk_entry_get_text (GTK_ENTRY (self->search_entry));
regex = vte_regex_new_for_search (g_regex_escape_string (search, -1),
-1, PCRE2_MULTILINE, &error);
......@@ -481,14 +482,14 @@ search_changed (KgxSearchBox *box,
}
static void
search_next (KgxSearchBox *box,
search_next (HdySearchBar *bar,
KgxWindow *self)
{
vte_terminal_search_find_next (VTE_TERMINAL (self->terminal));
}
static void
search_prev (KgxSearchBox *box,
search_prev (HdySearchBar *bar,
KgxWindow *self)
{
vte_terminal_search_find_previous (VTE_TERMINAL (self->terminal));
......@@ -663,8 +664,8 @@ kgx_window_class_init (KgxWindowClass *klass)
gtk_widget_class_bind_template_child (widget_class, KgxWindow, header_bar);
gtk_widget_class_bind_template_child (widget_class, KgxWindow, terminal);
gtk_widget_class_bind_template_child (widget_class, KgxWindow, dims);
gtk_widget_class_bind_template_child (widget_class, KgxWindow, search_entry);
gtk_widget_class_bind_template_child (widget_class, KgxWindow, search_bar);
gtk_widget_class_bind_template_child (widget_class, KgxWindow, search_wrap);
gtk_widget_class_bind_template_child (widget_class, KgxWindow, exit_info);
gtk_widget_class_bind_template_child (widget_class, KgxWindow, exit_message);
gtk_widget_class_bind_template_child (widget_class, KgxWindow, zoom_level);
......@@ -875,6 +876,9 @@ kgx_window_init (KgxWindow *self)
g_object_bind_property (self, "is-maximized",
self->terminal, "opaque",
G_BINDING_SYNC_CREATE);
hdy_search_bar_connect_entry (HDY_SEARCH_BAR (self->search_bar),
GTK_ENTRY (self->search_entry));
}
/**
......
......@@ -78,8 +78,8 @@ struct _KgxWindow
GtkWidget *header_bar;
GtkWidget *terminal;
GtkWidget *dims;
GtkWidget *search_entry;
GtkWidget *search_bar;
GtkWidget *search_wrap;
GtkWidget *exit_info;
GtkWidget *exit_message;
GtkWidget *zoom_level;
......
......@@ -140,15 +140,59 @@
<property name="visible">1</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchBar" id="search_bar">
<object class="HdySearchBar" id="search_bar">
<property name="visible">1</property>
<signal name="notify::search-mode-enabled" handler="search_enabled" swapped="no"/>
<child>
<object class="KgxSearchBox" id="search_wrap">
<object class="HdyColumn">
<property name="visible">1</property>
<signal name="next" handler="search_next" swapped="no"/>
<signal name="previous" handler="search_prev" swapped="no"/>
<signal name="changed" handler="search_changed" swapped="no"/>
<property name="maximum-width">500</property>
<child>
<object class="GtkBox">
<property name="visible">1</property>
<child>
<object class="GtkSearchEntry" id="search_entry">
<property name="visible">1</property>
<property name="can-focus">1</property>
<property name="hexpand">1</property>
<signal name="next-match" handler="search_next" swapped="no"/>
<signal name="previous-match" handler="search_prev" swapped="no"/>
<signal name="search-changed" handler="search_changed" swapped="no"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="visible">1</property>
<property name="can-focus">1</property>
<property name="receives-default">1</property>
<child>
<object class="GtkImage">
<property name="visible">1</property>
<property name="icon-name">go-down-symbolic</property>
</object>
</child>
<signal name="clicked" handler="search_next" swapped="no"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="visible">1</property>
<property name="can-focus">1</property>
<property name="receives-default">1</property>
<child>
<object class="GtkImage">
<property name="visible">1</property>
<property name="icon-name">go-up-symbolic</property>
</object>
</child>
<signal name="clicked" handler="search_prev" swapped="no"/>
</object>
</child>
<style>
<class name="linked"/>
</style>
</object>
</child>
</object>
</child>
<style>
......
......@@ -2,7 +2,6 @@
<gresources>
<gresource prefix="/org/gnome/zbrown/KingsCross">
<file compressed="true">kgx-window.ui</file>
<file compressed="true">kgx-search-box.ui</file>
<file compressed="true">kgx-close-dialog.ui</file>
<file compressed="true">kgx-close-dialog-row.ui</file>
<file compressed="true">styles.css</file>
......
......@@ -20,7 +20,6 @@
#include "kgx-application.h"
#include "kgx-window.h"
#include "kgx-terminal.h"
#include "kgx-search-box.h"
#include "kgx-enums.h"
#include "kgx-process.h"
......
......@@ -5,8 +5,6 @@ kgx_sources = [
'fp-vte-util.h',
'kgx-terminal.c',
'kgx-terminal.h',
'kgx-search-box.c',
'kgx-search-box.h',
'kgx-close-dialog.c',
'kgx-close-dialog.h',
'kgx-close-dialog-row.c',
......
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