mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 11:47:25 +01:00
editor: Implement drag and drop where it makes sense
This commit is contained in:
parent
a13e406e99
commit
e47b7c2006
31 changed files with 888 additions and 87 deletions
|
|
@ -119,3 +119,17 @@
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.drag-handle {
|
||||||
|
color: color-mix(in srgb, var(--window-fg-color) 40%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle:backdrop {
|
||||||
|
color: color-mix(in srgb, var(--window-fg-color) 40%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
dragwidget {
|
||||||
|
background-color: var(--card-bg-color);
|
||||||
|
color: var(--card-fg-color);
|
||||||
|
border: 1px solid rgba(0, 0, 6, 0.07);
|
||||||
|
}
|
||||||
23
data/ui/editor/album/recording_row.blp
Normal file
23
data/ui/editor/album/recording_row.blp
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
using Adw 1;
|
||||||
|
|
||||||
|
template $MusicusAlbumEditorRecordingRow: Adw.ActionRow {
|
||||||
|
[prefix]
|
||||||
|
Gtk.Image {
|
||||||
|
icon-name: "list-drag-handle-symbolic";
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"drag-handle",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Gtk.Button {
|
||||||
|
icon-name: "user-trash-symbolic";
|
||||||
|
valign: center;
|
||||||
|
clicked => $remove() swapped;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"flat",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,15 @@ using Gtk 4.0;
|
||||||
using Adw 1;
|
using Adw 1;
|
||||||
|
|
||||||
template $MusicusRecordingEditorEnsembleRow: Adw.ActionRow {
|
template $MusicusRecordingEditorEnsembleRow: Adw.ActionRow {
|
||||||
|
[prefix]
|
||||||
|
Gtk.Image {
|
||||||
|
icon-name: "list-drag-handle-symbolic";
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"drag-handle",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
Gtk.Button {
|
Gtk.Button {
|
||||||
icon-name: "user-trash-symbolic";
|
icon-name: "user-trash-symbolic";
|
||||||
valign: center;
|
valign: center;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,15 @@ using Gtk 4.0;
|
||||||
using Adw 1;
|
using Adw 1;
|
||||||
|
|
||||||
template $MusicusRecordingEditorPerformerRow: Adw.ActionRow {
|
template $MusicusRecordingEditorPerformerRow: Adw.ActionRow {
|
||||||
|
[prefix]
|
||||||
|
Gtk.Image {
|
||||||
|
icon-name: "list-drag-handle-symbolic";
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"drag-handle",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
Gtk.Button {
|
Gtk.Button {
|
||||||
icon-name: "user-trash-symbolic";
|
icon-name: "user-trash-symbolic";
|
||||||
valign: center;
|
valign: center;
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,18 @@ template $MusicusTracksEditorTrackRow: Adw.ActionRow {
|
||||||
[prefix]
|
[prefix]
|
||||||
Gtk.Box select_parts_box {
|
Gtk.Box select_parts_box {
|
||||||
Gtk.Image {
|
Gtk.Image {
|
||||||
icon-name: "document-edit-symbolic";
|
icon-name: "list-drag-handle-symbolic";
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"drag-handle",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Gtk.Image edit_image {
|
||||||
|
icon-name: "document-edit-symbolic";
|
||||||
|
}
|
||||||
|
|
||||||
Gtk.Button reset_button {
|
Gtk.Button reset_button {
|
||||||
icon-name: "edit-clear-symbolic";
|
icon-name: "edit-clear-symbolic";
|
||||||
tooltip-text: _("Clear selected work parts");
|
tooltip-text: _("Clear selected work parts");
|
||||||
|
|
@ -21,7 +29,7 @@ template $MusicusTracksEditorTrackRow: Adw.ActionRow {
|
||||||
clicked => $reset() swapped;
|
clicked => $reset() swapped;
|
||||||
|
|
||||||
styles [
|
styles [
|
||||||
"flat"
|
"flat",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,7 +40,7 @@ template $MusicusTracksEditorTrackRow: Adw.ActionRow {
|
||||||
clicked => $remove() swapped;
|
clicked => $remove() swapped;
|
||||||
|
|
||||||
styles [
|
styles [
|
||||||
"flat"
|
"flat",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,22 @@ using Gtk 4.0;
|
||||||
using Adw 1;
|
using Adw 1;
|
||||||
|
|
||||||
template $MusicusWorkEditorComposerRow: Adw.ActionRow {
|
template $MusicusWorkEditorComposerRow: Adw.ActionRow {
|
||||||
|
[prefix]
|
||||||
|
Gtk.Image {
|
||||||
|
icon-name: "list-drag-handle-symbolic";
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"drag-handle",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
Gtk.Button {
|
Gtk.Button {
|
||||||
icon-name: "user-trash-symbolic";
|
icon-name: "user-trash-symbolic";
|
||||||
valign: center;
|
valign: center;
|
||||||
clicked => $remove() swapped;
|
clicked => $remove() swapped;
|
||||||
|
|
||||||
styles [
|
styles [
|
||||||
"flat"
|
"flat",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -17,7 +26,7 @@ template $MusicusWorkEditorComposerRow: Adw.ActionRow {
|
||||||
clicked => $open_role_popover() swapped;
|
clicked => $open_role_popover() swapped;
|
||||||
|
|
||||||
styles [
|
styles [
|
||||||
"flat"
|
"flat",
|
||||||
]
|
]
|
||||||
|
|
||||||
Gtk.Box role_box {
|
Gtk.Box role_box {
|
||||||
|
|
|
||||||
23
data/ui/editor/work/instrument_row.blp
Normal file
23
data/ui/editor/work/instrument_row.blp
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
using Adw 1;
|
||||||
|
|
||||||
|
template $MusicusWorkEditorInstrumentRow: Adw.ActionRow {
|
||||||
|
[prefix]
|
||||||
|
Gtk.Image {
|
||||||
|
icon-name: "list-drag-handle-symbolic";
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"drag-handle",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Gtk.Button {
|
||||||
|
icon-name: "user-trash-symbolic";
|
||||||
|
valign: center;
|
||||||
|
clicked => $remove() swapped;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"flat",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,15 @@ template $MusicusWorkEditorPartRow: Adw.ActionRow {
|
||||||
activatable: true;
|
activatable: true;
|
||||||
activated => $edit() swapped;
|
activated => $edit() swapped;
|
||||||
|
|
||||||
|
[prefix]
|
||||||
|
Gtk.Image {
|
||||||
|
icon-name: "list-drag-handle-symbolic";
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"drag-handle",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
Gtk.Image {
|
Gtk.Image {
|
||||||
icon-name: "document-edit-symbolic";
|
icon-name: "document-edit-symbolic";
|
||||||
}
|
}
|
||||||
|
|
@ -15,7 +24,7 @@ template $MusicusWorkEditorPartRow: Adw.ActionRow {
|
||||||
clicked => $remove() swapped;
|
clicked => $remove() swapped;
|
||||||
|
|
||||||
styles [
|
styles [
|
||||||
"flat"
|
"flat",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
|
mod recording_row;
|
||||||
|
|
||||||
use std::cell::{OnceCell, RefCell};
|
use std::cell::{OnceCell, RefCell};
|
||||||
|
|
||||||
use adw::{prelude::*, subclass::prelude::*};
|
use adw::{prelude::*, subclass::prelude::*};
|
||||||
use gettextrs::gettext;
|
use gettextrs::gettext;
|
||||||
use gtk::glib::{self, clone, subclass::Signal, Properties};
|
use gtk::glib::{self, clone, subclass::Signal, Properties};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
use recording_row::RecordingRow;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::models::{Album, Recording},
|
db::models::{Album, Recording},
|
||||||
|
|
@ -25,7 +28,7 @@ mod imp {
|
||||||
pub library: OnceCell<Library>,
|
pub library: OnceCell<Library>,
|
||||||
|
|
||||||
pub album_id: OnceCell<String>,
|
pub album_id: OnceCell<String>,
|
||||||
pub recordings: RefCell<Vec<Recording>>,
|
pub recording_rows: RefCell<Vec<RecordingRow>>,
|
||||||
|
|
||||||
pub recordings_popover: OnceCell<RecordingSelectorPopover>,
|
pub recordings_popover: OnceCell<RecordingSelectorPopover>,
|
||||||
|
|
||||||
|
|
@ -143,40 +146,36 @@ impl AlbumEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_recording(&self, recording: Recording) {
|
fn add_recording(&self, recording: Recording) {
|
||||||
let row = adw::ActionRow::builder()
|
let row = RecordingRow::new(recording);
|
||||||
.title(recording.work.to_string())
|
|
||||||
.subtitle(recording.performers_string())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let remove_button = gtk::Button::builder()
|
row.connect_move(clone!(
|
||||||
.icon_name("user-trash-symbolic")
|
|
||||||
.valign(gtk::Align::Center)
|
|
||||||
.css_classes(["flat"])
|
|
||||||
.build();
|
|
||||||
|
|
||||||
remove_button.connect_clicked(clone!(
|
|
||||||
#[weak(rename_to = this)]
|
#[weak(rename_to = this)]
|
||||||
self,
|
self,
|
||||||
#[weak]
|
move |target, source| {
|
||||||
row,
|
let mut recording_rows = this.imp().recording_rows.borrow_mut();
|
||||||
#[strong]
|
if let Some(index) = recording_rows.iter().position(|p| p == target) {
|
||||||
recording,
|
this.imp().recordings_list.remove(&source);
|
||||||
move |_| {
|
recording_rows.retain(|p| p != &source);
|
||||||
this.imp().recordings_list.remove(&row);
|
this.imp().recordings_list.insert(&source, index as i32);
|
||||||
this.imp()
|
recording_rows.insert(index, source);
|
||||||
.recordings
|
}
|
||||||
.borrow_mut()
|
|
||||||
.retain(|r| *r != recording);
|
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
row.add_suffix(&remove_button);
|
row.connect_remove(clone!(
|
||||||
|
#[weak(rename_to = this)]
|
||||||
|
self,
|
||||||
|
move |row| {
|
||||||
|
this.imp().recordings_list.remove(row);
|
||||||
|
this.imp().recording_rows.borrow_mut().retain(|p| p != row);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
self.imp()
|
self.imp()
|
||||||
.recordings_list
|
.recordings_list
|
||||||
.insert(&row, self.imp().recordings.borrow().len() as i32);
|
.insert(&row, self.imp().recording_rows.borrow().len() as i32);
|
||||||
|
|
||||||
self.imp().recordings.borrow_mut().push(recording);
|
self.imp().recording_rows.borrow_mut().push(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
|
@ -184,7 +183,13 @@ impl AlbumEditor {
|
||||||
let library = self.imp().library.get().unwrap();
|
let library = self.imp().library.get().unwrap();
|
||||||
|
|
||||||
let name = self.imp().name_editor.translation();
|
let name = self.imp().name_editor.translation();
|
||||||
let recordings = self.imp().recordings.borrow().clone();
|
let recordings = self
|
||||||
|
.imp()
|
||||||
|
.recording_rows
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.map(|r| r.recording())
|
||||||
|
.collect::<Vec<Recording>>();
|
||||||
|
|
||||||
if let Some(album_id) = self.imp().album_id.get() {
|
if let Some(album_id) = self.imp().album_id.get() {
|
||||||
library.update_album(album_id, name, recordings).unwrap();
|
library.update_album(album_id, name, recordings).unwrap();
|
||||||
|
|
|
||||||
140
src/editor/album/recording_row.rs
Normal file
140
src/editor/album/recording_row.rs
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
use std::cell::OnceCell;
|
||||||
|
|
||||||
|
use adw::{prelude::*, subclass::prelude::*};
|
||||||
|
use gtk::{
|
||||||
|
gdk,
|
||||||
|
glib::{self, clone, subclass::Signal},
|
||||||
|
};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
|
use crate::{db::models::Recording, util::drag_widget::DragWidget};
|
||||||
|
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||||
|
#[template(file = "data/ui/editor/album/recording_row.blp")]
|
||||||
|
pub struct RecordingRow {
|
||||||
|
pub recording: OnceCell<Recording>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for RecordingRow {
|
||||||
|
const NAME: &'static str = "MusicusAlbumEditorRecordingRow";
|
||||||
|
type Type = super::RecordingRow;
|
||||||
|
type ParentType = adw::ActionRow;
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.bind_template();
|
||||||
|
klass.bind_template_instance_callbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||||
|
obj.init_template();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for RecordingRow {
|
||||||
|
fn signals() -> &'static [Signal] {
|
||||||
|
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
||||||
|
vec![
|
||||||
|
Signal::builder("remove").build(),
|
||||||
|
Signal::builder("move")
|
||||||
|
.param_types([super::RecordingRow::static_type()])
|
||||||
|
.build(),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
SIGNALS.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constructed(&self) {
|
||||||
|
self.parent_constructed();
|
||||||
|
|
||||||
|
let drag_source = gtk::DragSource::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.content(&gdk::ContentProvider::for_value(&self.obj().to_value()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
drag_source.connect_drag_begin(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
move |_, drag| {
|
||||||
|
let icon = gtk::DragIcon::for_drag(drag);
|
||||||
|
icon.set_child(Some(&DragWidget::new(&obj)));
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drag_source);
|
||||||
|
|
||||||
|
let drop_target = gtk::DropTarget::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.build();
|
||||||
|
drop_target.set_types(&[Self::Type::static_type()]);
|
||||||
|
|
||||||
|
drop_target.connect_drop(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
#[upgrade_or]
|
||||||
|
false,
|
||||||
|
move |_, value, _, _| {
|
||||||
|
if let Ok(row) = value.get::<Self::Type>() {
|
||||||
|
obj.emit_by_name::<()>("move", &[&row]);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drop_target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetImpl for RecordingRow {}
|
||||||
|
impl ListBoxRowImpl for RecordingRow {}
|
||||||
|
impl PreferencesRowImpl for RecordingRow {}
|
||||||
|
impl ActionRowImpl for RecordingRow {}
|
||||||
|
}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct RecordingRow(ObjectSubclass<imp::RecordingRow>)
|
||||||
|
@extends gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow, adw::ActionRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gtk::template_callbacks]
|
||||||
|
impl RecordingRow {
|
||||||
|
pub fn new(recording: Recording) -> Self {
|
||||||
|
let obj: Self = glib::Object::new();
|
||||||
|
obj.set_title(&recording.work.to_string());
|
||||||
|
obj.set_subtitle(&recording.performers_string());
|
||||||
|
obj.imp().recording.set(recording).unwrap();
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connect_move<F: Fn(&Self, Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
|
self.connect_local("move", true, move |values| {
|
||||||
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
let source = values[1].get::<Self>().unwrap();
|
||||||
|
f(&obj, source);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connect_remove<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
|
self.connect_local("remove", true, move |values| {
|
||||||
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
f(&obj);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recording(&self) -> Recording {
|
||||||
|
self.imp().recording.get().unwrap().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[template_callback]
|
||||||
|
fn remove(&self) {
|
||||||
|
self.emit_by_name::<()>("remove", &[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -266,6 +266,20 @@ impl RecordingEditor {
|
||||||
fn add_performer_row(&self, performer: Performer) {
|
fn add_performer_row(&self, performer: Performer) {
|
||||||
let row = RecordingEditorPerformerRow::new(&self.navigation(), &self.library(), performer);
|
let row = RecordingEditorPerformerRow::new(&self.navigation(), &self.library(), performer);
|
||||||
|
|
||||||
|
row.connect_move(clone!(
|
||||||
|
#[weak(rename_to = this)]
|
||||||
|
self,
|
||||||
|
move |target, source| {
|
||||||
|
let mut performer_rows = this.imp().performer_rows.borrow_mut();
|
||||||
|
if let Some(index) = performer_rows.iter().position(|p| p == target) {
|
||||||
|
this.imp().performer_list.remove(&source);
|
||||||
|
performer_rows.retain(|p| p != &source);
|
||||||
|
this.imp().performer_list.insert(&source, index as i32);
|
||||||
|
performer_rows.insert(index, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
row.connect_remove(clone!(
|
row.connect_remove(clone!(
|
||||||
#[weak(rename_to = this)]
|
#[weak(rename_to = this)]
|
||||||
self,
|
self,
|
||||||
|
|
@ -298,6 +312,20 @@ impl RecordingEditor {
|
||||||
ensemble_performer,
|
ensemble_performer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
row.connect_move(clone!(
|
||||||
|
#[weak(rename_to = this)]
|
||||||
|
self,
|
||||||
|
move |target, source| {
|
||||||
|
let mut ensemble_rows = this.imp().ensemble_rows.borrow_mut();
|
||||||
|
if let Some(index) = ensemble_rows.iter().position(|p| p == target) {
|
||||||
|
this.imp().ensemble_list.remove(&source);
|
||||||
|
ensemble_rows.retain(|p| p != &source);
|
||||||
|
this.imp().ensemble_list.insert(&source, index as i32);
|
||||||
|
ensemble_rows.insert(index, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
row.connect_remove(clone!(
|
row.connect_remove(clone!(
|
||||||
#[weak(rename_to = this)]
|
#[weak(rename_to = this)]
|
||||||
self,
|
self,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
use std::cell::{OnceCell, RefCell};
|
use std::cell::{OnceCell, RefCell};
|
||||||
|
|
||||||
use adw::{prelude::*, subclass::prelude::*};
|
use adw::{prelude::*, subclass::prelude::*};
|
||||||
use gtk::glib::{self, clone, subclass::Signal, Properties};
|
use gtk::{
|
||||||
|
gdk,
|
||||||
|
glib::{self, clone, subclass::Signal, Properties},
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::models::EnsemblePerformer, editor::role::RoleEditor, library::Library,
|
db::models::EnsemblePerformer, editor::role::RoleEditor, library::Library,
|
||||||
selector::role::RoleSelectorPopover,
|
selector::role::RoleSelectorPopover, util::drag_widget::DragWidget,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
|
|
@ -50,8 +53,14 @@ mod imp {
|
||||||
#[glib::derived_properties]
|
#[glib::derived_properties]
|
||||||
impl ObjectImpl for RecordingEditorEnsembleRow {
|
impl ObjectImpl for RecordingEditorEnsembleRow {
|
||||||
fn signals() -> &'static [Signal] {
|
fn signals() -> &'static [Signal] {
|
||||||
static SIGNALS: Lazy<Vec<Signal>> =
|
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
||||||
Lazy::new(|| vec![Signal::builder("remove").build()]);
|
vec![
|
||||||
|
Signal::builder("remove").build(),
|
||||||
|
Signal::builder("move")
|
||||||
|
.param_types([super::RecordingEditorEnsembleRow::static_type()])
|
||||||
|
.build(),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
SIGNALS.as_ref()
|
SIGNALS.as_ref()
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +68,44 @@ mod imp {
|
||||||
fn constructed(&self) {
|
fn constructed(&self) {
|
||||||
self.parent_constructed();
|
self.parent_constructed();
|
||||||
|
|
||||||
|
let drag_source = gtk::DragSource::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.content(&gdk::ContentProvider::for_value(&self.obj().to_value()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
drag_source.connect_drag_begin(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
move |_, drag| {
|
||||||
|
let icon = gtk::DragIcon::for_drag(drag);
|
||||||
|
icon.set_child(Some(&DragWidget::new(&obj)));
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drag_source);
|
||||||
|
|
||||||
|
let drop_target = gtk::DropTarget::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.build();
|
||||||
|
drop_target.set_types(&[Self::Type::static_type()]);
|
||||||
|
|
||||||
|
drop_target.connect_drop(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
#[upgrade_or]
|
||||||
|
false,
|
||||||
|
move |_, value, _, _| {
|
||||||
|
if let Ok(row) = value.get::<Self::Type>() {
|
||||||
|
obj.emit_by_name::<()>("move", &[&row]);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drop_target);
|
||||||
|
|
||||||
let role_popover = RoleSelectorPopover::new(self.library.get().unwrap());
|
let role_popover = RoleSelectorPopover::new(self.library.get().unwrap());
|
||||||
|
|
||||||
let obj = self.obj().to_owned();
|
let obj = self.obj().to_owned();
|
||||||
|
|
@ -118,6 +165,15 @@ impl RecordingEditorEnsembleRow {
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn connect_move<F: Fn(&Self, Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
|
self.connect_local("move", true, move |values| {
|
||||||
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
let source = values[1].get::<Self>().unwrap();
|
||||||
|
f(&obj, source);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn connect_remove<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
pub fn connect_remove<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
self.connect_local("remove", true, move |values| {
|
self.connect_local("remove", true, move |values| {
|
||||||
let obj = values[0].get::<Self>().unwrap();
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
use std::cell::{OnceCell, RefCell};
|
use std::cell::{OnceCell, RefCell};
|
||||||
|
|
||||||
use adw::{prelude::*, subclass::prelude::*};
|
use adw::{prelude::*, subclass::prelude::*};
|
||||||
use gtk::glib::{self, clone, subclass::Signal, Properties};
|
use gtk::{
|
||||||
|
gdk,
|
||||||
|
glib::{self, clone, subclass::Signal, Properties},
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::models::Performer, editor::role::RoleEditor, library::Library,
|
db::models::Performer, editor::role::RoleEditor, library::Library,
|
||||||
selector::performer_role::PerformerRoleSelectorPopover,
|
selector::performer_role::PerformerRoleSelectorPopover, util::drag_widget::DragWidget,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
|
|
@ -51,8 +54,14 @@ mod imp {
|
||||||
#[glib::derived_properties]
|
#[glib::derived_properties]
|
||||||
impl ObjectImpl for RecordingEditorPerformerRow {
|
impl ObjectImpl for RecordingEditorPerformerRow {
|
||||||
fn signals() -> &'static [Signal] {
|
fn signals() -> &'static [Signal] {
|
||||||
static SIGNALS: Lazy<Vec<Signal>> =
|
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
||||||
Lazy::new(|| vec![Signal::builder("remove").build()]);
|
vec![
|
||||||
|
Signal::builder("remove").build(),
|
||||||
|
Signal::builder("move")
|
||||||
|
.param_types([super::RecordingEditorPerformerRow::static_type()])
|
||||||
|
.build(),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
SIGNALS.as_ref()
|
SIGNALS.as_ref()
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +69,44 @@ mod imp {
|
||||||
fn constructed(&self) {
|
fn constructed(&self) {
|
||||||
self.parent_constructed();
|
self.parent_constructed();
|
||||||
|
|
||||||
|
let drag_source = gtk::DragSource::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.content(&gdk::ContentProvider::for_value(&self.obj().to_value()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
drag_source.connect_drag_begin(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
move |_, drag| {
|
||||||
|
let icon = gtk::DragIcon::for_drag(drag);
|
||||||
|
icon.set_child(Some(&DragWidget::new(&obj)));
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drag_source);
|
||||||
|
|
||||||
|
let drop_target = gtk::DropTarget::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.build();
|
||||||
|
drop_target.set_types(&[Self::Type::static_type()]);
|
||||||
|
|
||||||
|
drop_target.connect_drop(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
#[upgrade_or]
|
||||||
|
false,
|
||||||
|
move |_, value, _, _| {
|
||||||
|
if let Ok(row) = value.get::<Self::Type>() {
|
||||||
|
obj.emit_by_name::<()>("move", &[&row]);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drop_target);
|
||||||
|
|
||||||
let role_popover = PerformerRoleSelectorPopover::new(self.library.get().unwrap());
|
let role_popover = PerformerRoleSelectorPopover::new(self.library.get().unwrap());
|
||||||
|
|
||||||
let obj = self.obj().to_owned();
|
let obj = self.obj().to_owned();
|
||||||
|
|
@ -142,6 +189,15 @@ impl RecordingEditorPerformerRow {
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn connect_move<F: Fn(&Self, Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
|
self.connect_local("move", true, move |values| {
|
||||||
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
let source = values[1].get::<Self>().unwrap();
|
||||||
|
f(&obj, source);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn connect_remove<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
pub fn connect_remove<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
self.connect_local("remove", true, move |values| {
|
self.connect_local("remove", true, move |values| {
|
||||||
let obj = values[0].get::<Self>().unwrap();
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -268,6 +268,20 @@ impl TracksEditor {
|
||||||
let track_row =
|
let track_row =
|
||||||
TracksEditorTrackRow::new(&self.navigation(), &self.library(), recording, track_data);
|
TracksEditorTrackRow::new(&self.navigation(), &self.library(), recording, track_data);
|
||||||
|
|
||||||
|
track_row.connect_move(clone!(
|
||||||
|
#[weak(rename_to = this)]
|
||||||
|
self,
|
||||||
|
move |target, source| {
|
||||||
|
let mut track_rows = this.imp().track_rows.borrow_mut();
|
||||||
|
if let Some(index) = track_rows.iter().position(|p| p == target) {
|
||||||
|
this.imp().track_list.remove(&source);
|
||||||
|
track_rows.retain(|p| p != &source);
|
||||||
|
this.imp().track_list.insert(&source, index as i32);
|
||||||
|
track_rows.insert(index, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
track_row.connect_remove(clone!(
|
track_row.connect_remove(clone!(
|
||||||
#[weak(rename_to = this)]
|
#[weak(rename_to = this)]
|
||||||
self,
|
self,
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use gtk::{
|
||||||
};
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{activatable_row::ActivatableRow, db::models::Work};
|
use crate::{db::models::Work, util::activatable_row::ActivatableRow};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,17 @@ use std::{
|
||||||
use adw::{prelude::*, subclass::prelude::*};
|
use adw::{prelude::*, subclass::prelude::*};
|
||||||
use formatx::formatx;
|
use formatx::formatx;
|
||||||
use gettextrs::gettext;
|
use gettextrs::gettext;
|
||||||
use gtk::glib::{self, clone, subclass::Signal, Properties};
|
use gtk::{
|
||||||
|
gdk,
|
||||||
|
glib::{self, clone, subclass::Signal, Properties},
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use super::parts_popover::TracksEditorPartsPopover;
|
use super::parts_popover::TracksEditorPartsPopover;
|
||||||
use crate::{
|
use crate::{
|
||||||
db::models::{Recording, Track, Work},
|
db::models::{Recording, Track, Work},
|
||||||
library::Library,
|
library::Library,
|
||||||
|
util::drag_widget::DragWidget,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
|
|
@ -35,6 +39,8 @@ mod imp {
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub select_parts_box: TemplateChild<gtk::Box>,
|
pub select_parts_box: TemplateChild<gtk::Box>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
|
pub edit_image: TemplateChild<gtk::Image>,
|
||||||
|
#[template_child]
|
||||||
pub reset_button: TemplateChild<gtk::Button>,
|
pub reset_button: TemplateChild<gtk::Button>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,11 +63,59 @@ mod imp {
|
||||||
#[glib::derived_properties]
|
#[glib::derived_properties]
|
||||||
impl ObjectImpl for TracksEditorTrackRow {
|
impl ObjectImpl for TracksEditorTrackRow {
|
||||||
fn signals() -> &'static [Signal] {
|
fn signals() -> &'static [Signal] {
|
||||||
static SIGNALS: Lazy<Vec<Signal>> =
|
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
||||||
Lazy::new(|| vec![Signal::builder("remove").build()]);
|
vec![
|
||||||
|
Signal::builder("remove").build(),
|
||||||
|
Signal::builder("move")
|
||||||
|
.param_types([super::TracksEditorTrackRow::static_type()])
|
||||||
|
.build(),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
SIGNALS.as_ref()
|
SIGNALS.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn constructed(&self) {
|
||||||
|
self.parent_constructed();
|
||||||
|
|
||||||
|
let drag_source = gtk::DragSource::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.content(&gdk::ContentProvider::for_value(&self.obj().to_value()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
drag_source.connect_drag_begin(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
move |_, drag| {
|
||||||
|
let icon = gtk::DragIcon::for_drag(drag);
|
||||||
|
icon.set_child(Some(&DragWidget::new(&obj)));
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drag_source);
|
||||||
|
|
||||||
|
let drop_target = gtk::DropTarget::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.build();
|
||||||
|
drop_target.set_types(&[Self::Type::static_type()]);
|
||||||
|
|
||||||
|
drop_target.connect_drop(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
#[upgrade_or]
|
||||||
|
false,
|
||||||
|
move |_, value, _, _| {
|
||||||
|
if let Ok(row) = value.get::<Self::Type>() {
|
||||||
|
obj.emit_by_name::<()>("move", &[&row]);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drop_target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WidgetImpl for TracksEditorTrackRow {}
|
impl WidgetImpl for TracksEditorTrackRow {}
|
||||||
|
|
@ -89,6 +143,9 @@ impl TracksEditorTrackRow {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
obj.set_activatable(!recording.work.parts.is_empty());
|
obj.set_activatable(!recording.work.parts.is_empty());
|
||||||
|
obj.imp()
|
||||||
|
.edit_image
|
||||||
|
.set_visible(!recording.work.parts.is_empty());
|
||||||
|
|
||||||
obj.set_subtitle(&match &track_data.location {
|
obj.set_subtitle(&match &track_data.location {
|
||||||
TrackLocation::Undefined => String::new(),
|
TrackLocation::Undefined => String::new(),
|
||||||
|
|
@ -127,6 +184,15 @@ impl TracksEditorTrackRow {
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn connect_move<F: Fn(&Self, Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
|
self.connect_local("move", true, move |values| {
|
||||||
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
let source = values[1].get::<Self>().unwrap();
|
||||||
|
f(&obj, source);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn connect_remove<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
pub fn connect_remove<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
self.connect_local("remove", true, move |values| {
|
self.connect_local("remove", true, move |values| {
|
||||||
let obj = values[0].get::<Self>().unwrap();
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
mod composer_row;
|
mod composer_row;
|
||||||
|
mod instrument_row;
|
||||||
mod part_row;
|
mod part_row;
|
||||||
|
|
||||||
use std::cell::{Cell, OnceCell, RefCell};
|
use std::cell::{Cell, OnceCell, RefCell};
|
||||||
|
|
@ -19,6 +20,7 @@ use crate::{
|
||||||
library::Library,
|
library::Library,
|
||||||
selector::{instrument::InstrumentSelectorPopover, person::PersonSelectorPopover},
|
selector::{instrument::InstrumentSelectorPopover, person::PersonSelectorPopover},
|
||||||
};
|
};
|
||||||
|
use instrument_row::InstrumentRow;
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
@ -41,8 +43,7 @@ mod imp {
|
||||||
// handle all state related to the composer.
|
// handle all state related to the composer.
|
||||||
pub composer_rows: RefCell<Vec<WorkEditorComposerRow>>,
|
pub composer_rows: RefCell<Vec<WorkEditorComposerRow>>,
|
||||||
pub part_rows: RefCell<Vec<WorkEditorPartRow>>,
|
pub part_rows: RefCell<Vec<WorkEditorPartRow>>,
|
||||||
|
pub instrument_rows: RefCell<Vec<InstrumentRow>>,
|
||||||
pub instruments: RefCell<Vec<Instrument>>,
|
|
||||||
|
|
||||||
pub persons_popover: OnceCell<PersonSelectorPopover>,
|
pub persons_popover: OnceCell<PersonSelectorPopover>,
|
||||||
pub instruments_popover: OnceCell<InstrumentSelectorPopover>,
|
pub instruments_popover: OnceCell<InstrumentSelectorPopover>,
|
||||||
|
|
@ -240,6 +241,20 @@ impl WorkEditor {
|
||||||
fn add_part_row(&self, part: Work) {
|
fn add_part_row(&self, part: Work) {
|
||||||
let row = WorkEditorPartRow::new(&self.navigation(), &self.library(), part);
|
let row = WorkEditorPartRow::new(&self.navigation(), &self.library(), part);
|
||||||
|
|
||||||
|
row.connect_move(clone!(
|
||||||
|
#[weak(rename_to = this)]
|
||||||
|
self,
|
||||||
|
move |target, source| {
|
||||||
|
let mut part_rows = this.imp().part_rows.borrow_mut();
|
||||||
|
if let Some(index) = part_rows.iter().position(|p| p == target) {
|
||||||
|
this.imp().part_list.remove(&source);
|
||||||
|
part_rows.retain(|p| p != &source);
|
||||||
|
this.imp().part_list.insert(&source, index as i32);
|
||||||
|
part_rows.insert(index, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
row.connect_remove(clone!(
|
row.connect_remove(clone!(
|
||||||
#[weak(rename_to = this)]
|
#[weak(rename_to = this)]
|
||||||
self,
|
self,
|
||||||
|
|
@ -259,6 +274,20 @@ impl WorkEditor {
|
||||||
fn add_composer_row(&self, composer: Composer) {
|
fn add_composer_row(&self, composer: Composer) {
|
||||||
let row = WorkEditorComposerRow::new(&self.navigation(), &self.library(), composer);
|
let row = WorkEditorComposerRow::new(&self.navigation(), &self.library(), composer);
|
||||||
|
|
||||||
|
row.connect_move(clone!(
|
||||||
|
#[weak(rename_to = this)]
|
||||||
|
self,
|
||||||
|
move |target, source| {
|
||||||
|
let mut composer_rows = this.imp().composer_rows.borrow_mut();
|
||||||
|
if let Some(index) = composer_rows.iter().position(|p| p == target) {
|
||||||
|
this.imp().composer_list.remove(&source);
|
||||||
|
composer_rows.retain(|p| p != &source);
|
||||||
|
this.imp().composer_list.insert(&source, index as i32);
|
||||||
|
composer_rows.insert(index, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
row.connect_remove(clone!(
|
row.connect_remove(clone!(
|
||||||
#[weak(rename_to = this)]
|
#[weak(rename_to = this)]
|
||||||
self,
|
self,
|
||||||
|
|
@ -276,39 +305,36 @@ impl WorkEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_instrument_row(&self, instrument: Instrument) {
|
fn add_instrument_row(&self, instrument: Instrument) {
|
||||||
let row = adw::ActionRow::builder()
|
let row = InstrumentRow::new(instrument);
|
||||||
.title(instrument.to_string())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let remove_button = gtk::Button::builder()
|
row.connect_move(clone!(
|
||||||
.icon_name("user-trash-symbolic")
|
|
||||||
.valign(gtk::Align::Center)
|
|
||||||
.css_classes(["flat"])
|
|
||||||
.build();
|
|
||||||
|
|
||||||
remove_button.connect_clicked(clone!(
|
|
||||||
#[weak(rename_to = this)]
|
#[weak(rename_to = this)]
|
||||||
self,
|
self,
|
||||||
#[weak]
|
move |target, source| {
|
||||||
row,
|
let mut instrument_rows = this.imp().instrument_rows.borrow_mut();
|
||||||
#[strong]
|
if let Some(index) = instrument_rows.iter().position(|p| p == target) {
|
||||||
instrument,
|
this.imp().instrument_list.remove(&source);
|
||||||
move |_| {
|
instrument_rows.retain(|p| p != &source);
|
||||||
this.imp().instrument_list.remove(&row);
|
this.imp().instrument_list.insert(&source, index as i32);
|
||||||
this.imp()
|
instrument_rows.insert(index, source);
|
||||||
.instruments
|
}
|
||||||
.borrow_mut()
|
|
||||||
.retain(|i| *i != instrument);
|
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
row.add_suffix(&remove_button);
|
row.connect_remove(clone!(
|
||||||
|
#[weak(rename_to = this)]
|
||||||
|
self,
|
||||||
|
move |row| {
|
||||||
|
this.imp().instrument_list.remove(row);
|
||||||
|
this.imp().instrument_rows.borrow_mut().retain(|p| p != row);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
self.imp()
|
self.imp()
|
||||||
.instrument_list
|
.instrument_list
|
||||||
.insert(&row, self.imp().instruments.borrow().len() as i32);
|
.insert(&row, self.imp().instrument_rows.borrow().len() as i32);
|
||||||
|
|
||||||
self.imp().instruments.borrow_mut().push(instrument);
|
self.imp().instrument_rows.borrow_mut().push(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
|
@ -332,7 +358,14 @@ impl WorkEditor {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| c.composer())
|
.map(|c| c.composer())
|
||||||
.collect::<Vec<Composer>>();
|
.collect::<Vec<Composer>>();
|
||||||
let instruments = self.imp().instruments.borrow().clone();
|
|
||||||
|
let instruments = self
|
||||||
|
.imp()
|
||||||
|
.instrument_rows
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.map(|r| r.instrument())
|
||||||
|
.collect::<Vec<Instrument>>();
|
||||||
|
|
||||||
if self.imp().is_part_editor.get() {
|
if self.imp().is_part_editor.get() {
|
||||||
let work_id = self
|
let work_id = self
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
use std::cell::{OnceCell, RefCell};
|
use std::cell::{OnceCell, RefCell};
|
||||||
|
|
||||||
use adw::{prelude::*, subclass::prelude::*};
|
use adw::{prelude::*, subclass::prelude::*};
|
||||||
use gtk::glib::{self, clone, subclass::Signal, Properties};
|
use gtk::{
|
||||||
|
gdk,
|
||||||
|
glib::{self, clone, subclass::Signal, Properties},
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::models::Composer, editor::role::RoleEditor, library::Library,
|
db::models::Composer, editor::role::RoleEditor, library::Library,
|
||||||
selector::role::RoleSelectorPopover,
|
selector::role::RoleSelectorPopover, util::drag_widget::DragWidget,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
|
|
@ -50,8 +53,14 @@ mod imp {
|
||||||
#[glib::derived_properties]
|
#[glib::derived_properties]
|
||||||
impl ObjectImpl for WorkEditorComposerRow {
|
impl ObjectImpl for WorkEditorComposerRow {
|
||||||
fn signals() -> &'static [Signal] {
|
fn signals() -> &'static [Signal] {
|
||||||
static SIGNALS: Lazy<Vec<Signal>> =
|
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
||||||
Lazy::new(|| vec![Signal::builder("remove").build()]);
|
vec![
|
||||||
|
Signal::builder("remove").build(),
|
||||||
|
Signal::builder("move")
|
||||||
|
.param_types([super::WorkEditorComposerRow::static_type()])
|
||||||
|
.build(),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
SIGNALS.as_ref()
|
SIGNALS.as_ref()
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +68,44 @@ mod imp {
|
||||||
fn constructed(&self) {
|
fn constructed(&self) {
|
||||||
self.parent_constructed();
|
self.parent_constructed();
|
||||||
|
|
||||||
|
let drag_source = gtk::DragSource::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.content(&gdk::ContentProvider::for_value(&self.obj().to_value()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
drag_source.connect_drag_begin(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
move |_, drag| {
|
||||||
|
let icon = gtk::DragIcon::for_drag(drag);
|
||||||
|
icon.set_child(Some(&DragWidget::new(&obj)));
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drag_source);
|
||||||
|
|
||||||
|
let drop_target = gtk::DropTarget::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.build();
|
||||||
|
drop_target.set_types(&[Self::Type::static_type()]);
|
||||||
|
|
||||||
|
drop_target.connect_drop(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
#[upgrade_or]
|
||||||
|
false,
|
||||||
|
move |_, value, _, _| {
|
||||||
|
if let Ok(row) = value.get::<Self::Type>() {
|
||||||
|
obj.emit_by_name::<()>("move", &[&row]);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drop_target);
|
||||||
|
|
||||||
let role_popover = RoleSelectorPopover::new(self.library.get().unwrap());
|
let role_popover = RoleSelectorPopover::new(self.library.get().unwrap());
|
||||||
|
|
||||||
let obj = self.obj().to_owned();
|
let obj = self.obj().to_owned();
|
||||||
|
|
@ -114,6 +161,15 @@ impl WorkEditorComposerRow {
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn connect_move<F: Fn(&Self, Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
|
self.connect_local("move", true, move |values| {
|
||||||
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
let source = values[1].get::<Self>().unwrap();
|
||||||
|
f(&obj, source);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn connect_remove<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
pub fn connect_remove<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
self.connect_local("remove", true, move |values| {
|
self.connect_local("remove", true, move |values| {
|
||||||
let obj = values[0].get::<Self>().unwrap();
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
|
|
||||||
139
src/editor/work/instrument_row.rs
Normal file
139
src/editor/work/instrument_row.rs
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
use std::cell::OnceCell;
|
||||||
|
|
||||||
|
use adw::{prelude::*, subclass::prelude::*};
|
||||||
|
use gtk::{
|
||||||
|
gdk,
|
||||||
|
glib::{self, clone, subclass::Signal},
|
||||||
|
};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
|
use crate::{db::models::Instrument, util::drag_widget::DragWidget};
|
||||||
|
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||||
|
#[template(file = "data/ui/editor/work/instrument_row.blp")]
|
||||||
|
pub struct InstrumentRow {
|
||||||
|
pub instrument: OnceCell<Instrument>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for InstrumentRow {
|
||||||
|
const NAME: &'static str = "MusicusWorkEditorInstrumentRow";
|
||||||
|
type Type = super::InstrumentRow;
|
||||||
|
type ParentType = adw::ActionRow;
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.bind_template();
|
||||||
|
klass.bind_template_instance_callbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||||
|
obj.init_template();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for InstrumentRow {
|
||||||
|
fn signals() -> &'static [Signal] {
|
||||||
|
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
||||||
|
vec![
|
||||||
|
Signal::builder("remove").build(),
|
||||||
|
Signal::builder("move")
|
||||||
|
.param_types([super::InstrumentRow::static_type()])
|
||||||
|
.build(),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
SIGNALS.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constructed(&self) {
|
||||||
|
self.parent_constructed();
|
||||||
|
|
||||||
|
let drag_source = gtk::DragSource::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.content(&gdk::ContentProvider::for_value(&self.obj().to_value()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
drag_source.connect_drag_begin(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
move |_, drag| {
|
||||||
|
let icon = gtk::DragIcon::for_drag(drag);
|
||||||
|
icon.set_child(Some(&DragWidget::new(&obj)));
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drag_source);
|
||||||
|
|
||||||
|
let drop_target = gtk::DropTarget::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.build();
|
||||||
|
drop_target.set_types(&[Self::Type::static_type()]);
|
||||||
|
|
||||||
|
drop_target.connect_drop(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
#[upgrade_or]
|
||||||
|
false,
|
||||||
|
move |_, value, _, _| {
|
||||||
|
if let Ok(row) = value.get::<Self::Type>() {
|
||||||
|
obj.emit_by_name::<()>("move", &[&row]);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drop_target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetImpl for InstrumentRow {}
|
||||||
|
impl ListBoxRowImpl for InstrumentRow {}
|
||||||
|
impl PreferencesRowImpl for InstrumentRow {}
|
||||||
|
impl ActionRowImpl for InstrumentRow {}
|
||||||
|
}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct InstrumentRow(ObjectSubclass<imp::InstrumentRow>)
|
||||||
|
@extends gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow, adw::ActionRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gtk::template_callbacks]
|
||||||
|
impl InstrumentRow {
|
||||||
|
pub fn new(instrument: Instrument) -> Self {
|
||||||
|
let obj: Self = glib::Object::new();
|
||||||
|
obj.set_title(&instrument.to_string());
|
||||||
|
obj.imp().instrument.set(instrument).unwrap();
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connect_move<F: Fn(&Self, Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
|
self.connect_local("move", true, move |values| {
|
||||||
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
let source = values[1].get::<Self>().unwrap();
|
||||||
|
f(&obj, source);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connect_remove<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
|
self.connect_local("remove", true, move |values| {
|
||||||
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
f(&obj);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn instrument(&self) -> Instrument {
|
||||||
|
self.imp().instrument.get().unwrap().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[template_callback]
|
||||||
|
fn remove(&self) {
|
||||||
|
self.emit_by_name::<()>("remove", &[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
use std::cell::{OnceCell, RefCell};
|
use std::cell::{OnceCell, RefCell};
|
||||||
|
|
||||||
use adw::{prelude::*, subclass::prelude::*};
|
use adw::{prelude::*, subclass::prelude::*};
|
||||||
use gtk::glib::{self, clone, subclass::Signal, Properties};
|
use gtk::{
|
||||||
|
gdk,
|
||||||
|
glib::{self, clone, subclass::Signal, Properties},
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{db::models::Work, editor::work::WorkEditor, library::Library};
|
use crate::{
|
||||||
|
db::models::Work, editor::work::WorkEditor, library::Library, util::drag_widget::DragWidget,
|
||||||
|
};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Properties, Debug, Default, gtk::CompositeTemplate)]
|
#[derive(Properties, Debug, Default, gtk::CompositeTemplate)]
|
||||||
|
|
@ -42,11 +46,59 @@ mod imp {
|
||||||
#[glib::derived_properties]
|
#[glib::derived_properties]
|
||||||
impl ObjectImpl for WorkEditorPartRow {
|
impl ObjectImpl for WorkEditorPartRow {
|
||||||
fn signals() -> &'static [Signal] {
|
fn signals() -> &'static [Signal] {
|
||||||
static SIGNALS: Lazy<Vec<Signal>> =
|
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
||||||
Lazy::new(|| vec![Signal::builder("remove").build()]);
|
vec![
|
||||||
|
Signal::builder("remove").build(),
|
||||||
|
Signal::builder("move")
|
||||||
|
.param_types([super::WorkEditorPartRow::static_type()])
|
||||||
|
.build(),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
SIGNALS.as_ref()
|
SIGNALS.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn constructed(&self) {
|
||||||
|
self.parent_constructed();
|
||||||
|
|
||||||
|
let drag_source = gtk::DragSource::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.content(&gdk::ContentProvider::for_value(&self.obj().to_value()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
drag_source.connect_drag_begin(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
move |_, drag| {
|
||||||
|
let icon = gtk::DragIcon::for_drag(drag);
|
||||||
|
icon.set_child(Some(&DragWidget::new(&obj)));
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drag_source);
|
||||||
|
|
||||||
|
let drop_target = gtk::DropTarget::builder()
|
||||||
|
.actions(gdk::DragAction::MOVE)
|
||||||
|
.build();
|
||||||
|
drop_target.set_types(&[Self::Type::static_type()]);
|
||||||
|
|
||||||
|
drop_target.connect_drop(clone!(
|
||||||
|
#[weak(rename_to = obj)]
|
||||||
|
self.obj(),
|
||||||
|
#[upgrade_or]
|
||||||
|
false,
|
||||||
|
move |_, value, _, _| {
|
||||||
|
if let Ok(row) = value.get::<Self::Type>() {
|
||||||
|
obj.emit_by_name::<()>("move", &[&row]);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
self.obj().add_controller(drop_target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WidgetImpl for WorkEditorPartRow {}
|
impl WidgetImpl for WorkEditorPartRow {}
|
||||||
|
|
@ -71,6 +123,15 @@ impl WorkEditorPartRow {
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn connect_move<F: Fn(&Self, Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
|
self.connect_local("move", true, move |values| {
|
||||||
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
let source = values[1].get::<Self>().unwrap();
|
||||||
|
f(&obj, source);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn connect_remove<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
pub fn connect_remove<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
||||||
self.connect_local("remove", true, move |values| {
|
self.connect_local("remove", true, move |values| {
|
||||||
let obj = values[0].get::<Self>().unwrap();
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
mod activatable_row;
|
|
||||||
mod album_tile;
|
mod album_tile;
|
||||||
mod application;
|
mod application;
|
||||||
mod config;
|
mod config;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use gtk::{
|
||||||
};
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{activatable_row::ActivatableRow, db::models::Ensemble, library::Library};
|
use crate::{db::models::Ensemble, library::Library, util::activatable_row::ActivatableRow};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use gtk::{
|
||||||
};
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{activatable_row::ActivatableRow, db::models::Instrument, library::Library};
|
use crate::{db::models::Instrument, library::Library, util::activatable_row::ActivatableRow};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ use gtk::{
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
activatable_row::ActivatableRow,
|
|
||||||
db::models::{Instrument, Role},
|
db::models::{Instrument, Role},
|
||||||
library::Library,
|
library::Library,
|
||||||
|
util::activatable_row::ActivatableRow,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use gtk::{
|
||||||
};
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{activatable_row::ActivatableRow, db::models::Person, library::Library};
|
use crate::{db::models::Person, library::Library, util::activatable_row::ActivatableRow};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ use gtk::{
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
activatable_row::ActivatableRow,
|
|
||||||
db::models::{Person, Recording, Work},
|
db::models::{Person, Recording, Work},
|
||||||
library::Library,
|
library::Library,
|
||||||
|
util::activatable_row::ActivatableRow,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use gtk::{
|
||||||
};
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{activatable_row::ActivatableRow, db::models::Role, library::Library};
|
use crate::{db::models::Role, library::Library, util::activatable_row::ActivatableRow};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ use gtk::{
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
activatable_row::ActivatableRow,
|
|
||||||
db::models::{Person, Work},
|
db::models::{Person, Work},
|
||||||
library::Library,
|
library::Library,
|
||||||
|
util::activatable_row::ActivatableRow,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
pub mod activatable_row;
|
||||||
|
pub mod drag_widget;
|
||||||
|
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
|
|
||||||
41
src/util/drag_widget.rs
Normal file
41
src/util/drag_widget.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
use adw::{prelude::*, subclass::prelude::*};
|
||||||
|
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct DragWidget {}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for DragWidget {
|
||||||
|
const NAME: &'static str = "MusicusDragWidget";
|
||||||
|
type Type = super::DragWidget;
|
||||||
|
type ParentType = adw::Bin;
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.set_css_name("dragwidget");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for DragWidget {}
|
||||||
|
impl WidgetImpl for DragWidget {}
|
||||||
|
impl BinImpl for DragWidget {}
|
||||||
|
}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
/// A simple helper widget for displaying a drag icon for a widget.
|
||||||
|
pub struct DragWidget(ObjectSubclass<imp::DragWidget>)
|
||||||
|
@extends gtk::Widget, adw::Bin;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DragWidget {
|
||||||
|
pub fn new<W>(widget: &W) -> Self
|
||||||
|
where
|
||||||
|
W: IsA<gtk::Widget>,
|
||||||
|
{
|
||||||
|
let obj: Self = glib::Object::new();
|
||||||
|
let picture = gtk::Picture::for_paintable(>k::WidgetPaintable::new(Some(widget)));
|
||||||
|
obj.set_child(Some(&picture));
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue