2022-10-20 23:30:39 +03:00
/*
* Copyright ( c ) 2022 , kleines Filmröllchen < filmroellchen @ serenityos . org >
2023-01-09 02:44:32 +03:00
* Copyright ( c ) 2023 , Andreas Kling < kling @ serenityos . org >
2022-10-20 23:30:39 +03:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "PresenterWidget.h"
# include "Presentation.h"
2022-12-29 14:23:32 +03:00
# include <LibCore/MimeData.h>
2022-10-20 23:30:39 +03:00
# include <LibFileSystemAccessClient/Client.h>
# include <LibGUI/Action.h>
2023-01-18 01:31:34 +03:00
# include <LibGUI/Application.h>
2022-10-20 23:30:39 +03:00
# include <LibGUI/Event.h>
# include <LibGUI/Icon.h>
# include <LibGUI/Menu.h>
2023-01-02 17:15:14 +03:00
# include <LibGUI/MessageBox.h>
2022-10-20 23:30:39 +03:00
# include <LibGUI/Painter.h>
PresenterWidget : : PresenterWidget ( )
{
2023-01-18 01:33:08 +03:00
set_min_size ( 200 , 120 ) ;
2023-01-09 02:44:32 +03:00
set_fill_with_background_color ( true ) ;
m_web_view = add < WebView : : OutOfProcessWebView > ( ) ;
m_web_view - > set_frame_thickness ( 0 ) ;
m_web_view - > set_scrollbars_enabled ( false ) ;
m_web_view - > set_focus_policy ( GUI : : FocusPolicy : : NoFocus ) ;
m_web_view - > set_content_scales_to_viewport ( true ) ;
}
void PresenterWidget : : resize_event ( GUI : : ResizeEvent & event )
{
Widget : : resize_event ( event ) ;
if ( ! m_current_presentation )
return ;
auto normative_size = m_current_presentation - > normative_size ( ) . to_type < float > ( ) ;
float widget_ratio = static_cast < float > ( event . size ( ) . width ( ) ) / static_cast < float > ( event . size ( ) . height ( ) ) ;
float wh_ratio = normative_size . width ( ) / normative_size . height ( ) ;
Gfx : : IntRect rect ;
if ( widget_ratio > = wh_ratio ) {
rect . set_width ( static_cast < int > ( ceilf ( static_cast < float > ( event . size ( ) . height ( ) ) * wh_ratio ) ) ) ;
rect . set_height ( event . size ( ) . height ( ) ) ;
} else {
float hw_ratio = normative_size . height ( ) / normative_size . width ( ) ;
rect . set_width ( event . size ( ) . width ( ) ) ;
rect . set_height ( static_cast < int > ( ceilf ( static_cast < float > ( event . size ( ) . width ( ) ) * hw_ratio ) ) ) ;
}
m_web_view - > set_relative_rect ( rect . centered_within ( this - > rect ( ) ) ) ;
2022-10-20 23:30:39 +03:00
}
ErrorOr < void > PresenterWidget : : initialize_menubar ( )
{
auto * window = this - > window ( ) ;
// Set up the menu bar.
2023-01-18 01:31:34 +03:00
auto file_menu = TRY ( window - > try_add_menu ( " &File " ) ) ;
2022-10-20 23:30:39 +03:00
auto open_action = GUI : : CommonActions : : make_open_action ( [ this ] ( auto & ) {
2023-01-15 07:40:25 +03:00
auto response = FileSystemAccessClient : : Client : : the ( ) . open_file ( this - > window ( ) ) ;
2022-10-20 23:30:39 +03:00
if ( response . is_error ( ) )
return ;
2023-01-15 07:40:25 +03:00
this - > set_file ( response . value ( ) . filename ( ) ) ;
2022-10-20 23:30:39 +03:00
} ) ;
2023-01-18 01:31:34 +03:00
TRY ( file_menu - > try_add_action ( open_action ) ) ;
TRY ( file_menu - > try_add_separator ( ) ) ;
TRY ( file_menu - > try_add_action ( GUI : : CommonActions : : make_quit_action ( [ ] ( auto & ) {
GUI : : Application : : the ( ) - > quit ( ) ;
} ) ) ) ;
2022-10-20 23:30:39 +03:00
2023-01-18 01:31:34 +03:00
auto presentation_menu = TRY ( window - > try_add_menu ( " &Presentation " ) ) ;
2023-01-20 22:06:05 +03:00
m_next_slide_action = GUI : : Action : : create ( " &Next " , { KeyCode : : Key_Right } , TRY ( Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/go-forward.png " sv ) ) , [ this ] ( auto & ) {
2022-10-20 23:30:39 +03:00
if ( m_current_presentation ) {
m_current_presentation - > next_frame ( ) ;
2023-01-09 02:44:32 +03:00
update_web_view ( ) ;
2023-01-16 07:10:26 +03:00
update_slides_actions ( ) ;
2022-10-20 23:30:39 +03:00
}
} ) ;
2023-01-20 22:06:05 +03:00
m_previous_slide_action = GUI : : Action : : create ( " &Previous " , { KeyCode : : Key_Left } , TRY ( Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/go-back.png " sv ) ) , [ this ] ( auto & ) {
2022-10-20 23:30:39 +03:00
if ( m_current_presentation ) {
m_current_presentation - > previous_frame ( ) ;
2023-01-09 02:44:32 +03:00
update_web_view ( ) ;
2023-01-16 07:10:26 +03:00
update_slides_actions ( ) ;
2022-10-20 23:30:39 +03:00
}
} ) ;
2023-01-20 22:06:05 +03:00
m_full_screen_action = GUI : : Action : : create ( " &Full Screen " , { KeyModifier : : Mod_Shift , KeyCode : : Key_F5 } , { KeyCode : : Key_F11 } , TRY ( Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/fullscreen.png " sv ) ) , [ this ] ( auto & ) {
2022-10-20 23:30:39 +03:00
this - > window ( ) - > set_fullscreen ( true ) ;
2023-01-19 02:24:06 +03:00
} ) ;
2023-01-20 22:06:05 +03:00
m_present_from_first_slide_action = GUI : : Action : : create ( " Present From First &Slide " , { KeyCode : : Key_F5 } , TRY ( Gfx : : Bitmap : : load_from_file ( " /res/icons/16x16/play.png " sv ) ) , [ this ] ( auto & ) {
2023-01-09 02:44:32 +03:00
if ( m_current_presentation ) {
2022-10-20 23:30:39 +03:00
m_current_presentation - > go_to_first_slide ( ) ;
2023-01-09 02:44:32 +03:00
update_web_view ( ) ;
}
2022-10-20 23:30:39 +03:00
this - > window ( ) - > set_fullscreen ( true ) ;
2023-01-19 02:24:06 +03:00
} ) ;
TRY ( presentation_menu - > try_add_action ( * m_next_slide_action ) ) ;
TRY ( presentation_menu - > try_add_action ( * m_previous_slide_action ) ) ;
TRY ( presentation_menu - > try_add_action ( * m_full_screen_action ) ) ;
TRY ( presentation_menu - > try_add_action ( * m_present_from_first_slide_action ) ) ;
update_slides_actions ( ) ;
2022-10-20 23:30:39 +03:00
2023-01-18 01:31:34 +03:00
auto help_menu = TRY ( window - > try_add_menu ( " &Help " ) ) ;
2023-02-01 01:26:38 +03:00
TRY ( help_menu - > try_add_action ( GUI : : CommonActions : : make_about_action ( " Presenter " , GUI : : Icon : : default_icon ( " app-presenter " sv ) ) ) ) ;
2023-01-18 01:31:34 +03:00
2022-10-20 23:30:39 +03:00
return { } ;
}
2023-01-09 02:44:32 +03:00
void PresenterWidget : : update_web_view ( )
{
m_web_view - > run_javascript ( DeprecatedString : : formatted ( " goto({}, {}) " , m_current_presentation - > current_slide_number ( ) , m_current_presentation - > current_frame_in_slide_number ( ) ) ) ;
}
2023-01-16 07:10:26 +03:00
void PresenterWidget : : update_slides_actions ( )
{
if ( m_current_presentation ) {
m_next_slide_action - > set_enabled ( m_current_presentation - > has_a_next_frame ( ) ) ;
m_previous_slide_action - > set_enabled ( m_current_presentation - > has_a_previous_frame ( ) ) ;
2023-01-19 02:24:06 +03:00
m_full_screen_action - > set_enabled ( true ) ;
m_present_from_first_slide_action - > set_enabled ( true ) ;
} else {
m_next_slide_action - > set_enabled ( false ) ;
m_previous_slide_action - > set_enabled ( false ) ;
m_full_screen_action - > set_enabled ( false ) ;
m_present_from_first_slide_action - > set_enabled ( false ) ;
2023-01-16 07:10:26 +03:00
}
}
2022-10-20 23:30:39 +03:00
void PresenterWidget : : set_file ( StringView file_name )
{
2023-01-09 02:44:32 +03:00
auto presentation = Presentation : : load_from_file ( file_name ) ;
2022-10-20 23:30:39 +03:00
if ( presentation . is_error ( ) ) {
2022-12-04 21:02:33 +03:00
GUI : : MessageBox : : show_error ( window ( ) , DeprecatedString : : formatted ( " The presentation \" {} \" could not be loaded. \n {} " , file_name , presentation . error ( ) ) ) ;
2022-10-20 23:30:39 +03:00
} else {
m_current_presentation = presentation . release_value ( ) ;
2022-12-04 21:02:33 +03:00
window ( ) - > set_title ( DeprecatedString : : formatted ( title_template , m_current_presentation - > title ( ) , m_current_presentation - > author ( ) ) ) ;
2022-10-20 23:30:39 +03:00
set_min_size ( m_current_presentation - > normative_size ( ) ) ;
2023-01-09 02:44:32 +03:00
m_web_view - > load_html ( MUST ( m_current_presentation - > render ( ) ) , " presenter://slide.html " sv ) ;
2023-01-16 07:10:26 +03:00
update_slides_actions ( ) ;
2022-10-20 23:30:39 +03:00
}
}
void PresenterWidget : : keydown_event ( GUI : : KeyEvent & event )
{
if ( event . key ( ) = = Key_Escape & & window ( ) - > is_fullscreen ( ) )
window ( ) - > set_fullscreen ( false ) ;
// Alternate shortcuts for forward and backward
switch ( event . key ( ) ) {
case Key_Down :
case Key_PageDown :
case Key_Space :
case Key_N :
case Key_Return :
m_next_slide_action - > activate ( ) ;
event . accept ( ) ;
break ;
case Key_Up :
case Key_Backspace :
case Key_PageUp :
case Key_P :
m_previous_slide_action - > activate ( ) ;
event . accept ( ) ;
break ;
default :
2022-12-14 18:52:17 +03:00
event . ignore ( ) ;
2022-10-20 23:30:39 +03:00
break ;
}
}
2023-01-09 02:44:32 +03:00
void PresenterWidget : : paint_event ( GUI : : PaintEvent & event )
{
GUI : : Painter painter ( * this ) ;
painter . clear_rect ( event . rect ( ) , Gfx : : Color : : Black ) ;
}
void PresenterWidget : : second_paint_event ( GUI : : PaintEvent & event )
2022-10-20 23:30:39 +03:00
{
if ( ! m_current_presentation )
return ;
2023-01-09 02:44:32 +03:00
GUI : : Painter painter ( * this ) ;
painter . add_clip_rect ( event . rect ( ) ) ;
painter . draw_text ( m_web_view - > relative_rect ( ) , m_current_presentation - > current_slide ( ) . title ( ) , Gfx : : TextAlignment : : BottomCenter ) ;
2022-10-20 23:30:39 +03:00
}
2022-12-29 14:23:32 +03:00
void PresenterWidget : : drag_enter_event ( GUI : : DragEvent & event )
{
auto const & mime_types = event . mime_types ( ) ;
if ( mime_types . contains_slow ( " text/uri-list " ) )
event . accept ( ) ;
}
void PresenterWidget : : drop_event ( GUI : : DropEvent & event )
{
event . accept ( ) ;
if ( event . mime_data ( ) . has_urls ( ) ) {
auto urls = event . mime_data ( ) . urls ( ) ;
if ( urls . is_empty ( ) )
return ;
window ( ) - > move_to_front ( ) ;
set_file ( urls . first ( ) . path ( ) ) ;
}
}