2022-01-04 13:54:25 -05:00
use cascade ::cascade ;
2022-01-04 15:12:40 -05:00
use gio ::DesktopAppInfo ;
2022-01-04 13:54:25 -05:00
use gtk4 ::subclass ::prelude ::* ;
use gtk4 ::{ gio , glib } ;
use gtk4 ::{ prelude ::* , Label } ;
2022-01-04 15:12:40 -05:00
use gtk4 ::{ Box , Button , Image , ListBox , Orientation , Revealer , Window } ;
2022-01-04 13:54:25 -05:00
2022-01-04 15:12:40 -05:00
use crate ::dock_object ::{ self , DockObject } ;
2022-01-04 13:54:25 -05:00
use crate ::utils ::BoxedWindowList ;
2022-01-04 15:12:40 -05:00
use crate ::Event ;
2022-01-04 15:30:38 -05:00
use crate ::Item ;
2022-01-04 15:12:40 -05:00
use crate ::TX ;
2022-01-04 13:54:25 -05:00
mod imp ;
glib ::wrapper! {
pub struct DockPopover ( ObjectSubclass < imp ::DockPopover > )
@ extends gtk4 ::Widget , gtk4 ::Box ,
@ implements gtk4 ::Accessible , gtk4 ::Buildable , gtk4 ::ConstraintTarget , gtk4 ::Orientable ;
}
impl Default for DockPopover {
fn default ( ) -> Self {
Self ::new ( )
}
}
impl DockPopover {
pub fn new ( ) -> Self {
let self_ : DockPopover = glib ::Object ::new ( & [ ] ) . expect ( " Failed to create DockList " ) ;
self_ . layout ( ) ;
//dnd behavior is different for each type, as well as the data in the model
self_
}
pub fn set_dock_object ( & self , dock_object : & DockObject , update_layout : bool ) {
let imp = imp ::DockPopover ::from_instance ( & self ) ;
imp . dock_object . replace ( Some ( dock_object . clone ( ) ) ) ;
if update_layout {
self . update_layout ( ) ;
}
}
pub fn update_layout ( & self ) {
let imp = imp ::DockPopover ::from_instance ( & self ) ;
let dock_object = imp . dock_object . borrow ( ) ;
2022-01-06 10:50:47 -05:00
let menu_handle = imp . menu_handle . borrow ( ) ;
2022-01-04 13:54:25 -05:00
// build menu
if let Some ( dock_object ) = dock_object . as_ref ( ) {
cascade! {
& self ;
.. set_spacing ( 4 ) ;
.. set_orientation ( Orientation ::Vertical ) ;
.. set_hexpand ( true ) ;
} ;
let all_windows_item_container = cascade! {
Box ::new ( Orientation ::Vertical , 4 ) ;
} ;
menu_handle . append ( & all_windows_item_container ) ;
2022-01-05 15:37:04 -05:00
// let all_windows_item_header = cascade! {
// Button::new();
// ..set_hexpand(true);
// };
// all_windows_item_container.append(&all_windows_item_header);
2022-01-04 13:54:25 -05:00
2022-01-05 15:37:04 -05:00
// let all_windows_item_header_box = cascade! {
// Box::new(Orientation::Horizontal, 4);
// ..set_hexpand(true);
// };
// all_windows_item_header.set_child(Some(&all_windows_item_header_box));
2022-01-04 13:54:25 -05:00
2022-01-05 15:37:04 -05:00
// let all_windows_item_header_title = cascade! {
// Label::new(Some("All Windows"));
// ..add_css_class("header-5");
// ..set_halign(gtk4::Align::Start);
// };
// all_windows_item_header_box.append(&all_windows_item_header_title);
2022-01-04 13:54:25 -05:00
2022-01-05 15:37:04 -05:00
// let all_windows_item_header_icon = cascade! {
// Image::from_icon_name(Some("go-down"));
// ..set_halign(gtk4::Align::End);
// ..set_hexpand(true);
// ..set_pixel_size(16);
// };
// all_windows_item_header_box.append(&all_windows_item_header_icon);
// imp.all_windows_item_header.replace(all_windows_item_header);
2022-01-04 13:54:25 -05:00
if let Ok ( window_list ) = dock_object
. property ( " active " )
. unwrap ( )
. get ::< BoxedWindowList > ( )
{
if window_list . 0. len ( ) = = 0 {
all_windows_item_container . hide ( ) ;
} else {
2022-01-05 15:37:04 -05:00
// let window_list_revealer = cascade! {
// Revealer::new();
// ..set_reveal_child(false);
// ..set_transition_type(gtk4::RevealerTransitionType::SlideDown);
// };
// all_windows_item_container.append(&window_list_revealer);
2022-01-04 13:54:25 -05:00
let window_listbox = cascade! {
ListBox ::new ( ) ;
2022-01-04 15:30:38 -05:00
.. set_activate_on_single_click ( true ) ;
2022-01-04 13:54:25 -05:00
} ;
2022-01-05 15:37:04 -05:00
all_windows_item_container . append ( & window_listbox ) ;
2022-01-04 13:54:25 -05:00
for w in window_list . 0 {
let window_box = cascade! {
Box ::new ( Orientation ::Vertical , 4 ) ;
} ;
window_listbox . append ( & window_box ) ;
let window_title = cascade! {
Label ::new ( Some ( w . name . as_str ( ) ) ) ;
2022-01-04 14:03:28 -05:00
.. set_margin_start ( 4 ) ;
.. set_margin_end ( 4 ) ;
.. set_margin_top ( 4 ) ;
.. set_margin_bottom ( 4 ) ;
2022-01-05 15:37:04 -05:00
.. add_css_class ( " title-4 " ) ;
.. add_css_class ( " window_title " ) ;
2022-01-04 13:54:25 -05:00
} ;
// TODO investigate Xembed
let window_image = cascade! {
//TODO fill with image of window
Image ::from_pixbuf ( None ) ;
} ;
window_box . append ( & window_image ) ;
window_box . append ( & window_title ) ;
}
2022-01-05 15:37:04 -05:00
// imp.all_windows_item_revealer.replace(window_list_revealer);
2022-01-04 15:12:40 -05:00
imp . window_list . replace ( window_listbox ) ;
2022-01-04 13:54:25 -05:00
}
}
let launch_item_container = cascade! {
Box ::new ( Orientation ::Vertical , 4 ) ;
.. set_hexpand ( true ) ;
} ;
menu_handle . append ( & launch_item_container ) ;
let launch_new_item = cascade! {
Button ::with_label ( " New Window " ) ;
} ;
launch_item_container . append ( & launch_new_item ) ;
2022-01-04 15:12:40 -05:00
imp . launch_new_item . replace ( launch_new_item ) ;
2022-01-04 13:54:25 -05:00
let favorite_item = cascade! {
Button ::with_label ( if dock_object . property ( " saved " ) . unwrap ( ) . get ::< bool > ( ) . unwrap ( ) { " Remove from Favorites " } else { " Add to Favorites " } ) ;
} ;
menu_handle . append ( & favorite_item ) ;
2022-01-04 15:12:40 -05:00
imp . favorite_item . replace ( favorite_item ) ;
2022-01-04 13:54:25 -05:00
if let Ok ( window_list ) = dock_object
. property ( " active " )
. unwrap ( )
. get ::< BoxedWindowList > ( )
{
if window_list . 0. len ( ) > 1 {
let quit_all_item = cascade! {
Button ::with_label ( format! ( " Quit {} Windows " , window_list . 0. len ( ) ) . as_str ( ) ) ;
} ;
menu_handle . append ( & quit_all_item ) ;
2022-01-04 15:12:40 -05:00
imp . quit_all_item . replace ( quit_all_item ) ;
2022-01-04 13:54:25 -05:00
} else {
let quit_all_item = cascade! {
Button ::with_label ( " Quit " ) ;
} ;
menu_handle . append ( & quit_all_item ) ;
if window_list . 0. len ( ) = = 0 {
quit_all_item . hide ( ) ;
}
2022-01-04 15:12:40 -05:00
imp . quit_all_item . replace ( quit_all_item ) ;
2022-01-04 13:54:25 -05:00
}
}
self . setup_handlers ( ) ;
}
}
fn layout ( & self ) {
let imp = imp ::DockPopover ::from_instance ( & self ) ;
let menu_handle = cascade! {
2022-01-06 10:50:47 -05:00
Box ::new ( Orientation ::Vertical , 4 ) ;
2022-01-04 13:54:25 -05:00
} ;
self . append ( & menu_handle ) ;
imp . menu_handle . replace ( menu_handle ) ;
}
2022-01-04 15:46:43 -05:00
fn emit_hide ( & self ) {
self . emit_by_name ::< & str > ( " menu-hide " , & [ ] ) . unwrap ( ) ;
}
2022-01-06 10:50:47 -05:00
pub fn reset_menu ( & self ) {
// reset menu
let menu_handle = cascade! {
Box ::new ( Orientation ::Vertical , 4 ) ;
} ;
self . append ( & menu_handle ) ;
let imp = imp ::DockPopover ::from_instance ( & self ) ;
let old_menu_handle = imp . menu_handle . replace ( menu_handle ) ;
self . remove ( & old_menu_handle ) ;
}
2022-01-04 13:54:25 -05:00
fn setup_handlers ( & self ) {
2022-01-04 15:12:40 -05:00
let imp = imp ::DockPopover ::from_instance ( & self ) ;
let dock_object = imp . dock_object . borrow ( ) ;
let launch_new_item = imp . launch_new_item . borrow ( ) ;
let favorite_item = imp . favorite_item . borrow ( ) ;
let quit_all_item = imp . quit_all_item . borrow ( ) ;
let window_listbox = imp . window_list . borrow ( ) ;
let all_windows_header = imp . all_windows_item_header . borrow ( ) ;
let revealer = & imp . all_windows_item_revealer ;
if let Some ( dock_object ) = dock_object . as_ref ( ) {
println! ( " setting up popover menu handlers " ) ;
2022-01-04 15:46:43 -05:00
let self_ = self . clone ( ) ;
launch_new_item . connect_clicked ( glib ::clone! ( @ weak dock_object , = > move | _ | {
2022-01-04 15:12:40 -05:00
let app_info = dock_object . property ( " appinfo " ) . expect ( " DockObject must have appinfo property " ) . get ::< Option < DesktopAppInfo > > ( ) . expect ( " Failed to convert value to DesktopAppInfo " ) . unwrap ( ) ;
let window = self_ . root ( ) . unwrap ( ) . downcast ::< Window > ( ) . unwrap ( ) ;
let context = window . display ( ) . app_launch_context ( ) ;
if let Err ( err ) = app_info . launch ( & [ ] , Some ( & context ) ) {
gtk4 ::MessageDialog ::builder ( )
. text ( & format! ( " Failed to start {} " , app_info . name ( ) ) )
. secondary_text ( & err . to_string ( ) )
. message_type ( gtk4 ::MessageType ::Error )
. modal ( true )
. transient_for ( & window )
. build ( )
. show ( ) ;
}
2022-01-04 15:46:43 -05:00
self_ . emit_hide ( ) ;
2022-01-04 15:12:40 -05:00
} ) ) ;
2022-01-04 15:46:43 -05:00
let self_ = self . clone ( ) ;
quit_all_item . connect_clicked ( glib ::clone! ( @ weak dock_object = > move | _ | {
2022-01-04 15:12:40 -05:00
let active = dock_object . property ( " active " ) . expect ( " DockObject must have active property " ) . get ::< BoxedWindowList > ( ) . expect ( " Failed to convert value to WindowList " ) . 0 ;
for w in active {
let entity = w . entity . clone ( ) ;
glib ::MainContext ::default ( ) . spawn_local ( async move {
if let Some ( tx ) = TX . get ( ) {
let _ = tx . send ( Event ::Close ( entity ) ) . await ;
}
} ) ;
}
2022-01-04 15:46:43 -05:00
self_ . emit_hide ( ) ;
2022-01-04 15:12:40 -05:00
} ) ) ;
2022-01-04 15:46:43 -05:00
let self_ = self . clone ( ) ;
favorite_item . connect_clicked ( glib ::clone! ( @ weak dock_object = > move | _ | {
2022-01-04 16:53:28 -05:00
let saved = dock_object . property ( " saved " ) . expect ( " DockObject must have saved property " ) . get ::< bool > ( ) . expect ( " Failed to convert value to bool " ) ;
glib ::MainContext ::default ( ) . spawn_local ( async move {
if let Some ( tx ) = TX . get ( ) {
if let Some ( name ) = dock_object . get_name ( ) {
let _ = tx . send ( Event ::Favorite ( ( name . into ( ) , ! saved ) ) ) . await ;
}
}
} ) ;
2022-01-04 15:46:43 -05:00
self_ . emit_hide ( ) ;
2022-01-04 15:12:40 -05:00
} ) ) ;
2022-01-05 15:37:04 -05:00
// all_windows_header.connect_clicked(
// glib::clone!(@weak dock_object, @weak revealer => move |self_| {
// // dbg!(dock_object);
// let revealer = revealer.borrow();
// revealer.set_reveal_child(!revealer.reveals_child())
// }),
// );
2022-01-04 15:30:38 -05:00
2022-01-04 15:46:43 -05:00
let self_ = self . clone ( ) ;
2022-01-04 15:30:38 -05:00
window_listbox . connect_row_activated ( glib ::clone! ( @ weak dock_object = > move | _ , item | {
let active = dock_object . property ( " active " ) . expect ( " DockObject must have active property " ) . get ::< BoxedWindowList > ( ) . expect ( " Failed to convert value to WindowList " ) . 0 ;
let entity = active [ usize ::try_from ( item . index ( ) ) . unwrap ( ) ] . entity . clone ( ) ;
glib ::MainContext ::default ( ) . spawn_local ( async move {
if let Some ( tx ) = TX . get ( ) {
let _ = tx . send ( Event ::Activate ( entity ) ) . await ;
}
} ) ;
2022-01-04 15:46:43 -05:00
self_ . emit_hide ( ) ;
2022-01-04 15:30:38 -05:00
} ) ) ;
2022-01-04 15:12:40 -05:00
}
2022-01-04 13:54:25 -05:00
}
}