mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-30 07:42:23 +02:00
Add Gtk app
This commit is contained in:
62
clapper_src/app.js
Normal file
62
clapper_src/app.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
const { GLib, GObject, Gtk } = imports.gi;
|
||||||
|
const { Player } = imports.clapper_src.player;
|
||||||
|
const { Interface } = imports.clapper_src.interface;
|
||||||
|
|
||||||
|
const APP_NAME = 'Clapper';
|
||||||
|
|
||||||
|
var App = GObject.registerClass({
|
||||||
|
Signals: {
|
||||||
|
'player-ready': {
|
||||||
|
param_types: [GObject.TYPE_BOOLEAN]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, class ClapperApp extends Gtk.Application
|
||||||
|
{
|
||||||
|
_init(args)
|
||||||
|
{
|
||||||
|
GLib.set_prgname(APP_NAME);
|
||||||
|
|
||||||
|
super._init();
|
||||||
|
|
||||||
|
this.connect('startup', () => this._buildUI());
|
||||||
|
this.connect('activate', () => this._openDialog());
|
||||||
|
}
|
||||||
|
|
||||||
|
run(arr)
|
||||||
|
{
|
||||||
|
arr = arr || [];
|
||||||
|
super.run(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildUI()
|
||||||
|
{
|
||||||
|
this.appWindow = new Gtk.ApplicationWindow({
|
||||||
|
application: this,
|
||||||
|
title: APP_NAME,
|
||||||
|
border_width: 0,
|
||||||
|
resizable: true,
|
||||||
|
window_position: Gtk.WindowPosition.CENTER,
|
||||||
|
width_request: 960,
|
||||||
|
height_request: 642
|
||||||
|
});
|
||||||
|
|
||||||
|
this.interface = new Interface();
|
||||||
|
|
||||||
|
this.appWindow.add(this.interface);
|
||||||
|
this.appWindow.connect('realize', this._onRealize.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
_onRealize()
|
||||||
|
{
|
||||||
|
this.player = new Player();
|
||||||
|
this.interface.addPlayer(this.player);
|
||||||
|
|
||||||
|
this.player.widget.show_all();
|
||||||
|
this.emit('player-ready', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
_openDialog()
|
||||||
|
{
|
||||||
|
this.appWindow.show_all();
|
||||||
|
}
|
||||||
|
});
|
92
clapper_src/controls.js
vendored
Normal file
92
clapper_src/controls.js
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
const { GObject, Gtk } = imports.gi;
|
||||||
|
|
||||||
|
var Controls = GObject.registerClass(
|
||||||
|
class ClapperControls extends Gtk.HBox
|
||||||
|
{
|
||||||
|
_init()
|
||||||
|
{
|
||||||
|
super._init({
|
||||||
|
margin_top: 4,
|
||||||
|
margin_bottom: 4
|
||||||
|
});
|
||||||
|
|
||||||
|
this.togglePlayButton = Gtk.Button.new_from_icon_name(
|
||||||
|
'media-playback-pause-symbolic',
|
||||||
|
Gtk.IconSize.LARGE_TOOLBAR
|
||||||
|
);
|
||||||
|
this.pauseButton = Gtk.Button.new_from_icon_name(
|
||||||
|
'media-playback-start-symbolic',
|
||||||
|
Gtk.IconSize.LARGE_TOOLBAR
|
||||||
|
);
|
||||||
|
this.playImage = this.pauseButton.image;
|
||||||
|
this.pauseImage = this.togglePlayButton.image;
|
||||||
|
|
||||||
|
this.positionScale = new Gtk.Scale({
|
||||||
|
orientation: Gtk.Orientation.HORIZONTAL,
|
||||||
|
value_pos: Gtk.PositionType.LEFT,
|
||||||
|
draw_value: false
|
||||||
|
});
|
||||||
|
|
||||||
|
this.volumeButton = new Gtk.ScaleButton({
|
||||||
|
size: Gtk.IconSize.SMALL_TOOLBAR
|
||||||
|
});
|
||||||
|
this._prepareVolumeButton();
|
||||||
|
|
||||||
|
this.pack_start(this.togglePlayButton, false, false, 4);
|
||||||
|
this.pack_start(this.positionScale, true, true, 0);
|
||||||
|
this.pack_start(this.volumeButton, false, false, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
_prepareVolumeButton()
|
||||||
|
{
|
||||||
|
this.volumeButtonAdjustment = this.volumeButton.get_adjustment();
|
||||||
|
|
||||||
|
this.volumeButtonAdjustment.set_upper(2);
|
||||||
|
this.volumeButtonAdjustment.set_step_increment(0.05);
|
||||||
|
this.volumeButtonAdjustment.set_page_increment(0.05);
|
||||||
|
|
||||||
|
let basicIcons = [
|
||||||
|
"audio-volume-low-symbolic",
|
||||||
|
"audio-volume-medium-symbolic",
|
||||||
|
"audio-volume-medium-symbolic",
|
||||||
|
"audio-volume-high-symbolic"
|
||||||
|
];
|
||||||
|
|
||||||
|
let iconsArr = [
|
||||||
|
"audio-volume-muted-symbolic"
|
||||||
|
];
|
||||||
|
|
||||||
|
for(let icon of basicIcons)
|
||||||
|
iconsArr = this._addManyToArr(icon, iconsArr, 5);
|
||||||
|
|
||||||
|
iconsArr = this._addManyToArr(
|
||||||
|
"audio-volume-overamplified-symbolic", iconsArr, 18
|
||||||
|
);
|
||||||
|
|
||||||
|
this.volumeButton.set_icons(iconsArr);
|
||||||
|
|
||||||
|
let popup = this.volumeButton.get_popup();
|
||||||
|
let box = popup.get_child();
|
||||||
|
let boxChildren = box.get_children();
|
||||||
|
|
||||||
|
for(let child of boxChildren) {
|
||||||
|
if(child.constructor === Gtk.Button)
|
||||||
|
box.remove(child);
|
||||||
|
if(child.constructor === Gtk.Scale) {
|
||||||
|
child.height_request = 200;
|
||||||
|
child.add_mark(0, Gtk.PositionType.LEFT, '0%');
|
||||||
|
child.add_mark(1, Gtk.PositionType.LEFT, '100%');
|
||||||
|
child.add_mark(2, Gtk.PositionType.LEFT, '200%');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_addManyToArr(item, arr, count)
|
||||||
|
{
|
||||||
|
for(let i = 0; i < count; i++) {
|
||||||
|
arr.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
});
|
124
clapper_src/interface.js
Normal file
124
clapper_src/interface.js
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
const { GObject, Gtk, GstPlayer } = imports.gi;
|
||||||
|
const { Controls } = imports.clapper_src.controls;
|
||||||
|
|
||||||
|
var Interface = GObject.registerClass(
|
||||||
|
class ClapperInterface extends Gtk.Grid
|
||||||
|
{
|
||||||
|
_init()
|
||||||
|
{
|
||||||
|
super._init();
|
||||||
|
|
||||||
|
this.lastPositionValue = 0;
|
||||||
|
|
||||||
|
this.controls = new Controls();
|
||||||
|
this.attach(this.controls, 0, 1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
addPlayer(player)
|
||||||
|
{
|
||||||
|
this._player = player;
|
||||||
|
this._player.widget.expand = true;
|
||||||
|
this._connectControlsToPlayer();
|
||||||
|
|
||||||
|
this.attach(this._player.widget, 0, 0, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_connectControlsToPlayer()
|
||||||
|
{
|
||||||
|
this._player.connect('state-changed', this._onPlayerStateChanged.bind(this));
|
||||||
|
this._player.connect('volume-changed', this._onPlayerVolumeChanged.bind(this));
|
||||||
|
this._player.connect('duration-changed', this._onPlayerDurationChanged.bind(this));
|
||||||
|
this._player.connect('position-updated', this._onPlayerPositionUpdated.bind(this));
|
||||||
|
|
||||||
|
this.controls.togglePlayButton.connect(
|
||||||
|
'clicked', this._onControlsTogglePlayClicked.bind(this)
|
||||||
|
);
|
||||||
|
this.controls.positionScale.connect(
|
||||||
|
'value-changed', this._onControlsPositionChanged.bind(this)
|
||||||
|
);
|
||||||
|
this.controls.volumeButton.connect(
|
||||||
|
'value-changed', this._onControlsVolumeChanged.bind(this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPlayerStateChanged(player, state)
|
||||||
|
{
|
||||||
|
switch(state) {
|
||||||
|
case GstPlayer.PlayerState.STOPPED:
|
||||||
|
break;
|
||||||
|
case GstPlayer.PlayerState.BUFFERING:
|
||||||
|
break;
|
||||||
|
case GstPlayer.PlayerState.PAUSED:
|
||||||
|
this.controls.togglePlayButton.image = this.controls.playImage;
|
||||||
|
break;
|
||||||
|
case GstPlayer.PlayerState.PLAYING:
|
||||||
|
this.controls.togglePlayButton.image = this.controls.pauseImage;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPlayerDurationChanged(player)
|
||||||
|
{
|
||||||
|
let duration = player.get_duration() / 1000000000;
|
||||||
|
let increment = (duration < 1)
|
||||||
|
? 0
|
||||||
|
: (duration < 100)
|
||||||
|
? 1
|
||||||
|
: duration / 100;
|
||||||
|
|
||||||
|
let adjustment = new Gtk.Adjustment({
|
||||||
|
upper: duration,
|
||||||
|
step_increment: increment,
|
||||||
|
page_increment: increment
|
||||||
|
});
|
||||||
|
this.controls.positionScale.set_adjustment(adjustment);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPlayerPositionUpdated(player, position)
|
||||||
|
{
|
||||||
|
let positionSeconds = position / 1000000000;
|
||||||
|
let positionFloor = Math.floor(positionSeconds);
|
||||||
|
|
||||||
|
if(positionFloor === this.lastPositionValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.lastPositionValue = positionFloor;
|
||||||
|
this.controls.positionScale.set_value(positionSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPlayerVolumeChanged(player)
|
||||||
|
{
|
||||||
|
let volume = player.get_volume();
|
||||||
|
|
||||||
|
if(this.controls.volumeButton.value === volume)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.controls.volumeButton.value = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
_onControlsTogglePlayClicked()
|
||||||
|
{
|
||||||
|
this._player.toggle_play();
|
||||||
|
}
|
||||||
|
|
||||||
|
_onControlsPositionChanged(range)
|
||||||
|
{
|
||||||
|
let position = Math.floor(range.get_value());
|
||||||
|
|
||||||
|
if(position === this.lastPositionValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.lastPositionValue = position;
|
||||||
|
this._player.seek_seconds(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onControlsVolumeChanged(widget, value)
|
||||||
|
{
|
||||||
|
if(this._player.get_volume() === value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._player.set_volume(value);
|
||||||
|
}
|
||||||
|
});
|
@@ -1,10 +1,19 @@
|
|||||||
const { GLib, GObject, Gst, GstPlayer } = imports.gi;
|
const { GLib, GObject, Gst, GstPlayer } = imports.gi;
|
||||||
|
|
||||||
var GtkPlayer = GObject.registerClass(
|
const DEFAULTS = {
|
||||||
class GtkPlayer extends GstPlayer.Player
|
position_update_interval: 1000,
|
||||||
|
seek_accurate: false,
|
||||||
|
user_agent: 'clapper',
|
||||||
|
};
|
||||||
|
|
||||||
|
var Player = GObject.registerClass(
|
||||||
|
class ClapperPlayer extends GstPlayer.Player
|
||||||
{
|
{
|
||||||
_init()
|
_init(opts)
|
||||||
{
|
{
|
||||||
|
opts = opts || {};
|
||||||
|
Object.assign(opts, DEFAULTS);
|
||||||
|
|
||||||
let gtkglsink = Gst.ElementFactory.make('gtkglsink', null);
|
let gtkglsink = Gst.ElementFactory.make('gtkglsink', null);
|
||||||
let glsinkbin = Gst.ElementFactory.make('glsinkbin', null);
|
let glsinkbin = Gst.ElementFactory.make('glsinkbin', null);
|
||||||
glsinkbin.sink = gtkglsink;
|
glsinkbin.sink = gtkglsink;
|
||||||
@@ -19,6 +28,13 @@ class GtkPlayer extends GstPlayer.Player
|
|||||||
video_renderer: renderer
|
video_renderer: renderer
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let config = this.get_config();
|
||||||
|
|
||||||
|
for(let setting of Object.keys(DEFAULTS))
|
||||||
|
GstPlayer.Player[`config_set_${setting}`](config, opts[setting]);
|
||||||
|
|
||||||
|
this.set_config(config);
|
||||||
|
|
||||||
this.loop = GLib.MainLoop.new(null, false);
|
this.loop = GLib.MainLoop.new(null, false);
|
||||||
this.widget = gtkglsink.widget;
|
this.widget = gtkglsink.widget;
|
||||||
this.state = GstPlayer.PlayerState.STOPPED;
|
this.state = GstPlayer.PlayerState.STOPPED;
|
||||||
@@ -33,6 +49,15 @@ class GtkPlayer extends GstPlayer.Player
|
|||||||
this.seek(position * 1000000000);
|
this.seek(position * 1000000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggle_play()
|
||||||
|
{
|
||||||
|
let action = (this.state === GstPlayer.PlayerState.PLAYING)
|
||||||
|
? 'pause'
|
||||||
|
: 'play';
|
||||||
|
|
||||||
|
this[action]();
|
||||||
|
}
|
||||||
|
|
||||||
_onStateChanged(player, state)
|
_onStateChanged(player, state)
|
||||||
{
|
{
|
||||||
this.state = state;
|
this.state = state;
|
5
gex.json
5
gex.json
@@ -1,6 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "clapper",
|
"name": "clapper",
|
||||||
"files": [
|
"files": [
|
||||||
"src/player.js"
|
"clapper_src/app.js",
|
||||||
|
"clapper_src/controls.js",
|
||||||
|
"clapper_src/interface.js",
|
||||||
|
"clapper_src/player.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user