/* -*- Mode: JS2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- */
/* vim: set et ts=4 sw=4: */
/*
* Copyright (c) 2016 Marcus Lundblad.
*
* GNOME Maps 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 2 of the License, or (at your
* option) any later version.
*
* GNOME Maps 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 GNOME Maps; if not, see .
*
* Author: Marcus Lundblad
* Jonas Danielsson
*/
import Gdk from 'gi://Gdk';
import GObject from 'gi://GObject';
import Gtk from 'gi://Gtk';
/* Abstract search result popover that progagates keypress events from a
focus-taking internal widget to the spawning search entry widget */
export class SearchPopover extends Gtk.Popover {
constructor(props) {
super(props);
this._entry = this.relative_to;
// We need to propagate events to the listbox so that we can
// keep typing while selecting a place. But we do not want to
// propagate the 'enter' key press if there is a selection.
this._keyController =
new Gtk.EventControllerKey({ widget: this._entry });
this._keyController.connect('key-pressed',
this._propagateKeys.bind(this));
this._buttonPressGesture = new Gtk.GestureSingle({ widget: this._entry });
this._buttonPressGesture.connect('begin',
() => this._list.unselect_all());
}
_propagateKeys(controller, keyval, keycode, state) {
if (keyval === Gdk.KEY_Escape) {
this.hide();
this._list.unselect_all();
return true;
}
if (keyval === Gdk.KEY_Return ||
keyval === Gdk.KEY_KP_ENTER ||
keyval === Gdk.KEY_ISO_Enter) {
// If we get an 'enter' keypress and we have a selected
// row, we do not want to propagate the event.
let row = this._list.get_selected_row();
if (this.visible && row) {
row.activate();
return true;
} else {
return false;
}
}
if (keyval === Gdk.KEY_KP_Up ||
keyval === Gdk.KEY_Up ||
keyval === Gdk.KEY_KP_Down ||
keyval === Gdk.KEY_Down) {
let length = this._list.get_children().length;
if (length === 0) {
return false;
}
let direction = (keyval === Gdk.KEY_KP_Up || keyval === Gdk.KEY_Up) ? -1 : 1;
let row = this._list.get_selected_row();
let idx;
if (!row) {
idx = (direction === 1) ? 0 : length - 1;
} else {
idx = row.get_index() + direction;
}
let inBounds = 0 <= idx && idx < length;
if (inBounds) {
this.show();
this._selectRow(this._list.get_row_at_index(idx));
} else {
this._list.unselect_all();
}
return true;
}
return false;
}
/* Selects given row and ensures that it is visible. */
_selectRow(row) {
this._list.select_row(row);
let adjustment = this._list.get_adjustment();
if (adjustment) {
let allocation = row.get_allocation();
adjustment.clamp_page(allocation.y, allocation.y + allocation.height);
}
}
}
GObject.registerClass({
Abstract: true
}, SearchPopover);