Blame js/ui/ibusCandidatePopup.js

Packit Service ed5168
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
Packit Service ed5168
Packit Service ed5168
const { Clutter, IBus, St } = imports.gi;
Packit Service ed5168
const Signals = imports.signals;
Packit Service ed5168
Packit Service ed5168
const BoxPointer = imports.ui.boxpointer;
Packit Service ed5168
const Main = imports.ui.main;
Packit Service ed5168
Packit Service ed5168
var MAX_CANDIDATES_PER_PAGE = 16;
Packit Service ed5168
Packit Service ed5168
var DEFAULT_INDEX_LABELS = [ '1', '2', '3', '4', '5', '6', '7', '8',
Packit Service ed5168
                             '9', '0', 'a', 'b', 'c', 'd', 'e', 'f' ];
Packit Service ed5168
Packit Service ed5168
var CandidateArea = class CandidateArea {
Packit Service ed5168
    constructor() {
Packit Service ed5168
        this.actor = new St.BoxLayout({ vertical: true,
Packit Service ed5168
                                        reactive: true,
Packit Service ed5168
                                        visible: false });
Packit Service ed5168
        this._candidateBoxes = [];
Packit Service ed5168
        for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
Packit Service ed5168
            let box = new St.BoxLayout({ style_class: 'candidate-box',
Packit Service ed5168
                                         reactive: true,
Packit Service ed5168
                                         track_hover: true });
Packit Service ed5168
            box._indexLabel = new St.Label({ style_class: 'candidate-index' });
Packit Service ed5168
            box._candidateLabel = new St.Label({ style_class: 'candidate-label' });
Packit Service ed5168
            box.add(box._indexLabel, { y_fill: false });
Packit Service ed5168
            box.add(box._candidateLabel, { y_fill: false });
Packit Service ed5168
            this._candidateBoxes.push(box);
Packit Service ed5168
            this.actor.add(box);
Packit Service ed5168
Packit Service ed5168
            let j = i;
Packit Service ed5168
            box.connect('button-release-event', (actor, event) => {
Packit Service ed5168
                this.emit('candidate-clicked', j, event.get_button(), event.get_state());
Packit Service ed5168
                return Clutter.EVENT_PROPAGATE;
Packit Service ed5168
            });
Packit Service ed5168
        }
Packit Service ed5168
Packit Service ed5168
        this.actor.connect('scroll-event', (actor, event) => {
Packit Service ed5168
            let direction = event.get_scroll_direction();
Packit Service ed5168
            switch(direction) {
Packit Service ed5168
            case Clutter.ScrollDirection.UP:
Packit Service ed5168
                this.emit('cursor-up');
Packit Service ed5168
                break;
Packit Service ed5168
            case Clutter.ScrollDirection.DOWN:
Packit Service ed5168
                this.emit('cursor-down');
Packit Service ed5168
                break;
Packit Service ed5168
            };
Packit Service ed5168
            return Clutter.EVENT_PROPAGATE;
Packit Service ed5168
        });
Packit Service ed5168
Packit Service ed5168
        this._buttonBox = new St.BoxLayout({ style_class: 'candidate-page-button-box' });
Packit Service ed5168
Packit Service ed5168
        this._previousButton = new St.Button({ style_class: 'candidate-page-button candidate-page-button-previous button' });
Packit Service ed5168
        this._previousButton.child = new St.Icon({ style_class: 'candidate-page-button-icon' });
Packit Service ed5168
        this._buttonBox.add(this._previousButton, { expand: true });
Packit Service ed5168
Packit Service ed5168
        this._nextButton = new St.Button({ style_class: 'candidate-page-button candidate-page-button-next button' });
Packit Service ed5168
        this._nextButton.child = new St.Icon({ style_class: 'candidate-page-button-icon' });
Packit Service ed5168
        this._buttonBox.add(this._nextButton, { expand: true });
Packit Service ed5168
Packit Service ed5168
        this.actor.add(this._buttonBox);
Packit Service ed5168
Packit Service ed5168
        this._previousButton.connect('clicked', () => {
Packit Service ed5168
            this.emit('previous-page');
Packit Service ed5168
        });
Packit Service ed5168
        this._nextButton.connect('clicked', () => {
Packit Service ed5168
            this.emit('next-page');
Packit Service ed5168
        });
Packit Service ed5168
Packit Service ed5168
        this._orientation = -1;
Packit Service ed5168
        this._cursorPosition = 0;
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    setOrientation(orientation) {
Packit Service ed5168
        if (this._orientation == orientation)
Packit Service ed5168
            return;
Packit Service ed5168
Packit Service ed5168
        this._orientation = orientation;
Packit Service ed5168
Packit Service ed5168
        if (this._orientation == IBus.Orientation.HORIZONTAL) {
Packit Service ed5168
            this.actor.vertical = false;
Packit Service ed5168
            this.actor.remove_style_class_name('vertical');
Packit Service ed5168
            this.actor.add_style_class_name('horizontal');
Packit Service ed5168
            this._previousButton.child.icon_name = 'go-previous-symbolic';
Packit Service ed5168
            this._nextButton.child.icon_name = 'go-next-symbolic';
Packit Service ed5168
        } else {                // VERTICAL || SYSTEM
Packit Service ed5168
            this.actor.vertical = true;
Packit Service ed5168
            this.actor.add_style_class_name('vertical');
Packit Service ed5168
            this.actor.remove_style_class_name('horizontal');
Packit Service ed5168
            this._previousButton.child.icon_name = 'go-up-symbolic';
Packit Service ed5168
            this._nextButton.child.icon_name = 'go-down-symbolic';
Packit Service ed5168
        }
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    setCandidates(indexes, candidates, cursorPosition, cursorVisible) {
Packit Service ed5168
        for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
Packit Service ed5168
            let visible = i < candidates.length;
Packit Service ed5168
            let box = this._candidateBoxes[i];
Packit Service ed5168
            box.visible = visible;
Packit Service ed5168
Packit Service ed5168
            if (!visible)
Packit Service ed5168
                continue;
Packit Service ed5168
Packit Service ed5168
            box._indexLabel.text = ((indexes && indexes[i]) ? indexes[i] : DEFAULT_INDEX_LABELS[i]);
Packit Service ed5168
            box._candidateLabel.text = candidates[i];
Packit Service ed5168
        }
Packit Service ed5168
Packit Service ed5168
        this._candidateBoxes[this._cursorPosition].remove_style_pseudo_class('selected');
Packit Service ed5168
        this._cursorPosition = cursorPosition;
Packit Service ed5168
        if (cursorVisible)
Packit Service ed5168
            this._candidateBoxes[cursorPosition].add_style_pseudo_class('selected');
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    updateButtons(wrapsAround, page, nPages) {
Packit Service ed5168
        if (nPages < 2) {
Packit Service ed5168
            this._buttonBox.hide();
Packit Service ed5168
            return;
Packit Service ed5168
        }
Packit Service ed5168
        this._buttonBox.show();
Packit Service ed5168
        this._previousButton.reactive = wrapsAround || page > 0;
Packit Service ed5168
        this._nextButton.reactive = wrapsAround || page < nPages - 1;
Packit Service ed5168
    }
Packit Service ed5168
};
Packit Service ed5168
Signals.addSignalMethods(CandidateArea.prototype);
Packit Service ed5168
Packit Service ed5168
var CandidatePopup = class CandidatePopup {
Packit Service ed5168
    constructor() {
Packit Service ed5168
        this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP);
Packit Service ed5168
        this._boxPointer.visible = false;
Packit Service ed5168
        this._boxPointer.style_class = 'candidate-popup-boxpointer';
Packit Service ed5168
        Main.layoutManager.addChrome(this._boxPointer);
Packit Service ed5168
Packit Service ed5168
        let box = new St.BoxLayout({ style_class: 'candidate-popup-content',
Packit Service ed5168
                                     vertical: true });
Packit Service ed5168
        this._boxPointer.bin.set_child(box);
Packit Service ed5168
Packit Service ed5168
        this._preeditText = new St.Label({ style_class: 'candidate-popup-text',
Packit Service ed5168
                                           visible: false });
Packit Service ed5168
        box.add(this._preeditText);
Packit Service ed5168
Packit Service ed5168
        this._auxText = new St.Label({ style_class: 'candidate-popup-text',
Packit Service ed5168
                                       visible: false });
Packit Service ed5168
        box.add(this._auxText);
Packit Service ed5168
Packit Service ed5168
        this._candidateArea = new CandidateArea();
Packit Service ed5168
        box.add(this._candidateArea.actor);
Packit Service ed5168
Packit Service ed5168
        this._candidateArea.connect('previous-page', () => {
Packit Service ed5168
            this._panelService.page_up();
Packit Service ed5168
        });
Packit Service ed5168
        this._candidateArea.connect('next-page', () => {
Packit Service ed5168
            this._panelService.page_down();
Packit Service ed5168
        });
Packit Service ed5168
Packit Service ed5168
        this._candidateArea.connect('cursor-up', () => {
Packit Service ed5168
            this._panelService.cursor_up();
Packit Service ed5168
        });
Packit Service ed5168
        this._candidateArea.connect('cursor-down', () => {
Packit Service ed5168
            this._panelService.cursor_down();
Packit Service ed5168
        });
Packit Service ed5168
Packit Service ed5168
        this._candidateArea.connect('candidate-clicked', (area, index, button, state) => {
Packit Service ed5168
            this._panelService.candidate_clicked(index, button, state);
Packit Service ed5168
        });
Packit Service ed5168
Packit Service ed5168
        this._panelService = null;
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    setPanelService(panelService) {
Packit Service ed5168
        this._panelService = panelService;
Packit Service ed5168
        if (!panelService)
Packit Service ed5168
            return;
Packit Service ed5168
Packit Service ed5168
        panelService.connect('set-cursor-location', (ps, x, y, w, h) => {
Packit Service ed5168
            this._setDummyCursorGeometry(x, y, w, h);
Packit Service ed5168
        });
Packit Service ed5168
        try {
Packit Service ed5168
            panelService.connect('set-cursor-location-relative', (ps, x, y, w, h) => {
Packit Service ed5168
                if (!global.display.focus_window)
Packit Service ed5168
                    return;
Packit Service ed5168
                let window = global.display.focus_window.get_compositor_private();
Packit Service ed5168
                this._setDummyCursorGeometry(window.x + x, window.y + y, w, h);
Packit Service ed5168
            });
Packit Service ed5168
        } catch(e) {
Packit Service ed5168
            // Only recent IBus versions have support for this signal
Packit Service ed5168
            // which is used for wayland clients. In order to work
Packit Service ed5168
            // with older IBus versions we can silently ignore the
Packit Service ed5168
            // signal's absence.
Packit Service ed5168
        }
Packit Service ed5168
        panelService.connect('update-preedit-text', (ps, text, cursorPosition, visible) => {
Packit Service ed5168
            this._preeditText.visible = visible;
Packit Service ed5168
            this._updateVisibility();
Packit Service ed5168
Packit Service ed5168
            this._preeditText.text = text.get_text();
Packit Service ed5168
Packit Service ed5168
            let attrs = text.get_attributes();
Packit Service ed5168
            if (attrs)
Packit Service ed5168
                this._setTextAttributes(this._preeditText.clutter_text,
Packit Service ed5168
                                        attrs);
Packit Service ed5168
        });
Packit Service ed5168
        panelService.connect('show-preedit-text', ps => {
Packit Service ed5168
            this._preeditText.show();
Packit Service ed5168
            this._updateVisibility();
Packit Service ed5168
        });
Packit Service ed5168
        panelService.connect('hide-preedit-text', ps => {
Packit Service ed5168
            this._preeditText.hide();
Packit Service ed5168
            this._updateVisibility();
Packit Service ed5168
        });
Packit Service ed5168
        panelService.connect('update-auxiliary-text', (ps, text, visible) => {
Packit Service ed5168
            this._auxText.visible = visible;
Packit Service ed5168
            this._updateVisibility();
Packit Service ed5168
Packit Service ed5168
            this._auxText.text = text.get_text();
Packit Service ed5168
        });
Packit Service ed5168
        panelService.connect('show-auxiliary-text', ps => {
Packit Service ed5168
            this._auxText.show();
Packit Service ed5168
            this._updateVisibility();
Packit Service ed5168
        });
Packit Service ed5168
        panelService.connect('hide-auxiliary-text', ps => {
Packit Service ed5168
            this._auxText.hide();
Packit Service ed5168
            this._updateVisibility();
Packit Service ed5168
        });
Packit Service ed5168
        panelService.connect('update-lookup-table', (ps, lookupTable, visible) => {
Packit Service ed5168
            this._candidateArea.actor.visible = visible;
Packit Service ed5168
            this._updateVisibility();
Packit Service ed5168
Packit Service ed5168
            let nCandidates = lookupTable.get_number_of_candidates();
Packit Service ed5168
            let cursorPos = lookupTable.get_cursor_pos();
Packit Service ed5168
            let pageSize = lookupTable.get_page_size();
Packit Service ed5168
            let nPages = Math.ceil(nCandidates / pageSize);
Packit Service ed5168
            let page = ((cursorPos == 0) ? 0 : Math.floor(cursorPos / pageSize));
Packit Service ed5168
            let startIndex = page * pageSize;
Packit Service ed5168
            let endIndex = Math.min((page + 1) * pageSize, nCandidates);
Packit Service ed5168
Packit Service ed5168
            let indexes = [];
Packit Service ed5168
            let indexLabel;
Packit Service ed5168
            for (let i = 0; (indexLabel = lookupTable.get_label(i)); ++i)
Packit Service ed5168
                 indexes.push(indexLabel.get_text());
Packit Service ed5168
Packit Service ed5168
            Main.keyboard.resetSuggestions();
Packit Service ed5168
Packit Service ed5168
            let candidates = [];
Packit Service ed5168
            for (let i = startIndex; i < endIndex; ++i) {
Packit Service ed5168
                candidates.push(lookupTable.get_candidate(i).get_text());
Packit Service ed5168
Packit Service ed5168
                Main.keyboard.addSuggestion(lookupTable.get_candidate(i).get_text(), () => {
Packit Service ed5168
                    let index = i;
Packit Service ed5168
                    this._panelService.candidate_clicked(index, 1, 0);
Packit Service ed5168
                });
Packit Service ed5168
            }
Packit Service ed5168
Packit Service ed5168
            this._candidateArea.setCandidates(indexes,
Packit Service ed5168
                                              candidates,
Packit Service ed5168
                                              cursorPos % pageSize,
Packit Service ed5168
                                              lookupTable.is_cursor_visible());
Packit Service ed5168
            this._candidateArea.setOrientation(lookupTable.get_orientation());
Packit Service ed5168
            this._candidateArea.updateButtons(lookupTable.is_round(), page, nPages);
Packit Service ed5168
        });
Packit Service ed5168
        panelService.connect('show-lookup-table', ps => {
Packit Service ed5168
            this._candidateArea.actor.show();
Packit Service ed5168
            this._updateVisibility();
Packit Service ed5168
        });
Packit Service ed5168
        panelService.connect('hide-lookup-table', ps => {
Packit Service ed5168
            this._candidateArea.actor.hide();
Packit Service ed5168
            this._updateVisibility();
Packit Service ed5168
        });
Packit Service ed5168
        panelService.connect('focus-out', ps => {
Packit Service ed5168
            this._boxPointer.close(BoxPointer.PopupAnimation.NONE);
Packit Service ed5168
            Main.keyboard.resetSuggestions();
Packit Service ed5168
        });
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _setDummyCursorGeometry(x, y, w, h) {
Packit Service ed5168
        Main.layoutManager.setDummyCursorGeometry(x, y, w, h);
Packit Service ed5168
        if (this._boxPointer.actor.visible)
Packit Service ed5168
            this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _updateVisibility() {
Packit Service ed5168
        let isVisible = (!Main.keyboard.visible &&
Packit Service ed5168
                         (this._preeditText.visible ||
Packit Service ed5168
                          this._auxText.visible ||
Packit Service ed5168
                          this._candidateArea.actor.visible));
Packit Service ed5168
Packit Service ed5168
        if (isVisible) {
Packit Service ed5168
            this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
Packit Service ed5168
            this._boxPointer.open(BoxPointer.PopupAnimation.NONE);
Packit Service ed5168
            this._boxPointer.actor.raise_top();
Packit Service ed5168
        } else {
Packit Service ed5168
            this._boxPointer.close(BoxPointer.PopupAnimation.NONE);
Packit Service ed5168
        }
Packit Service ed5168
    }
Packit Service ed5168
Packit Service ed5168
    _setTextAttributes(clutterText, ibusAttrList) {
Packit Service ed5168
        let attr;
Packit Service ed5168
        for (let i = 0; (attr = ibusAttrList.get(i)); ++i)
Packit Service ed5168
            if (attr.get_attr_type() == IBus.AttrType.BACKGROUND)
Packit Service ed5168
                clutterText.set_selection(attr.get_start_index(), attr.get_end_index());
Packit Service ed5168
    }
Packit Service ed5168
};