Merge pull request #148 from Rafostar/popovers-rework

Popovers rework
This commit is contained in:
Rafał Dzięgiel
2021-09-01 17:18:03 +02:00
committed by GitHub
11 changed files with 426 additions and 373 deletions

View File

@@ -5,17 +5,33 @@ scale marks {
radio { radio {
margin-left: -2px; margin-left: -2px;
} }
scrolledwindow scrollbar.vertical slider {
min-height: 16px;
}
/* Adwaita is missing osd ListBox */ /* Adwaita is missing osd ListBox */
.playlistrow { .clapperplaylist row {
border-radius: 5px; border-radius: 5px;
} }
.playlistrow { .clapperplaylist row {
color: @theme_fg_color; color: @theme_fg_color;
} }
.osd .playlist { .clapperplaylist row button {
margin: 0px;
padding: 0px;
min-width: 28px;
min-height: 28px;
}
.fullscreen.tvmode .clapperplaylist row button {
min-width: 36px;
min-height: 36px;
margin-left: 2px;
margin-right: 2px;
}
.osd .clapperplaylist {
background: none; background: none;
} }
.osd .playlist row image { .osd .clapperplaylist row image {
-gtk-icon-shadow: none; -gtk-icon-shadow: none;
} }
.osdheaderbar { .osdheaderbar {
@@ -41,6 +57,9 @@ popover contents {
border-color: transparent; border-color: transparent;
box-shadow: none; box-shadow: none;
} }
.popoverseparator separator {
background-color: @insensitive_fg_color;
}
/* Rounded corners */ /* Rounded corners */
.adwrounded.csd { .adwrounded.csd {
@@ -79,25 +98,29 @@ scale trough slider {
font-size: 21px; font-size: 21px;
font-weight: 500; font-weight: 500;
} }
.adwicons .playercontrols { .adwicons .clappercontrols {
margin-bottom: -1px; margin-bottom: -1px;
} }
.playercontrols { .clappercontrols {
margin-left: 2px; margin-left: 2px;
margin-right: 2px; margin-right: 2px;
} }
.playercontrols button { .clappercontrolsbutton {
margin: 3px; margin: 3px;
margin-left: 1px; margin-left: 1px;
margin-right: 1px; margin-right: 1px;
} }
.fullscreen.tvmode .playercontrols button { .fullscreen.tvmode .clappercontrolsbutton {
min-width: 32px; min-width: 32px;
min-height: 32px; min-height: 32px;
margin: 5px; margin: 5px;
margin-left: 3px; margin-left: 3px;
margin-right: 3px; margin-right: 3px;
} }
.clappercontrolsbutton.text-button {
padding-left: 4px;
padding-right: 4px;
}
.fullscreen.tvmode button image { .fullscreen.tvmode button image {
-gtk-icon-shadow: none; -gtk-icon-shadow: none;
} }
@@ -109,7 +132,8 @@ scale trough slider {
min-height: 17px; min-height: 17px;
} }
.fullscreen.tvmode .playercontrols button image { /* Also affects popover buttons */
.fullscreen.tvmode .clappercontrols button image {
-gtk-icon-size: 24px; -gtk-icon-size: 24px;
} }
.adwicons .playbackicon { .adwicons .playbackicon {
@@ -118,15 +142,12 @@ scale trough slider {
.adwicons.fullscreen.tvmode .playbackicon { .adwicons.fullscreen.tvmode .playbackicon {
-gtk-icon-size: 28px; -gtk-icon-size: 28px;
} }
.labelbuttonlabel { .clappercontrolsbutton.text-button label {
margin-left: -4px;
margin-right: -4px;
min-width: 8px;
font-family: 'Cantarell', sans-serif; font-family: 'Cantarell', sans-serif;
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
font-weight: 600; font-weight: 600;
} }
.fullscreen.tvmode .labelbuttonlabel { .fullscreen.tvmode .clappercontrolsbutton.text-button label {
font-size: 22px; font-size: 22px;
text-shadow: none; text-shadow: none;
} }
@@ -157,12 +178,6 @@ scale trough slider {
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
/* Button Inside Popover */
.popoverbutton {
min-width: 24px;
min-height: 24px;
}
/* Position Scale */ /* Position Scale */
.positionscale { .positionscale {
margin: -2px; margin: -2px;
@@ -245,14 +260,14 @@ scale trough slider {
} }
/* Elapsed Popover */ /* Elapsed Popover */
.elapsedpopoverbox { .elapsedpopover {
min-width: 260px; min-width: 326px;
} }
.elapsedpopoverbox box separator { .fullscreen.tvmode .elapsedpopover {
background: @insensitive_fg_color; min-width: 448px;
} }
.fullscreen.tvmode .elapsedpopoverbox { .elapsedpopover contents {
min-width: 360px; padding-bottom: 0px;
} }
.speedscale trough highlight { .speedscale trough highlight {
min-height: 4px; min-height: 4px;

View File

@@ -1,10 +1,5 @@
const { GObject, Gtk } = imports.gi; const { GObject, Gtk } = imports.gi;
const Misc = imports.src.misc;
/* Negative values from CSS */
const PopoverOffset = {
DEFAULT: -3,
TVMODE: -5,
};
var CustomButton = GObject.registerClass( var CustomButton = GObject.registerClass(
class ClapperCustomButton extends Gtk.Button class ClapperCustomButton extends Gtk.Button
@@ -22,28 +17,15 @@ class ClapperCustomButton extends Gtk.Button
super._init(opts); super._init(opts);
this.isFullscreen = false;
this.add_css_class('flat'); this.add_css_class('flat');
} this.add_css_class('clappercontrolsbutton');
setFullscreenMode(isFullscreen)
{
if(this.isFullscreen === isFullscreen)
return;
/* Redraw icon after style class change */
if(this.icon_name)
this.set_icon_name(this.icon_name);
this.isFullscreen = isFullscreen;
} }
vfunc_clicked() vfunc_clicked()
{ {
if(!this.isFullscreen)
return;
const clapperWidget = this.get_ancestor(Gtk.Grid); const clapperWidget = this.get_ancestor(Gtk.Grid);
if(clapperWidget.isFullscreenMode)
clapperWidget.revealControls(); clapperWidget.revealControls();
} }
}); });
@@ -72,79 +54,73 @@ class ClapperIconToggleButton extends CustomButton
} }
}); });
var PopoverButtonBase = GObject.registerClass( var PopoverSeparator = GObject.registerClass({
class ClapperPopoverButtonBase extends Gtk.ToggleButton GTypeName: 'ClapperPopoverSeparator',
Template: `file://${Misc.getClapperPath()}/ui/popover-separator.ui`,
InternalChildren: ['middle_label'],
Properties: {
'label': GObject.ParamSpec.string(
'label',
'Middle label',
'Text to set in the middle',
GObject.ParamFlags.WRITABLE,
null
),
}
},
class ClapperPopoverSeparator extends Gtk.Box
{ {
_init() _init(opts)
{ {
super._init({ super._init();
halign: Gtk.Align.CENTER,
valign: Gtk.Align.CENTER,
can_focus: false,
});
this.isFullscreen = false; if(!opts.label)
this.add_css_class('flat'); this.visible = false;
this.popover = new Gtk.Popover({ this.label = opts.label;
position: Gtk.PositionType.TOP,
});
this.popoverBox = new Gtk.Box({
orientation: Gtk.Orientation.VERTICAL,
});
this.popover.set_child(this.popoverBox);
this.popover.set_offset(0, PopoverOffset.DEFAULT);
if(this.isFullscreen)
this.popover.add_css_class('osd');
this.popover.connect('closed', this._onClosed.bind(this));
this.popover.set_parent(this);
} }
setFullscreenMode(isFullscreen) set label(value)
{ {
if(this.isFullscreen === isFullscreen) this._middle_label.label = value || "";
return;
/* Redraw icon after style class change */ if(value)
if(this.icon_name) this.visible = true;
this.set_icon_name(this.icon_name); }
});
this.isFullscreen = isFullscreen; var PopoverButtonBase = GObject.registerClass({
GTypeName: 'ClapperPopoverButtonBase',
},
class ClapperPopoverButtonBase extends Gtk.MenuButton
{
_init(opts = {})
{
super._init(opts);
/* TODO: Fullscreen non-tv mode */ if(opts.icon_name)
const offset = (isFullscreen) this.icon_name = opts.icon_name;
? PopoverOffset.TVMODE else if(opts.label)
: PopoverOffset.DEFAULT; this.label = opts.label;
this.popover.set_offset(0, offset); this.toggleButton = this.get_first_child();
this.toggleButton.add_css_class('clappercontrolsbutton');
const cssClass = 'osd'; this.set_create_popup_func(this._onPopoverOpened);
if(isFullscreen === this.popover.has_css_class(cssClass)) this.popover.connect('closed', this._onPopoverClosed.bind(this));
return;
const action = (isFullscreen) ? 'add' : 'remove';
this.popover[action + '_css_class'](cssClass);
} }
vfunc_toggled() _onPopoverOpened(self)
{ {
if(!this.active) const clapperWidget = self.get_ancestor(Gtk.Grid);
return;
const clapperWidget = this.get_ancestor(Gtk.Grid); if(clapperWidget.isFullscreenMode) {
if(this.isFullscreen) {
clapperWidget.revealControls(); clapperWidget.revealControls();
clapperWidget.isPopoverOpen = true; clapperWidget.isPopoverOpen = true;
} }
this.popover.popup();
} }
_onClosed() _onPopoverClosed(popover)
{ {
const clapperWidget = this.get_ancestor(Gtk.Grid); const clapperWidget = this.get_ancestor(Gtk.Grid);
@@ -153,94 +129,107 @@ class ClapperPopoverButtonBase extends Gtk.ToggleButton
clapperWidget.revealControls(); clapperWidget.revealControls();
clapperWidget.isPopoverOpen = false; clapperWidget.isPopoverOpen = false;
this.active = false;
}
_onCloseRequest()
{
this.popover.unparent();
} }
}); });
var IconPopoverButton = GObject.registerClass( var ElapsedTimeButton = GObject.registerClass({
class ClapperIconPopoverButton extends PopoverButtonBase GTypeName: 'ClapperElapsedTimeButton',
Template: `file://${Misc.getClapperPath()}/ui/elapsed-time-button.ui`,
Children: ['scrolledWindow', 'speedScale'],
},
class ClapperElapsedTimeButton extends PopoverButtonBase
{ {
_init(icon) _init(opts)
{ {
super._init(); super._init(opts);
this.icon_name = icon; this.setInitialState();
} this.popover.add_css_class('elapsedpopover');
});
var LabelPopoverButton = GObject.registerClass( this.scrolledWindow.max_content_height = 150;
class ClapperLabelPopoverButton extends PopoverButtonBase
{
_init(text)
{
super._init();
this.customLabel = new Gtk.Label({
label: text,
single_line_mode: true,
});
this.customLabel.add_css_class('labelbuttonlabel');
this.set_child(this.customLabel);
} }
set_label(text) set label(value)
{ {
this.customLabel.set_text(text); this.toggleButton.label = value;
}
});
var ElapsedPopoverButton = GObject.registerClass(
class ClapperElapsedPopoverButton extends LabelPopoverButton
{
_init(text)
{
super._init(text);
this.popoverBox.add_css_class('elapsedpopoverbox');
this.scrolledWindow = new Gtk.ScrolledWindow({
max_content_height: 150,
propagate_natural_height: true,
});
this.popoverBox.append(this.scrolledWindow);
} }
setFullscreenMode(isFullscreen) get label()
{ {
super.setFullscreenMode(isFullscreen); return this.toggleButton.label;
}
this.scrolledWindow.max_content_height = (isFullscreen) setInitialState()
{
this.label = '00:00/00:00';
}
setFullscreenMode(isFullscreen, isMobileMonitor)
{
this.scrolledWindow.max_content_height = (isFullscreen && !isMobileMonitor)
? 190 : 150; ? 190 : 150;
} }
});
addSeparator(text) var TrackSelectButton = GObject.registerClass({
GTypeName: 'ClapperTrackSelectButton',
Template: `file://${Misc.getClapperPath()}/ui/track-select-button.ui`,
Children: ['popoverBox'],
InternalChildren: ['scrolled_window', 'decoder_separator'],
},
class ClapperTrackSelectButton extends PopoverButtonBase
{ {
const box = new Gtk.Box({ _init(opts)
orientation: Gtk.Orientation.HORIZONTAL, {
hexpand: true, super._init(opts);
});
const label = new Gtk.Label({ this._scrolled_window.max_content_height = 220;
label: text, }
halign: Gtk.Align.CENTER,
}); setFullscreenMode(isFullscreen, isMobileMonitor)
const leftSeparator = new Gtk.Separator({ {
orientation: Gtk.Orientation.HORIZONTAL, this._scrolled_window.max_content_height = (isFullscreen && !isMobileMonitor)
hexpand: true, ? 290 : 220;
valign: Gtk.Align.CENTER, }
});
const rightSeparator = new Gtk.Separator({ setDecoder(decoder)
orientation: Gtk.Orientation.HORIZONTAL, {
hexpand: true, this._decoder_separator.label = _('Decoder: %s').format(decoder);
valign: Gtk.Align.CENTER, }
}); });
box.append(leftSeparator);
box.append(label); var VolumeButton = GObject.registerClass({
box.append(rightSeparator); GTypeName: 'ClapperVolumeButton',
this.popoverBox.append(box); Template: `file://${Misc.getClapperPath()}/ui/volume-button.ui`,
Children: ['volumeScale'],
},
class ClapperVolumeButton extends PopoverButtonBase
{
_onVolumeScaleValueChanged(scale)
{
const volume = scale.get_value();
const cssClass = 'overamp';
const hasOveramp = (scale.has_css_class(cssClass));
if(volume > 1) {
if(!hasOveramp)
scale.add_css_class(cssClass);
}
else {
if(hasOveramp)
scale.remove_css_class(cssClass);
}
const icon = (volume <= 0)
? 'muted'
: (volume <= 0.3)
? 'low'
: (volume <= 0.7)
? 'medium'
: (volume <= 1)
? 'high'
: 'overamplified';
this.icon_name = `audio-volume-${icon}-symbolic`;
} }
}); });

246
src/controls.js vendored
View File

@@ -29,15 +29,29 @@ class ClapperControls extends Gtk.Box
this.showHours = false; this.showHours = false;
this.durationFormatted = '00:00'; this.durationFormatted = '00:00';
this.buttonsArr = [];
this.revealersArr = []; this.revealersArr = [];
this.chapters = null; this.chapters = null;
this.chapterShowId = null; this.chapterShowId = null;
this.chapterHideId = null; this.chapterHideId = null;
this._addTogglePlayButton(); this.togglePlayButton = new Buttons.IconToggleButton(
this._addElapsedButton(); 'media-playback-start-symbolic',
'media-playback-pause-symbolic'
);
this.togglePlayButton.child.add_css_class('playbackicon');
this.togglePlayButton.connect(
'clicked', this._onTogglePlayClicked.bind(this)
);
this.append(this.togglePlayButton);
const elapsedRevealer = new Revealers.ButtonsRevealer('SLIDE_RIGHT');
this.elapsedButton = new Buttons.ElapsedTimeButton();
elapsedRevealer.append(this.elapsedButton);
elapsedRevealer.reveal_child = true;
this.append(elapsedRevealer);
this.revealersArr.push(elapsedRevealer);
this._addPositionScale(); this._addPositionScale();
const revealTracksButton = new Buttons.IconToggleButton( const revealTracksButton = new Buttons.IconToggleButton(
@@ -45,30 +59,29 @@ class ClapperControls extends Gtk.Box
'go-next-symbolic' 'go-next-symbolic'
); );
revealTracksButton.add_css_class('narrowbutton'); revealTracksButton.add_css_class('narrowbutton');
this.buttonsArr.push(revealTracksButton);
const tracksRevealer = new Revealers.ButtonsRevealer( const tracksRevealer = new Revealers.ButtonsRevealer(
'SLIDE_LEFT', revealTracksButton 'SLIDE_LEFT', revealTracksButton
); );
this.visualizationsButton = this.addIconPopoverButton( this.visualizationsButton = new Buttons.TrackSelectButton({
'display-projector-symbolic', icon_name: 'display-projector-symbolic',
tracksRevealer visible: false,
); });
this.visualizationsButton.set_visible(false); tracksRevealer.append(this.visualizationsButton);
this.videoTracksButton = this.addIconPopoverButton( this.videoTracksButton = new Buttons.TrackSelectButton({
'emblem-videos-symbolic', icon_name: 'emblem-videos-symbolic',
tracksRevealer visible: false,
); });
this.videoTracksButton.set_visible(false); tracksRevealer.append(this.videoTracksButton);
this.audioTracksButton = this.addIconPopoverButton( this.audioTracksButton = new Buttons.TrackSelectButton({
'emblem-music-symbolic', icon_name: 'emblem-music-symbolic',
tracksRevealer visible: false,
); });
this.audioTracksButton.set_visible(false); tracksRevealer.append(this.audioTracksButton);
this.subtitleTracksButton = this.addIconPopoverButton( this.subtitleTracksButton = new Buttons.TrackSelectButton({
'media-view-subtitles-symbolic', icon_name: 'media-view-subtitles-symbolic',
tracksRevealer visible: false,
); });
this.subtitleTracksButton.set_visible(false); tracksRevealer.append(this.subtitleTracksButton);
this.revealTracksRevealer = new Revealers.ButtonsRevealer('SLIDE_LEFT'); this.revealTracksRevealer = new Revealers.ButtonsRevealer('SLIDE_LEFT');
this.revealTracksRevealer.append(revealTracksButton); this.revealTracksRevealer.append(revealTracksButton);
@@ -79,24 +92,30 @@ class ClapperControls extends Gtk.Box
this.revealersArr.push(tracksRevealer); this.revealersArr.push(tracksRevealer);
this.append(tracksRevealer); this.append(tracksRevealer);
this._addVolumeButton(); this.volumeButton = new Buttons.VolumeButton();
this.unfullscreenButton = this.addButton( this.append(this.volumeButton);
'view-restore-symbolic'
); this.unfullscreenButton = new Buttons.CustomButton({
icon_name: 'view-restore-symbolic',
});
this.unfullscreenButton.connect('clicked', this._onUnfullscreenClicked.bind(this)); this.unfullscreenButton.connect('clicked', this._onUnfullscreenClicked.bind(this));
this.unfullscreenButton.set_visible(false); this.unfullscreenButton.set_visible(false);
this.append(this.unfullscreenButton);
this.add_css_class('playercontrols'); this.add_css_class('clappercontrols');
this.realizeSignal = this.connect('realize', this._onRealize.bind(this)); this.realizeSignal = this.connect('realize', this._onRealize.bind(this));
} }
setFullscreenMode(isFullscreen) setFullscreenMode(isFullscreen, isMobileMonitor)
{ {
/* Allow recheck on next resize */ /* Allow recheck on next resize */
this.isMobile = null; this.isMobile = null;
for(let button of this.buttonsArr) this.elapsedButton.setFullscreenMode(isFullscreen, isMobileMonitor);
button.setFullscreenMode(isFullscreen); this.visualizationsButton.setFullscreenMode(isFullscreen, isMobileMonitor);
this.videoTracksButton.setFullscreenMode(isFullscreen, isMobileMonitor);
this.audioTracksButton.setFullscreenMode(isFullscreen, isMobileMonitor);
this.subtitleTracksButton.setFullscreenMode(isFullscreen, isMobileMonitor);
this.unfullscreenButton.visible = isFullscreen; this.unfullscreenButton.visible = isFullscreen;
this.isFullscreen = isFullscreen; this.isFullscreen = isFullscreen;
@@ -105,7 +124,7 @@ class ClapperControls extends Gtk.Box
setLiveMode(isLive, isSeekable) setLiveMode(isLive, isSeekable)
{ {
if(isLive) if(isLive)
this.elapsedButton.set_label('LIVE'); this.elapsedButton.label = 'LIVE';
this.positionScale.visible = isSeekable; this.positionScale.visible = isSeekable;
} }
@@ -116,7 +135,7 @@ class ClapperControls extends Gtk.Box
this.positionScale.set_value(0); this.positionScale.set_value(0);
this.positionScale.visible = false; this.positionScale.visible = false;
this.elapsedButton.set_label(INITIAL_ELAPSED); this.elapsedButton.setInitialState();
this.togglePlayButton.setPrimaryIcon(); this.togglePlayButton.setPrimaryIcon();
for(let type of ['video', 'audio', 'subtitle']) for(let type of ['video', 'audio', 'subtitle'])
@@ -132,46 +151,7 @@ class ClapperControls extends Gtk.Box
const elapsed = Misc.getFormattedTime(value, this.showHours) const elapsed = Misc.getFormattedTime(value, this.showHours)
+ '/' + this.durationFormatted; + '/' + this.durationFormatted;
this.elapsedButton.set_label(elapsed); this.elapsedButton.label = elapsed;
}
addButton(buttonIcon, revealer)
{
const button = (buttonIcon instanceof Gtk.Button)
? buttonIcon
: new Buttons.CustomButton({ icon_name: buttonIcon });
if(!revealer)
this.append(button);
else
revealer.append(button);
this.buttonsArr.push(button);
return button;
}
addIconPopoverButton(iconName, revealer)
{
const button = new Buttons.IconPopoverButton(iconName);
return this.addButton(button, revealer);
}
addLabelPopoverButton(text, revealer)
{
text = text || '';
const button = new Buttons.LabelPopoverButton(text);
return this.addButton(button, revealer);
}
addElapsedPopoverButton(text, revealer)
{
text = text || '';
const button = new Buttons.ElapsedPopoverButton(text);
return this.addButton(button, revealer);
} }
addCheckButtons(box, array, activeId) addCheckButtons(box, array, activeId)
@@ -285,51 +265,6 @@ class ClapperControls extends Gtk.Box
} }
} }
_addTogglePlayButton()
{
this.togglePlayButton = new Buttons.IconToggleButton(
'media-playback-start-symbolic',
'media-playback-pause-symbolic'
);
this.togglePlayButton.child.add_css_class('playbackicon');
this.togglePlayButton.connect(
'clicked', this._onTogglePlayClicked.bind(this)
);
this.addButton(this.togglePlayButton);
}
_addElapsedButton()
{
const elapsedRevealer = new Revealers.ButtonsRevealer('SLIDE_RIGHT');
this.elapsedButton = this.addElapsedPopoverButton(INITIAL_ELAPSED, elapsedRevealer);
elapsedRevealer.set_reveal_child(true);
this.revealersArr.push(elapsedRevealer);
this.elapsedButton.addSeparator('Speed');
const speedScale = new Gtk.Scale({
orientation: Gtk.Orientation.HORIZONTAL,
value_pos: Gtk.PositionType.BOTTOM,
draw_value: false,
round_digits: 2,
hexpand: true,
valign: Gtk.Align.CENTER,
});
speedScale.add_css_class('speedscale');
this.speedAdjustment = speedScale.get_adjustment();
this.speedAdjustment.set_lower(0.01);
this.speedAdjustment.set_upper(2);
this.speedAdjustment.set_value(1);
this.speedAdjustment.set_page_increment(0.1);
speedScale.add_mark(0.25, Gtk.PositionType.BOTTOM, '0.25x');
speedScale.add_mark(1, Gtk.PositionType.BOTTOM, 'Normal');
speedScale.add_mark(2, Gtk.PositionType.BOTTOM, '2x');
this.elapsedButton.popoverBox.append(speedScale);
this.append(elapsedRevealer);
}
_addPositionScale() _addPositionScale()
{ {
this.positionScale = new Gtk.Scale({ this.positionScale = new Gtk.Scale({
@@ -381,36 +316,6 @@ class ClapperControls extends Gtk.Box
this.append(box); this.append(box);
} }
_addVolumeButton()
{
this.volumeButton = this.addIconPopoverButton(
'audio-volume-muted-symbolic'
);
this.volumeScale = new Gtk.Scale({
orientation: Gtk.Orientation.VERTICAL,
inverted: true,
value_pos: Gtk.PositionType.TOP,
draw_value: false,
vexpand: true,
});
this.volumeScale.add_css_class('volumescale');
this.volumeAdjustment = this.volumeScale.get_adjustment();
this.volumeAdjustment.set_upper(Misc.maxVolume);
this.volumeAdjustment.set_step_increment(0.05);
this.volumeAdjustment.set_page_increment(0.05);
for(let i of [0, 1, Misc.maxVolume]) {
const text = (!i) ? '0%' : (i % 1 === 0) ? `${i}00%` : `${i * 10}0%`;
this.volumeScale.add_mark(i, Gtk.PositionType.LEFT, text);
}
this.volumeScale.connect(
'value-changed', this._onVolumeScaleValueChanged.bind(this)
);
this.volumeButton.popoverBox.append(this.volumeScale);
}
_setChapterVisible(isVisible) _setChapterVisible(isVisible)
{ {
const type = (isVisible) ? 'Show' : 'Hide'; const type = (isVisible) ? 'Show' : 'Hide';
@@ -553,42 +458,6 @@ class ClapperControls extends Gtk.Box
} }
} }
_onVolumeScaleValueChanged(scale)
{
const volume = scale.get_value();
/* FIXME: All of below should be placed in 'volume-changed'
* event once we move to message bus API */
const cssClass = 'overamp';
const hasOveramp = (scale.has_css_class(cssClass));
if(volume > 1) {
if(!hasOveramp)
scale.add_css_class(cssClass);
}
else {
if(hasOveramp)
scale.remove_css_class(cssClass);
}
const icon = (volume <= 0)
? 'muted'
: (volume <= 0.3)
? 'low'
: (volume <= 0.7)
? 'medium'
: (volume <= 1)
? 'high'
: 'overamplified';
const iconName = `audio-volume-${icon}-symbolic`;
if(this.volumeButton.icon_name === iconName)
return;
this.volumeButton.icon_name = iconName;
debug(`set volume icon: ${icon}`);
}
_onPositionScaleDragging(scale) _onPositionScaleDragging(scale)
{ {
const isPositionDragging = scale.has_css_class('dragging'); const isPositionDragging = scale.has_css_class('dragging');
@@ -638,13 +507,6 @@ class ClapperControls extends Gtk.Box
this.positionScale.disconnect(this.positionScaleValueSignal); this.positionScale.disconnect(this.positionScaleValueSignal);
this.positionScale.disconnect(this.positionScaleDragSignal); this.positionScale.disconnect(this.positionScaleDragSignal);
for(let button of this.buttonsArr) {
if(!button._onCloseRequest)
continue;
button._onCloseRequest();
}
this.chapterPopover.unparent(); this.chapterPopover.unparent();
} }
}); });

View File

@@ -3,6 +3,7 @@ imports.gi.versions.Gtk = '4.0';
imports.gi.versions.Soup = '2.4'; imports.gi.versions.Soup = '2.4';
pkg.initGettext(); pkg.initGettext();
pkg.initFormat();
const { GstClapper, Gtk, Adw } = imports.gi; const { GstClapper, Gtk, Adw } = imports.gi;
const { App } = imports.src.app; const { App } = imports.src.app;

View File

@@ -354,9 +354,9 @@ class ClapperPlayer extends GstClapper.Clapper
const { controls } = this.widget.get_ancestor(Gtk.Grid); const { controls } = this.widget.get_ancestor(Gtk.Grid);
const value = (isIncrease) ? offset : -offset; const value = (isIncrease) ? offset : -offset;
const volume = controls.volumeScale.get_value() + value; const scale = controls.volumeButton.volumeScale;
controls.volumeScale.set_value(volume); scale.set_value(scale.get_value() + value);
} }
next_chapter() next_chapter()

View File

@@ -28,7 +28,7 @@ class ClapperPlaylistWidget extends Gtk.ListBox
}); });
this.activeRowId = -1; this.activeRowId = -1;
this.repeatMode = RepeatMode.NONE; this.repeatMode = RepeatMode.NONE;
this.add_css_class('playlist'); this.add_css_class('clapperplaylist');
this.connect('row-activated', this._onRowActivated.bind(this)); this.connect('row-activated', this._onRowActivated.bind(this));
} }
@@ -255,7 +255,6 @@ class ClapperPlaylistItem extends Gtk.ListBoxRow
} }
this.filename = filename || uri; this.filename = filename || uri;
this.set_tooltip_text(this.filename); this.set_tooltip_text(this.filename);
this.add_css_class('playlistrow');
const box = new Gtk.Box({ const box = new Gtk.Box({
orientation: Gtk.Orientation.HORIZONTAL, orientation: Gtk.Orientation.HORIZONTAL,
@@ -270,7 +269,6 @@ class ClapperPlaylistItem extends Gtk.ListBoxRow
}); });
repeatButton.add_css_class('flat'); repeatButton.add_css_class('flat');
repeatButton.add_css_class('circular'); repeatButton.add_css_class('circular');
repeatButton.add_css_class('popoverbutton');
repeatButton.connect('clicked', this._onRepeatClicked.bind(this)); repeatButton.connect('clicked', this._onRepeatClicked.bind(this));
const label = new Gtk.Label({ const label = new Gtk.Label({
label: this.filename, label: this.filename,
@@ -285,7 +283,6 @@ class ClapperPlaylistItem extends Gtk.ListBoxRow
}); });
removeButton.add_css_class('flat'); removeButton.add_css_class('flat');
removeButton.add_css_class('circular'); removeButton.add_css_class('circular');
removeButton.add_css_class('popoverbutton');
removeButton.connect('clicked', this._onRemoveClicked.bind(this)); removeButton.connect('clicked', this._onRemoveClicked.bind(this));
box.append(repeatButton); box.append(repeatButton);

View File

@@ -65,16 +65,23 @@ class ClapperWidget extends Gtk.Grid
this.controls.elapsedButton.scrolledWindow.set_child(this.player.playlistWidget); this.controls.elapsedButton.scrolledWindow.set_child(this.player.playlistWidget);
this.controls.speedAdjustment.bind_property( const speedAdjustment = this.controls.elapsedButton.speedScale.get_adjustment();
speedAdjustment.bind_property(
'value', this.player, 'rate', GObject.BindingFlags.BIDIRECTIONAL 'value', this.player, 'rate', GObject.BindingFlags.BIDIRECTIONAL
); );
this.controls.volumeAdjustment.bind_property(
const volumeAdjustment = this.controls.volumeButton.volumeScale.get_adjustment();
volumeAdjustment.bind_property(
'value', this.player, 'volume', GObject.BindingFlags.BIDIRECTIONAL 'value', this.player, 'volume', GObject.BindingFlags.BIDIRECTIONAL
); );
this.player.connect('position-updated', this._onPlayerPositionUpdated.bind(this)); this.player.connect('position-updated', this._onPlayerPositionUpdated.bind(this));
this.player.connect('duration-changed', this._onPlayerDurationChanged.bind(this)); this.player.connect('duration-changed', this._onPlayerDurationChanged.bind(this));
this.player.connect('media-info-updated', this._onMediaInfoUpdated.bind(this)); this.player.connect('media-info-updated', this._onMediaInfoUpdated.bind(this));
this.player.connect('video-decoder-changed', this._onPlayerVideoDecoderChanged.bind(this));
this.player.connect('audio-decoder-changed', this._onPlayerAudioDecoderChanged.bind(this));
this.overlay.set_child(playerWidget); this.overlay.set_child(playerWidget);
this.overlay.add_overlay(this.revealerTop); this.overlay.add_overlay(this.revealerTop);
this.overlay.add_overlay(this.revealerBottom); this.overlay.add_overlay(this.revealerBottom);
@@ -155,7 +162,7 @@ class ClapperWidget extends Gtk.Grid
this.revealerBottom.revealerBox.visible = isFullscreen; this.revealerBottom.revealerBox.visible = isFullscreen;
this._changeControlsPlacement(isFullscreen); this._changeControlsPlacement(isFullscreen);
this.controls.setFullscreenMode(isFullscreen); this.controls.setFullscreenMode(isFullscreen, this.isMobileMonitor);
if(this.revealerTop.child_revealed) if(this.revealerTop.child_revealed)
this._checkSetUpdateTimeInterval(); this._checkSetUpdateTimeInterval();
@@ -503,6 +510,16 @@ class ClapperWidget extends Gtk.Grid
this.controls.positionScale.set_value(positionSeconds); this.controls.positionScale.set_value(positionSeconds);
} }
_onPlayerVideoDecoderChanged(player, decoder)
{
this.controls.videoTracksButton.setDecoder(decoder);
}
_onPlayerAudioDecoderChanged(player, decoder)
{
this.controls.audioTracksButton.setDecoder(decoder);
}
_onStateNotify(toplevel) _onStateNotify(toplevel)
{ {
const isMaximized = Boolean( const isMaximized = Boolean(

58
ui/elapsed-time-button.ui Normal file
View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="ClapperElapsedTimeButton" parent="ClapperPopoverButtonBase">
<property name="popover">popover</property>
<property name="direction">up</property>
<property name="valign">center</property>
<property name="halign">center</property>
<property name="can_focus">False</property>
<style>
<class name="flat"/>
</style>
</template>
<object class="GtkPopover" id="popover">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkScrolledWindow" id="scrolledWindow">
<property name="propagate_natural_width">False</property>
<property name="propagate_natural_height">True</property>
</object>
</child>
<child>
<object class="ClapperPopoverSeparator">
<property name="label" translatable="yes">Speed</property>
</object>
</child>
<child>
<object class="GtkScale" id="speedScale">
<property name="orientation">horizontal</property>
<property name="value_pos">bottom</property>
<property name="draw_value">False</property>
<property name="round_digits">2</property>
<property name="hexpand">True</property>
<property name="valign">center</property>
<property name="adjustment">speed_adjustment</property>
<marks>
<mark value="0.25" position="bottom">0.25x</mark>
<mark value="1" position="bottom" translatable="yes">Normal</mark>
<mark value="2" position="bottom">2x</mark>
</marks>
<style>
<class name="speedscale"/>
</style>
</object>
</child>
</object>
</child>
</object>
<object class="GtkAdjustment" id="speed_adjustment">
<property name="lower">0.01</property>
<property name="upper">2</property>
<property name="value">1</property>
<property name="page-increment">0.1</property>
</object>
</interface>

29
ui/popover-separator.ui Normal file
View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="ClapperPopoverSeparator" parent="GtkBox">
<property name="orientation">horizontal</property>
<property name="hexpand">True</property>
<style>
<class name="popoverseparator"/>
</style>
<child>
<object class="GtkSeparator">
<property name="orientation">horizontal</property>
<property name="hexpand">True</property>
<property name="valign">center</property>
</object>
</child>
<child>
<object class="GtkLabel" id="middle_label">
<property name="halign">center</property>
</object>
</child>
<child>
<object class="GtkSeparator">
<property name="orientation">horizontal</property>
<property name="hexpand">True</property>
<property name="valign">center</property>
</object>
</child>
</template>
</interface>

37
ui/track-select-button.ui Normal file
View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="ClapperTrackSelectButton" parent="ClapperPopoverButtonBase">
<property name="popover">popover</property>
<property name="direction">up</property>
<property name="valign">center</property>
<property name="halign">center</property>
<property name="can_focus">False</property>
<style>
<class name="flat"/>
</style>
</template>
<object class="GtkPopover" id="popover">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="ClapperPopoverSeparator" id="decoder_separator">
</object>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolled_window">
<property name="propagate_natural_width">True</property>
<property name="propagate_natural_height">True</property>
<child>
<object class="GtkBox" id="popoverBox">
<property name="orientation">vertical</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

48
ui/volume-button.ui Normal file
View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="ClapperVolumeButton" parent="ClapperPopoverButtonBase">
<property name="icon_name">audio-volume-muted-symbolic</property>
<property name="popover">popover</property>
<property name="direction">up</property>
<property name="valign">center</property>
<property name="halign">center</property>
<property name="can_focus">False</property>
<style>
<class name="flat"/>
</style>
</template>
<object class="GtkPopover" id="popover">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkScale" id="volumeScale">
<property name="orientation">vertical</property>
<property name="inverted">True</property>
<property name="value_pos">top</property>
<property name="draw_value">False</property>
<property name="vexpand">True</property>
<property name="adjustment">volume_adjustment</property>
<signal name="value-changed" handler="_onVolumeScaleValueChanged"/>
<marks>
<mark value="0" position="left">0%</mark>
<mark value="1" position="left">100%</mark>
<mark value="1.5" position="left">150%</mark>
</marks>
<style>
<class name="volumescale"/>
</style>
</object>
</child>
</object>
</child>
</object>
<object class="GtkAdjustment" id="volume_adjustment">
<property name="lower">0</property>
<property name="upper">1.5</property>
<property name="step-increment">0.05</property>
<property name="page-increment">0.05</property>
</object>
</interface>