[gnome-characters/bilelmoussaoui/gtk4: 40/76] characters view: implement scrollable
- From: Bilal Elmoussaoui <bilelmoussaoui src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-characters/bilelmoussaoui/gtk4: 40/76] characters view: implement scrollable
- Date: Fri, 26 Nov 2021 08:59:06 +0000 (UTC)
commit 67eb70690e427ad68b90421f19204778cef28ec4
Author: Bilal Elmoussaoui <bil elmoussaoui gmail com>
Date: Mon Nov 22 19:20:32 2021 +0100
characters view: implement scrollable
Merge both CharactersView & CharactersListView into one
and make it a GtkScrollable
data/characters_view.ui | 10 -
data/meson.build | 1 -
data/org.gnome.Characters.data.gresource.xml | 1 -
data/window.ui | 2 +-
src/charactersView.js | 360 ++++++++++++---------------
src/sidebar.js | 1 -
src/window.js | 5 +-
7 files changed, 169 insertions(+), 211 deletions(-)
---
diff --git a/data/meson.build b/data/meson.build
index abd70fa..87da838 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -10,7 +10,6 @@ resource_data = files(
'icons/hicolor/scalable/categories/characters-punctuation-symbolic.svg',
'style.css',
'character_dialog.ui',
- 'characters_view.ui',
'menu.ui',
'shortcuts.ui',
'sidebar.ui',
diff --git a/data/org.gnome.Characters.data.gresource.xml b/data/org.gnome.Characters.data.gresource.xml
index 116d834..914073b 100644
--- a/data/org.gnome.Characters.data.gresource.xml
+++ b/data/org.gnome.Characters.data.gresource.xml
@@ -2,7 +2,6 @@
<gresources>
<gresource prefix="/org/gnome/Characters">
<file preprocess="xml-stripblanks">character_dialog.ui</file>
- <file preprocess="xml-stripblanks">characters_view.ui</file>
<file preprocess="xml-stripblanks" alias="gtk/help-overlay.ui">shortcuts.ui</file>
<file preprocess="xml-stripblanks">menu.ui</file>
<file preprocess="xml-stripblanks">sidebar.ui</file>
diff --git a/data/window.ui b/data/window.ui
index 13a42f9..6613b9a 100644
--- a/data/window.ui
+++ b/data/window.ui
@@ -149,7 +149,7 @@
<object class="GtkStackPage">
<property name="name">character-list</property>
<property name="child">
- <object class="GtkScrolledWindow">
+ <object class="GtkScrolledWindow" id="scrolledWindow">
<property name="hscrollbar-policy">never</property>
<child>
<object class="Gjs_CharactersView" id="charactersView" />
diff --git a/src/charactersView.js b/src/charactersView.js
index 4f5ce66..e144eac 100644
--- a/src/charactersView.js
+++ b/src/charactersView.js
@@ -182,20 +182,120 @@ const CharacterListRow = GObject.registerClass({
}
});
-const CharacterListWidget = GObject.registerClass({
+const MAX_SEARCH_RESULTS = 100;
+
+var FontFilter = GObject.registerClass({
+ Properties: {
+ 'font': GObject.ParamSpec.string(
+ 'font', '', '',
+ GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
+ 'Cantarell 50'),
+ },
+ Signals: {
+ 'filter-set': { param_types: [] },
+ },
+}, class FontFilter extends GObject.Object {
+ _init() {
+ super._init({});
+
+ this._fontDescription = null;
+ this._filterFontDescription = null;
+
+ Main.settings.bind('font', this, 'font', Gio.SettingsBindFlags.DEFAULT);
+ }
+
+ get font() {
+ return this._font;
+ }
+
+ set font(v) {
+ let fontDescription = Pango.FontDescription.from_string(v);
+ if (fontDescription.get_size() === 0)
+ fontDescription.set_size(CELL_SIZE * Pango.SCALE);
+
+ if (this._fontDescription &&
+ fontDescription.equal(this._fontDescription))
+ return;
+
+ this._font = v;
+ this._fontDescription = fontDescription;
+ }
+
+ get fontDescription() {
+ if (this._filterFontDescription)
+ return this._filterFontDescription;
+ return this._fontDescription;
+ }
+
+ setFilterFont(v) {
+ let fontDescription;
+ if (v === null) {
+ fontDescription = null;
+ } else {
+ fontDescription = Pango.FontDescription.from_string(v);
+ fontDescription.set_size(this._fontDescription.get_size());
+ }
+
+ if (this._filterFontDescription !== null && fontDescription === null ||
+ this._filterFontDescription === null && fontDescription !== null ||
+ this._filterFontDescription !== null && fontDescription !== null &&
+ !fontDescription.equal(this._filterFontDescription)) {
+ this._filterFontDescription = fontDescription;
+ this.emit('filter-set');
+ }
+ }
+
+ filter(widget, characters) {
+ let fontDescription = this._fontDescription;
+ if (this._filterFontDescription) {
+ let context = widget.get_pango_context();
+ let filterFont = context.load_font(this._filterFontDescription);
+ let filteredCharacters = [];
+ for (let index = 0; index < characters.length; index++) {
+ let uc = characters[index];
+ if (Gc.pango_context_font_has_glyph(context, filterFont, uc))
+ filteredCharacters.push(uc);
+ }
+ characters = filteredCharacters;
+ fontDescription = this._filterFontDescription;
+ }
+
+ return [fontDescription, characters];
+ }
+});
+
+var CharactersView = GObject.registerClass({
Signals: {
'character-selected': { param_types: [GObject.TYPE_STRING] },
},
-}, class CharacterListWidget extends Gtk.Widget {
- _init(numRows) {
+ Properties: {
+ 'vscroll-policy': GObject.ParamSpec.override('vscroll-policy', Gtk.Scrollable),
+ 'vadjustment': GObject.ParamSpec.override('vadjustment', Gtk.Scrollable),
+ 'hscroll-policy': GObject.ParamSpec.override('hscroll-policy', Gtk.Scrollable),
+ 'hadjustment': GObject.ParamSpec.override('hadjustment', Gtk.Scrollable),
+ },
+ Implements: [Gtk.Scrollable],
+}, class CharactersView extends Gtk.Widget {
+ _init() {
super._init({
- hexpand: true,
- vexpand: true,
+ vadjustment: new Gtk.Adjustment(),
+ hadjustment: new Gtk.Adjustment(),
});
- this.add_css_class('character-list');
- this._cellsPerRow = CELLS_PER_ROW;
- this._numRows = numRows;
+
+ this._selectedCharacter = null;
this._characters = [];
+ this._spinnerTimeoutId = 0;
+ this._searchContext = null;
+ this._cancellable = new Gio.Cancellable();
+ this._cancellable.connect(() => {
+ this._stopSpinner();
+ this._searchContext = null;
+ this._characters = [];
+ this._updateCharacterList();
+ });
+
+ this._cellsPerRow = CELLS_PER_ROW;
+ this._numRows = NUM_ROWS;
this._rows = [];
/* this.add_events(Gdk.EventMask.BUTTON_PRESS_MASK |
Gdk.EventMask.BUTTON_RELEASE_MASK);
@@ -208,9 +308,31 @@ const CharacterListWidget = GObject.registerClass({
gestureClick.connect('pressed', this.onButtonPress.bind(this));
gestureClick.connect('released', this.onButtonRelease.bind(this));
this.add_controller(gestureClick);
+ }
+
+ get vadjustment() {
+ return this._vadjustment;
+ }
+
+ set vadjustment(adj) {
+ adj.connect('value-changed', () => {
+ this.queue_draw();
+ });
+ this._vadjustment = adj;
+ }
+
+ get hadjustment() {
+ return this._hadjustment;
+ }
+
+ set hadjustment(adj) {
+ adj.connect('value-changed', () => {
+ this.queue_draw();
+ });
+ this._hadjustment = adj;
- this._character = null;
}
+
/*
vfunc_drag_begin(context) {
let cellSize = getCellSize(this._fontDescription);
@@ -233,21 +355,24 @@ const CharacterListWidget = GObject.registerClass({
*/
onButtonPress(gesture, nPress, x, y) {
+ let hadj = this.get_hadjustment();
+ let vadj = this.get_vadjustment();
+
let cellSize = getCellSize(this._fontDescription);
- x = Math.floor(x / cellSize);
- y = Math.floor(y / cellSize);
+ x = Math.floor((x + hadj.get_value()) / cellSize);
+ y = Math.floor((y + vadj.get_value()) / cellSize);
+
let index = y * this._cellsPerRow + x;
if (index < this._characters.length)
- this._character = this._characters[index];
+ this._selectedCharacter = this._characters[index];
else
- this._character = null;
+ this._selectedCharacter = null;
return false;
}
onButtonRelease() {
- if (this._character)
- this.emit('character-selected', this._character);
- log(this._character);
+ if (this._selectedCharacter)
+ this.emit('character-selected', this._selectedCharacter);
return false;
}
@@ -265,11 +390,14 @@ const CharacterListWidget = GObject.registerClass({
}
vfunc_snapshot(snapshot) {
- // Clear the canvas.
- let allocation = this.get_allocation();
+ let hadj = this.get_hadjustment();
+ let vadj = this.get_vadjustment();
let rect = new Graphene.Rect({
origin: new Graphene.Point({ x: 0, y: 0 }),
- size: new Graphene.Size({ width: allocation.width, height: allocation.height }),
+ size: new Graphene.Size({
+ width: hadj.get_page_size(),
+ height: vadj.get_page_size(),
+ }),
});
let cr = snapshot.append_cairo(rect);
@@ -277,18 +405,13 @@ const CharacterListWidget = GObject.registerClass({
let fg = context.get_color();
Gdk.cairo_set_source_rgba(cr, fg);
- // Use device coordinates directly, since PangoCairo doesn't
- // work well with scaled matrix:
- // https://bugzilla.gnome.org/show_bug.cgi?id=700592
-
- // Redraw rows within the clipped region.
- let [_, y1, __, y2] = cr.clipExtents();
let cellSize = getCellSize(this._fontDescription);
- let start = Math.max(0, Math.floor(y1 / cellSize));
- let end = Math.min(this._rows.length, Math.ceil(y2 / cellSize));
+ let start = Math.max(0, Math.floor(vadj.get_value() / cellSize));
+ let end = Math.min(this._rows.length, Math.ceil((vadj.get_value() + vadj.get_page_size()) /
cellSize));
+
for (let index = start; index < end; index++) {
- this._rows[index].draw(cr, 0, index * cellSize,
- allocation.width, cellSize, context);
+ this._rows[index].draw(cr, 0, (index - start) * cellSize,
+ this.get_allocation().width, cellSize, context);
}
}
@@ -298,9 +421,17 @@ const CharacterListWidget = GObject.registerClass({
vfunc_size_allocate(width, height, baseline) {
super.vfunc_size_allocate(width, height, baseline);
-
let cellSize = getCellSize(this._fontDescription);
let cellsPerRow = Math.floor(width / cellSize);
+
+ let maxHeight = Math.floor((this._rows.length + BASELINE_OFFSET) * cellSize);
+ let maxWidth = cellsPerRow * cellSize;
+
+ let hadj = this.get_hadjustment();
+ let vadj = this.get_vadjustment();
+ vadj.configure(vadj.get_value(), 0.0, maxHeight, 0.1 * height, 0.9 * height, height);
+ hadj.configure(hadj.get_value(), 0.0, maxWidth, 0.1 * width, 0.9 * width, width);
+
if (cellsPerRow !== this._cellsPerRow) {
// Reflow if the number of cells per row has changed.
this._cellsPerRow = cellsPerRow;
@@ -343,130 +474,9 @@ const CharacterListWidget = GObject.registerClass({
this.queue_resize();
this.queue_draw();
}
-});
-
-const MAX_SEARCH_RESULTS = 100;
-
-var FontFilter = GObject.registerClass({
- Properties: {
- 'font': GObject.ParamSpec.string(
- 'font', '', '',
- GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
- 'Cantarell 50'),
- },
- Signals: {
- 'filter-set': { param_types: [] },
- },
-}, class FontFilter extends GObject.Object {
- _init() {
- super._init({});
-
- this._fontDescription = null;
- this._filterFontDescription = null;
-
- Main.settings.bind('font', this, 'font', Gio.SettingsBindFlags.DEFAULT);
- }
-
- get font() {
- return this._font;
- }
-
- set font(v) {
- let fontDescription = Pango.FontDescription.from_string(v);
- if (fontDescription.get_size() === 0)
- fontDescription.set_size(CELL_SIZE * Pango.SCALE);
-
- if (this._fontDescription &&
- fontDescription.equal(this._fontDescription))
- return;
-
- this._font = v;
- this._fontDescription = fontDescription;
- }
-
- get fontDescription() {
- if (this._filterFontDescription)
- return this._filterFontDescription;
- return this._fontDescription;
- }
-
- setFilterFont(v) {
- let fontDescription;
- if (v === null) {
- fontDescription = null;
- } else {
- fontDescription = Pango.FontDescription.from_string(v);
- fontDescription.set_size(this._fontDescription.get_size());
- }
-
- if (this._filterFontDescription !== null && fontDescription === null ||
- this._filterFontDescription === null && fontDescription !== null ||
- this._filterFontDescription !== null && fontDescription !== null &&
- !fontDescription.equal(this._filterFontDescription)) {
- this._filterFontDescription = fontDescription;
- this.emit('filter-set');
- }
- }
-
- filter(widget, characters) {
- let fontDescription = this._fontDescription;
- if (this._filterFontDescription) {
- let context = widget.get_pango_context();
- let filterFont = context.load_font(this._filterFontDescription);
- let filteredCharacters = [];
- for (let index = 0; index < characters.length; index++) {
- let uc = characters[index];
- if (Gc.pango_context_font_has_glyph(context, filterFont, uc))
- filteredCharacters.push(uc);
- }
- characters = filteredCharacters;
- fontDescription = this._filterFontDescription;
- }
-
- return [fontDescription, characters];
- }
-});
-
-var CharactersView = GObject.registerClass({
- Template: 'resource:///org/gnome/Characters/characters_view.ui',
- Signals: {
- 'character-selected': { param_types: [GObject.TYPE_STRING] },
- },
- Properties: {
- 'model': GObject.ParamSpec.object(
- 'model',
- 'Characters List Model', 'Characters List Model',
- GObject.ParamFlags.READWRITE,
- Gio.ListModel.$gtype,
- ),
- },
-}, class CharactersView extends Adw.Bin {
- _init() {
- super._init();
-
- this._characterList = new CharacterListWidget(NUM_ROWS);
- this._characterList.connect('character-selected', (w, c) => this.emit('character-selected', c));
-
- this.set_child(this._characterList);
-
- this._characters = [];
- this._spinnerTimeoutId = 0;
- this._searchContext = null;
- this._cancellable = new Gio.Cancellable();
- this._cancellable.connect(() => {
- this._stopSpinner();
- this._searchContext = null;
- this._characters = [];
- this._updateCharacterList();
- });
- /* TODO: use listmodels & grid view hopefully
- scroll.connect('edge-reached', (scrolled, pos) => this._onEdgeReached(scrolled, pos));
- scroll.connect('size-allocate', (scrolled, allocation) => this._onSizeAllocate(scrolled,
allocation));
- */
- }
setFontFilter(fontFilter) {
- this._characterList.setFontDescription(fontFilter.fontDescription);
+ this.setFontDescription(fontFilter.fontDescription);
fontFilter.connect('filter-set', () => this._updateCharacterList());
this._fontFilter = fontFilter;
}
@@ -496,16 +506,11 @@ var CharactersView = GObject.registerClass({
this.setCharacters(characters);
}
- setCharacters(characters) {
- this._characters = characters;
- this._updateCharacterList();
- }
-
_updateCharacterList() {
log('Updating characters list');
const [fontDescription, characters] = this._fontFilter.filter(this, this._characters);
- this._characterList.setFontDescription(fontDescription);
- this._characterList.setCharacters(characters);
+ this.setFontDescription(fontDescription);
+ this.setCharacters(characters);
}
get initialSearchCount() {
@@ -575,40 +580,3 @@ var CharactersView = GObject.registerClass({
this._cancellable.reset();
}
});
-
-var RecentCharacterListView = GObject.registerClass({
- Signals: {
- 'character-selected': { param_types: [GObject.TYPE_STRING] },
- },
-}, class RecentCharacterListView extends Adw.Bin {
- _init(category) {
- super._init({
- hexpand: true, vexpand: false,
- });
-
- this._characterList = new CharacterListWidget(0);
- this._characterList.connect('character-selected', (w, c) => this.emit('character-selected', c));
- this.set_child(this._characterList);
-
- this._category = category;
- this._characters = [];
- }
-
- setFontFilter(fontFilter) {
- this._characterList.setFontDescription(fontFilter.fontDescription);
- fontFilter.connect('filter-set', () => this._updateCharacterList());
- this._fontFilter = fontFilter;
- }
-
- setCharacters(characters) {
- const result = Gc.filter_characters(this._category, characters);
- this._characters = Util.searchResultToArray(result);
- this._updateCharacterList();
- }
-
- _updateCharacterList() {
- const [fontDescription, characters] = this._fontFilter.filter(this, this._characters);
- this._characterList.setFontDescription(fontDescription);
- this._characterList.setCharacters(characters);
- }
-});
diff --git a/src/sidebar.js b/src/sidebar.js
index 8823f82..4283bd5 100644
--- a/src/sidebar.js
+++ b/src/sidebar.js
@@ -44,7 +44,6 @@ var Sidebar = GObject.registerClass({
restorePreviousSelection() {
if (this.lastSelectedRow)
this._list.select_row(this.lastSelectedRow);
-
}
rowByName(name) {
diff --git a/src/window.js b/src/window.js
index a777390..cffeea3 100644
--- a/src/window.js
+++ b/src/window.js
@@ -41,7 +41,7 @@ var MainWindow = GObject.registerClass({
'search-bar', 'search-entry', 'back-button',
'menuPopover', 'container', 'sidebar',
'leaflet', 'mainStack', 'windowTitle',
- 'charactersView',
+ 'charactersView', 'scrolledWindow',
],
Properties: {
'search-active': GObject.ParamSpec.boolean(
@@ -70,6 +70,9 @@ var MainWindow = GObject.registerClass({
this._sidebar.list.connect('row-selected', (sidebar, row) => {
+ const adj = this._scrolledWindow.get_vadjustment();
+ adj.set_value(0.0); // scroll back to the top
+ this._charactersView.queue_resize();
if (row) {
this._sidebar.lastSelectedRow = row;
this.setPage(row);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]