/* overviewControls.js
 *
 * 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 2 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/>.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

/* exported SlideDirection, SlideLayout */

import Clutter from 'gi://Clutter';
import GObject from 'gi://GObject';

function getRtlSlideDirection(direction, actor) {
    let rtl = actor.text_direction === Clutter.TextDirection.RTL;
    if (rtl) direction = direction === SlideDirection.LEFT ? SlideDirection.RIGHT : SlideDirection.LEFT;
    return direction;
}

export const SlideDirection = {
    LEFT: 0,
    RIGHT: 1,
};

export const SlideLayout = GObject.registerClass({
    Properties: {
        'slide-x': GObject.ParamSpec.double('slide-x', 'slide-x', 'slide-x', GObject.ParamFlags.READWRITE, 0, 1, 1),
    },
}, class SlideLayout extends Clutter.FixedLayout {
    _init(params) {
        this._slideX = 1;
        this._direction = SlideDirection.LEFT;
        super._init(params);
    }

    vfunc_get_preferred_width(container, forHeight) {
        let child = container.get_first_child();
        let [minWidth, natWidth] = child.get_preferred_width(forHeight);
        minWidth *= this._slideX;
        natWidth *= this._slideX;
        return [minWidth, natWidth];
    }

    vfunc_allocate(container, box) {
        let child = container.get_first_child();
        let availWidth = Math.round(box.x2 - box.x1);
        let availHeight = Math.round(box.y2 - box.y1);
        let [, natWidth] = child.get_preferred_width(availHeight);
        // Align the actor inside the clipped box, as the actor's alignment
        // flags only determine what to do if the allocated box is bigger
        // than the actor's box.
        let realDirection = getRtlSlideDirection(this._direction, child);
        let alignX = realDirection === SlideDirection.LEFT ? availWidth - natWidth : availWidth - natWidth * this._slideX;
        let actorBox = new Clutter.ActorBox();
        actorBox.x1 = box.x1 + alignX;
        actorBox.x2 = actorBox.x1 + (child.x_expand ? availWidth : natWidth);
        actorBox.y1 = box.y1;
        actorBox.y2 = actorBox.y1 + availHeight;
        child.allocate(actorBox);
    }

    // eslint-disable-next-line camelcase
    set slide_x(value) {
        if (this._slideX === value) return;
        this._slideX = value;
        this.notify('slide-x');
        this.layout_changed();
    }

    // eslint-disable-next-line camelcase
    get slide_x() {
        return this._slideX;
    }

    set slideDirection(direction) {
        this._direction = direction;
        this.layout_changed();
    }

    get slideDirection() {
        return this._direction;
    }
});
