[gnome-maps] Convert SearchPopup to GtkListBox



commit 11320aa33f9a2f1b17ca4558efe7af2dcd32bc90
Author: Jonas Danielsson <jonas danielsson threetimestwo org>
Date:   Fri Nov 14 03:26:23 2014 -0500

    Convert SearchPopup to GtkListBox

 src/gnome-maps.data.gresource.xml |    1 +
 src/placeEntry.js                 |   13 ++-
 src/placeFormatter.js             |    8 ++
 src/search-popup-row.ui           |   73 ++++++++++++++++++
 src/search-popup.ui               |   80 +++++++------------
 src/searchPopup.js                |  152 ++++++++++++++++---------------------
 src/sidebar.js                    |    3 +-
 7 files changed, 189 insertions(+), 141 deletions(-)
---
diff --git a/src/gnome-maps.data.gresource.xml b/src/gnome-maps.data.gresource.xml
index 450e6d1..5af82f8 100644
--- a/src/gnome-maps.data.gresource.xml
+++ b/src/gnome-maps.data.gresource.xml
@@ -6,6 +6,7 @@
     <file preprocess="xml-stripblanks">main-window.ui</file>
     <file preprocess="xml-stripblanks">zoom-control.ui</file>
     <file preprocess="xml-stripblanks">search-popup.ui</file>
+    <file preprocess="xml-stripblanks">search-popup-row.ui</file>
     <file preprocess="xml-stripblanks">sidebar.ui</file>
     <file preprocess="xml-stripblanks">context-menu.ui</file>
     <file preprocess="xml-stripblanks">layers-popover.ui</file>
diff --git a/src/placeEntry.js b/src/placeEntry.js
index cb57a28..409bc17 100644
--- a/src/placeEntry.js
+++ b/src/placeEntry.js
@@ -79,7 +79,7 @@ const PlaceEntry = new Lang.Class({
     },
 
     _init: function(props) {
-        let numVisible = props.num_visible || 10;
+        let numVisible = props.num_visible || 6;
         delete props.num_visible;
         this._mapView = props.mapView;
         delete props.mapView;
@@ -88,13 +88,16 @@ const PlaceEntry = new Lang.Class({
             props.primary_icon_name = null;
         delete props.loupe;
 
+        let maxChars = props.maxChars;
+        delete props.maxChars;
+
         let parseOnFocusOut = props.parseOnFocusOut;
         delete props.parseOnFocusOut;
 
         props.completion = this._createCompletion();
         this.parent(props);
 
-        this._popover = this._createPopover(numVisible);
+        this._popover = this._createPopover(numVisible, maxChars);
 
         this.connect('activate', this._onActivate.bind(this));
         this.connect('search-changed', (function() {
@@ -127,11 +130,11 @@ const PlaceEntry = new Lang.Class({
         return completion;
     },
 
-    _createPopover: function(numVisible) {
+    _createPopover: function(numVisible, maxChars) {
         let popover = new SearchPopup.SearchPopup({ num_visible:   numVisible,
                                                     relative_to:   this,
-                                                    no_show_all:   true,
-                                                    visible:       true });
+                                                    maxChars:      maxChars});
+
         this.connect('size-allocate', (function(widget, allocation) {
             // Magic number to make the alignment pixel perfect.
             let width_request = allocation.width + 20;
diff --git a/src/placeFormatter.js b/src/placeFormatter.js
index 6209241..895a762 100644
--- a/src/placeFormatter.js
+++ b/src/placeFormatter.js
@@ -56,6 +56,14 @@ const PlaceFormatter = new Lang.Class({
         return this._rows;
     },
 
+    getDetailsString: function() {
+        return this.rows.map((function(row) {
+            return row.map((function(prop) {
+                return this._place[prop];
+            }).bind(this)).join(', ');
+        }).bind(this)).join(', ');
+    },
+
     _update: function() {
         switch (this._place.place_type) {
         case Geocode.PlaceType.COUNTRY:
diff --git a/src/search-popup-row.ui b/src/search-popup-row.ui
new file mode 100644
index 0000000..32d5519
--- /dev/null
+++ b/src/search-popup-row.ui
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface>
+  <requires lib="gtk+" version="3.12"/>
+  <template class="Gjs_SearchPopupRow" parent="GtkListBoxRow">
+    <property name="visible">True</property>
+    <child>
+      <object class="GtkGrid" id="grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="margin-bottom">5</property>
+        <child>
+          <object class="GtkImage" id="icon">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="valign">start</property>
+            <property name="margin_end">10</property>
+            <property name="pixel_size">32</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+            <property name="height">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkImage" id="typeIcon">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="valign">start</property>
+            <property name="margin_start">10</property>
+            <property name="pixel_size">32</property>
+          </object>
+          <packing>
+            <property name="left_attach">2</property>
+            <property name="top_attach">0</property>
+            <property name="height">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="name">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">start</property>
+            <property name="use_markup">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="details">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">start</property>
+            <property name="use_markup">True</property>
+            <property name="ellipsize">end</property>
+            <style>
+              <class name="subtitle"/>
+              <class name="dim-label"/>
+            </style>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/search-popup.ui b/src/search-popup.ui
index 1ddfb17..a768c89 100644
--- a/src/search-popup.ui
+++ b/src/search-popup.ui
@@ -1,68 +1,48 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <!-- interface-requires gtk+ 3.10 -->
-  <object class="GtkStack" id="stack">
-    <property name="visible">True</property>
-    <property name="can_focus">False</property>
-    <property name="transition-type">crossfade</property>
+  <template class="Gjs_SearchPopup" parent="GtkPopover">
+    <property name="visible">False</property>
+    <property name="no_show_all">True</property>
+    <property name="hexpand">False</property>
     <style>
-      <class name="maps-stack"/>
+      <class name="maps-popover"/>
     </style>
     <child>
-      <object class="GtkScrolledWindow" id="scrolled-window">
+      <object class="GtkStack" id="stack">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="hscrollbar_policy">never</property>
-        <property name="shadow_type">in</property>
+        <property name="transition-type">crossfade</property>
+        <style>
+          <class name="maps-stack"/>
+        </style>
         <child>
-          <object class="GtkTreeView" id="treeview">
+          <object class="GtkScrolledWindow" id="scrolledWindow">
             <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="expand">True</property>
-            <property name="headers-visible">False</property>
-            <property name="hover-selection">True</property>
-            <property name="activate-on-single-click">True</property>
-            <child internal-child="selection">
-              <object class="GtkTreeSelection" id="treeview-selection"/>
-            </child>
-            <child>
-              <object class="GtkTreeViewColumn" id="icon-column">
-                <child>
-                  <object class="GtkCellRendererPixbuf" id="icon-cell">
-                    <property name="xpad">2</property>
-                  </object>
-                  <attributes>
-                    <attribute name="pixbuf">0</attribute>
-                  </attributes>
-                </child>
-              </object>
-            </child>
+            <property name="can_focus">False</property>
+            <property name="hscrollbar_policy">never</property>
+            <property name="shadow_type">in</property>
             <child>
-              <object class="GtkTreeViewColumn" id="text-column">
-                <child>
-                  <object class="GtkCellRendererText" id="text-cell">
-                    <property name="xpad">4</property>
-                    <property name="ypad">4</property>
-                  </object>
-                  <attributes>
-                    <attribute name="markup">2</attribute>
-                  </attributes>
-                </child>
+              <object class="GtkListBox" id="list">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="expand">True</property>
+                <property name="activate_on_single_click">True</property>
               </object>
             </child>
           </object>
         </child>
+        <child>
+          <object class="GtkSpinner" id="spinner">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">center</property>
+            <property name="valign">center</property>
+            <property name="width_request">16</property>
+            <property name="height_request">16</property>
+          </object>
+        </child>
       </object>
     </child>
-    <child>
-      <object class="GtkSpinner" id="spinner">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-        <property name="width_request">16</property>
-        <property name="height_request">16</property>
-      </object>
-    </child>
-  </object>
+  </template>
 </interface>
diff --git a/src/searchPopup.js b/src/searchPopup.js
index 3517622..d793726 100644
--- a/src/searchPopup.js
+++ b/src/searchPopup.js
@@ -24,15 +24,54 @@ const GdkPixbuf = imports.gi.GdkPixbuf;
 const Gtk = imports.gi.Gtk;
 const Lang = imports.lang;
 
+const PlaceFormatter = imports.placeFormatter;
 const Utils = imports.utils;
 
-const Columns = {
-    ICON:         0,
-    PLACE:        1,
-    DESCRIPTION:  2
-};
-
 const _PLACE_ICON_SIZE = 20;
+const _ROW_HEIGHT = 50;
+
+const SearchPopupRow = new Lang.Class({
+    Name: 'SearchPopupRow',
+    Extends: Gtk.ListBoxRow,
+    Template: 'resource:///org/gnome/maps/search-popup-row.ui',
+    InternalChildren: [ 'icon',
+                        'name',
+                        'details' ],
+
+    _init: function(params) {
+        this.place = params.place;
+        delete params.place;
+
+        let searchString = params.searchString;
+        delete params.searchString;
+
+        let maxChars = params.maxChars || 40;
+        delete params.maxChars;
+
+        params.height_request = _ROW_HEIGHT;
+        this.parent(params);
+
+        let formatter = new PlaceFormatter.PlaceFormatter(this.place);
+        let title = GLib.markup_escape_text(formatter.title, -1);
+
+        this._name.label = this._boldMatch(title, searchString);
+        this._details.max_width_chars = maxChars;
+        this._details.label = formatter.getDetailsString();
+        this._icon.gicon = this.place.icon;
+    },
+
+    _boldMatch: function(title, string) {
+        string = string.toLowerCase();
+
+        let index = title.toLowerCase().indexOf(string);
+
+        if (index !== -1) {
+            let substring = title.substring(index, index + string.length);
+            title = title.replace(substring, substring.bold());
+        }
+        return title;
+    }
+});
 
 const SearchPopup = new Lang.Class({
     Name: 'SearchPopup',
@@ -40,52 +79,27 @@ const SearchPopup = new Lang.Class({
     Signals : {
         'selected' : { param_types: [ GObject.TYPE_OBJECT ] }
     },
+    Template: 'resource:///org/gnome/maps/search-popup.ui',
+    InternalChildren: [ 'scrolledWindow',
+                        'stack',
+                        'spinner',
+                        'list' ],
 
     _init: function(props) {
-        this._numVisible = props.num_visible;
+        let numVisible = props.num_visible;
         delete props.num_visible;
 
-        let ui = Utils.getUIObject('search-popup', ['scrolled-window',
-                                                    'stack',
-                                                    'spinner',
-                                                    'treeview',
-                                                    'text-column',]);
-        this._stack = ui.stack;
-        this._scrolledWindow = ui.scrolledWindow;
-        this._spinner = ui.spinner;
-        this._treeView = ui.treeview;
-
-        let model = new Gtk.ListStore();
-        model.set_column_types([GdkPixbuf.Pixbuf,
-                                GObject.TYPE_OBJECT,
-                                GObject.TYPE_STRING]);
-        this._treeView.model = model;
-
-        this._treeView.connect('row-activated',
-                               this._onRowActivated.bind(this));
-        let cellHeight = ui.textColumn.cell_get_size(null)[3];
-        this.height_request = cellHeight * this._numVisible;
-        this._scrolledWindow.set_min_content_height(this.height_request);
+        this._maxChars = props.maxChars;
+        delete props.maxChars;
 
         this.parent(props);
 
-        this.get_style_context().add_class('maps-popover');
-        this.add(this._stack);
-        this.hide();
-    },
-
-    _onRowActivated: function(widget, path, column) {
-        let model = this._treeView.model;
-        let iter_valid, iter;
-
-        if (model === null)
-            return;
-
-        [iter_valid, iter] = model.get_iter(path);
-        if (!iter_valid)
-            return;
+        this._list.connect('row-activated', (function(list, row) {
+            if (row)
+                this.emit('selected', row.place);
+        }).bind(this));
 
-        this.emit('selected', model.get_value(iter, Columns.PLACE));
+        this._scrolledWindow.min_content_height = numVisible * _ROW_HEIGHT;
     },
 
     showSpinner: function() {
@@ -105,12 +119,7 @@ const SearchPopup = new Lang.Class({
         if (!this.get_visible())
             this.show();
 
-        this._treeView.grab_focus();
-    },
-
-    vfunc_show: function() {
-        this._treeView.columns_autosize();
-        this.parent();
+        this.grab_focus();
     },
 
     vfunc_hide: function() {
@@ -121,45 +130,18 @@ const SearchPopup = new Lang.Class({
     },
 
     updateResult: function(places, searchString) {
-        let model = this._treeView.get_model();
-
-        model.clear();
+        this._list.forall(function(row) {
+            row.destroy();
+        });
 
         places.forEach((function(place) {
             if (!place.location)
                 return;
-
-            let iter = model.append();
-            let location = place.get_location();
-            let icon = place.icon;
-
-            let description = GLib.markup_escape_text(location.description, -1);
-            description = this._boldMatch(description, searchString);
-
-            model.set(iter,
-                      [Columns.DESCRIPTION,
-                       Columns.PLACE],
-                      [description,
-                       place]);
-
-            if (icon !== null) {
-                Utils.load_icon(icon, _PLACE_ICON_SIZE, function(pixbuf) {
-                    model.set(iter, [Columns.ICON], [pixbuf]);
-                });
-            }
+            let row = new SearchPopupRow({ place: place,
+                                           searchString: searchString,
+                                           maxChars: this._maxChars,
+                                           can_focus: true });
+            this._list.add(row);
         }).bind(this));
-    },
-
-    _boldMatch: function(description, searchString) {
-        searchString = searchString.toLowerCase();
-
-        let index = description.toLowerCase().indexOf(searchString);
-
-        if (index !== -1) {
-            let substring = description.substring(index,
-                                                  index + searchString.length);
-            description = description.replace(substring, substring.bold());
-        }
-        return description;
     }
 });
diff --git a/src/sidebar.js b/src/sidebar.js
index 870a0a7..5434c53 100644
--- a/src/sidebar.js
+++ b/src/sidebar.js
@@ -171,7 +171,8 @@ const Sidebar = new Lang.Class({
                                            hexpand: true,
                                            receives_default: true,
                                            mapView: this._mapView,
-                                           parseOnFocusOut: true });
+                                           parseOnFocusOut: true,
+                                           maxChars: 15 });
     },
 
     _createViaRow: function(listbox, index) {


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