hydrus/include/ClientGUIHoverFrames.py

757 lines
26 KiB
Python

import ClientConstants as CC
import ClientData
import ClientGUICanvas
import ClientGUICommon
import ClientGUIListBoxes
import HydrusConstants as HC
import HydrusData
import HydrusGlobals
import os
import wx
class FullscreenHoverFrame( wx.Frame ):
def __init__( self, parent, canvas_key ):
if HC.PLATFORM_WINDOWS:
border_style = wx.BORDER_RAISED
else:
border_style = wx.BORDER_SIMPLE
wx.Frame.__init__( self, parent, style = wx.FRAME_TOOL_WINDOW | wx.FRAME_NO_TASKBAR | wx.FRAME_FLOAT_ON_PARENT | border_style )
self._canvas_key = canvas_key
self._current_media = None
self._last_ideal_position = None
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_FRAMEBK ) )
self.SetCursor( wx.StockCursor( wx.CURSOR_ARROW ) )
self._timer_check_show = wx.Timer( self, id = ClientGUICanvas.ID_TIMER_HOVER_SHOW )
self.Bind( wx.EVT_TIMER, self.TIMEREventCheckIfShouldShow, id = ClientGUICanvas.ID_TIMER_HOVER_SHOW )
self._timer_check_show.Start( 100, wx.TIMER_CONTINUOUS )
self._hide_until = None
HydrusGlobals.client_controller.sub( self, 'SetDisplayMedia', 'canvas_new_display_media' )
def _GetIdealSizeAndPosition( self ):
raise NotImplementedError()
def _SizeAndPosition( self ):
( should_resize, my_ideal_size, my_ideal_position ) = self._GetIdealSizeAndPosition()
if should_resize:
self.Fit()
self.SetSize( my_ideal_size )
self.SetPosition( my_ideal_position )
def GiveParentFocus( self ):
self.GetParent().SetFocus()
def SetDisplayMedia( self, canvas_key, media ):
if canvas_key == self._canvas_key:
self._current_media = media
def TIMEREventCheckIfShouldShow( self, event ):
try:
if self._hide_until is not None:
if HydrusData.TimeHasPassed( self._hide_until ):
self._hide_until = None
else:
return
if self._current_media is None:
self.Hide()
else:
( mouse_x, mouse_y ) = wx.GetMousePosition()
( my_width, my_height ) = self.GetSize()
( should_resize, ( my_ideal_width, my_ideal_height ), ( my_ideal_x, my_ideal_y ) ) = self._GetIdealSizeAndPosition()
if my_ideal_width == -1: my_ideal_width = my_width
if my_ideal_height == -1: my_ideal_height = my_height
in_x = my_ideal_x <= mouse_x and mouse_x <= my_ideal_x + my_ideal_width
in_y = my_ideal_y <= mouse_y and mouse_y <= my_ideal_y + my_ideal_height
menu_open = HydrusGlobals.client_controller.MenuIsOpen()
dialog_open = False
tlps = wx.GetTopLevelWindows()
for tlp in tlps:
if isinstance( tlp, wx.Dialog ):
dialog_open = True
mime = self._current_media.GetMime()
in_position = in_x and in_y
mouse_is_over_interactable_media = mime == HC.APPLICATION_FLASH and self.GetParent().MouseIsOverMedia()
mouse_is_near_animation_bar = self.GetParent().MouseIsNearAnimationBar()
mouse_is_over_something_important = mouse_is_over_interactable_media or mouse_is_near_animation_bar
current_focus_tlp = wx.GetTopLevelParent( wx.Window.FindFocus() )
canvas_parent_tlp = wx.GetTopLevelParent( self.GetParent() )
if current_focus_tlp in ( self, canvas_parent_tlp ):
focus_is_good = True
else:
focus_is_good = False
ready_to_show = in_position and not mouse_is_over_something_important and focus_is_good and not dialog_open and not menu_open
ready_to_hide = not menu_open and ( not in_position or dialog_open or not focus_is_good )
if ready_to_show:
self._SizeAndPosition()
self.Show()
elif ready_to_hide:
self.Hide()
except wx.PyDeadObjectError:
self._timer_check_show.Stop()
except:
self._timer_check_show.Stop()
raise
class FullscreenHoverFrameCommands( FullscreenHoverFrame ):
def __init__( self, parent, canvas_key ):
FullscreenHoverFrame.__init__( self, parent, canvas_key )
self._always_archive = False
self._current_zoom = 1.0
self._current_index_string = ''
vbox = wx.BoxSizer( wx.VERTICAL )
self._first_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.first )
self._first_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_show_first', self._canvas_key ) )
self._first_button.SetToolTipString( 'first' )
self._previous_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.previous )
self._previous_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_show_previous', self._canvas_key ) )
self._previous_button.SetToolTipString( 'previous' )
self._index_text = wx.StaticText( self, label = 'index' )
self._next_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.next )
self._next_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_show_next', self._canvas_key ) )
self._next_button.SetToolTipString( 'next' )
self._last_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.last )
self._last_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_show_last', self._canvas_key ) )
self._last_button.SetToolTipString( 'last' )
self._archive_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.archive )
self._archive_button.Bind( wx.EVT_BUTTON, self.EventArchiveButton )
self._trash_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.delete )
self._trash_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_delete', self._canvas_key ) )
self._trash_button.SetToolTipString( 'send to trash' )
self._delete_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.trash_delete )
self._delete_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_delete', self._canvas_key ) )
self._delete_button.SetToolTipString( 'delete completely' )
self._undelete_button = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.undelete )
self._undelete_button.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_undelete', self._canvas_key ) )
self._undelete_button.SetToolTipString( 'undelete' )
self._zoom_text = wx.StaticText( self, label = 'zoom' )
zoom_in = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.zoom_in )
zoom_in.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_zoom_in', self._canvas_key ) )
zoom_in.SetToolTipString( 'zoom in' )
zoom_out = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.zoom_out )
zoom_out.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_zoom_out', self._canvas_key ) )
zoom_out.SetToolTipString( 'zoom out' )
zoom_switch = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.zoom_switch )
zoom_switch.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_zoom_switch', self._canvas_key ) )
zoom_switch.SetToolTipString( 'zoom switch' )
fullscreen_switch = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.fullscreen_switch )
fullscreen_switch.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_fullscreen_switch', self._canvas_key ) )
fullscreen_switch.SetToolTipString( 'fullscreen switch' )
open_externally = wx.BitmapButton( self, bitmap = CC.GlobalBMPs.open_externally )
open_externally.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_open_externally', self._canvas_key ) )
open_externally.SetToolTipString( 'open externally' )
close = wx.Button( self, label = 'X', style = wx.BU_EXACTFIT )
close.Bind( wx.EVT_BUTTON, lambda event: HydrusGlobals.client_controller.pub( 'canvas_close', self._canvas_key ) )
close.SetToolTipString( 'close' )
self._top_hbox = wx.BoxSizer( wx.HORIZONTAL )
self._title_text = wx.StaticText( self, label = 'title' )
self._info_text = wx.StaticText( self, label = 'info' )
self._button_hbox = wx.BoxSizer( wx.HORIZONTAL )
self._top_hbox.AddF( self._first_button, CC.FLAGS_VCENTER )
self._top_hbox.AddF( self._previous_button, CC.FLAGS_VCENTER )
self._top_hbox.AddF( self._index_text, CC.FLAGS_VCENTER )
self._top_hbox.AddF( self._next_button, CC.FLAGS_VCENTER )
self._top_hbox.AddF( self._last_button, CC.FLAGS_VCENTER )
self._top_hbox.AddF( ( 20, 20 ), CC.FLAGS_EXPAND_BOTH_WAYS )
self._top_hbox.AddF( self._archive_button, CC.FLAGS_VCENTER )
self._top_hbox.AddF( self._trash_button, CC.FLAGS_VCENTER )
self._top_hbox.AddF( self._delete_button, CC.FLAGS_VCENTER )
self._top_hbox.AddF( self._undelete_button, CC.FLAGS_VCENTER )
self._top_hbox.AddF( ( 20, 20 ), CC.FLAGS_EXPAND_BOTH_WAYS )
self._top_hbox.AddF( self._zoom_text, CC.FLAGS_VCENTER )
self._top_hbox.AddF( zoom_in, CC.FLAGS_VCENTER )
self._top_hbox.AddF( zoom_out, CC.FLAGS_VCENTER )
self._top_hbox.AddF( zoom_switch, CC.FLAGS_VCENTER )
self._top_hbox.AddF( fullscreen_switch, CC.FLAGS_VCENTER )
self._top_hbox.AddF( open_externally, CC.FLAGS_VCENTER )
self._top_hbox.AddF( close, CC.FLAGS_VCENTER )
vbox.AddF( self._top_hbox, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._title_text, CC.FLAGS_CENTER )
vbox.AddF( self._info_text, CC.FLAGS_CENTER )
vbox.AddF( self._button_hbox, CC.FLAGS_CENTER )
self.SetSizer( vbox )
HydrusGlobals.client_controller.sub( self, 'SetCurrentZoom', 'canvas_new_zoom' )
HydrusGlobals.client_controller.sub( self, 'SetIndexString', 'canvas_new_index_string' )
HydrusGlobals.client_controller.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
self.Bind( wx.EVT_MOUSEWHEEL, self.EventMouseWheel )
def _GetIdealSizeAndPosition( self ):
parent = self.GetParent()
( parent_width, parent_height ) = parent.GetClientSize()
( my_width, my_height ) = self.GetSize()
my_ideal_width = int( parent_width * 0.6 )
should_resize = my_ideal_width != my_width
ideal_size = ( my_ideal_width, -1 )
ideal_position = parent.ClientToScreenXY( int( parent_width * 0.2 ), 0 )
return ( should_resize, ideal_size, ideal_position )
def _ResetButtons( self ):
if self._current_media is not None:
if self._always_archive or self._current_media.HasInbox():
self._archive_button.SetBitmapLabel( CC.GlobalBMPs.archive )
self._archive_button.SetToolTipString( 'archive' )
else:
self._archive_button.SetBitmapLabel( CC.GlobalBMPs.to_inbox )
self._archive_button.SetToolTipString( 'return to inbox' )
current_locations = self._current_media.GetLocationsManager().GetCurrent()
if CC.LOCAL_FILE_SERVICE_KEY in current_locations:
self._trash_button.Show()
self._delete_button.Hide()
self._undelete_button.Hide()
elif CC.TRASH_SERVICE_KEY in current_locations:
self._trash_button.Hide()
self._delete_button.Show()
self._undelete_button.Show()
def _ResetText( self ):
if self._current_media is None:
self._title_text.Hide()
self._info_text.Hide()
else:
label = self._current_media.GetTitleString()
if len( label ) > 0:
self._title_text.SetLabelText( label )
self._title_text.Show()
else: self._title_text.Hide()
lines = self._current_media.GetPrettyInfoLines()
label = ' | '.join( lines )
self._info_text.SetLabelText( label )
self._info_text.Show()
def AddCommand( self, label, callback ):
command = wx.Button( self, label = label, style = wx.BU_EXACTFIT )
command.Bind( wx.EVT_BUTTON, callback )
self._button_hbox.AddF( command, CC.FLAGS_VCENTER )
def EventArchiveButton( self, event ):
if self._always_archive or self._current_media.HasInbox():
HydrusGlobals.client_controller.pub( 'canvas_archive', self._canvas_key )
else:
HydrusGlobals.client_controller.pub( 'canvas_inbox', self._canvas_key )
def EventMouseWheel( self, event ):
event.ResumePropagation( 1 )
event.Skip()
def ProcessContentUpdates( self, service_keys_to_content_updates ):
if self._current_media is not None:
my_hash = self._current_media.GetHash()
do_redraw = False
for ( service_key, content_updates ) in service_keys_to_content_updates.items():
if True in ( my_hash in content_update.GetHashes() for content_update in content_updates ):
do_redraw = True
break
if do_redraw:
self._ResetButtons()
self.Fit()
self._SizeAndPosition()
def SetAlwaysArchive( self, value ):
self._always_archive = value
self._ResetButtons()
def SetCurrentZoom( self, canvas_key, zoom ):
if canvas_key == self._canvas_key:
self._current_zoom = zoom
label = ClientData.ConvertZoomToPercentage( self._current_zoom )
self._zoom_text.SetLabelText( label )
self._top_hbox.Layout()
def SetDisplayMedia( self, canvas_key, media ):
if canvas_key == self._canvas_key:
FullscreenHoverFrame.SetDisplayMedia( self, canvas_key, media )
self._ResetButtons()
self._ResetText()
self.Fit()
self._SizeAndPosition()
def SetIndexString( self, canvas_key, text ):
if canvas_key == self._canvas_key:
self._current_index_string = text
self._index_text.SetLabelText( self._current_index_string )
self._top_hbox.Layout()
def SetNavigable( self, value ):
if value:
self._first_button.Show()
self._last_button.Show()
self._previous_button.SetToolTipString( 'previous' )
self._next_button.SetToolTipString( 'next' )
else:
self._first_button.Hide()
self._last_button.Hide()
self._previous_button.SetToolTipString( 'back' )
self._next_button.SetToolTipString( 'skip' )
class FullscreenHoverFrameRatings( FullscreenHoverFrame ):
def __init__( self, parent, canvas_key ):
FullscreenHoverFrame.__init__( self, parent, canvas_key )
vbox = wx.BoxSizer( wx.VERTICAL )
self._icon_panel = wx.Panel( self )
self._trash_icon = ClientGUICommon.BufferedWindowIcon( self._icon_panel, CC.GlobalBMPs.trash )
self._inbox_icon = ClientGUICommon.BufferedWindowIcon( self._icon_panel, CC.GlobalBMPs.inbox )
icon_hbox = wx.BoxSizer( wx.HORIZONTAL )
icon_hbox.AddF( ( 16, 16 ), CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
icon_hbox.AddF( self._trash_icon, CC.FLAGS_VCENTER )
icon_hbox.AddF( self._inbox_icon, CC.FLAGS_VCENTER )
self._icon_panel.SetSizer( icon_hbox )
# repo strings
self._file_repos = wx.StaticText( self, label = '', style = wx.ALIGN_RIGHT )
# likes
like_hbox = wx.BoxSizer( wx.HORIZONTAL )
like_hbox.AddF( ( 16, 16 ), CC.FLAGS_EXPAND_BOTH_WAYS )
like_services = HydrusGlobals.client_controller.GetServicesManager().GetServices( ( HC.LOCAL_RATING_LIKE, ), randomised = False )
for service in like_services:
service_key = service.GetServiceKey()
control = ClientGUICommon.RatingLikeCanvas( self, service_key, canvas_key )
like_hbox.AddF( control, CC.FLAGS_NONE )
# each numerical one in turn
vbox.AddF( self._icon_panel, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
vbox.AddF( self._file_repos, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.AddF( like_hbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
numerical_services = HydrusGlobals.client_controller.GetServicesManager().GetServices( ( HC.LOCAL_RATING_NUMERICAL, ), randomised = False )
for service in numerical_services:
service_key = service.GetServiceKey()
control = ClientGUICommon.RatingNumericalCanvas( self, service_key, canvas_key )
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( ( 16, 16 ), CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
hbox.AddF( control, CC.FLAGS_NONE )
vbox.AddF( hbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
self.SetSizer( vbox )
self._ResetData()
HydrusGlobals.client_controller.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
self.Bind( wx.EVT_MOUSEWHEEL, self.EventMouseWheel )
def _GetIdealSizeAndPosition( self ):
parent = self.GetParent()
( parent_width, parent_height ) = parent.GetClientSize()
( my_width, my_height ) = self.GetSize()
my_ideal_width = int( parent_width * 0.2 )
should_resize = my_ideal_width != my_width
ideal_size = ( my_ideal_width, -1 )
ideal_position = parent.ClientToScreenXY( int( parent_width * 0.8 ), 0 )
return ( should_resize, ideal_size, ideal_position )
def _ResetData( self ):
if self._current_media is not None:
has_inbox = self._current_media.HasInbox()
has_trash = CC.TRASH_SERVICE_KEY in self._current_media.GetLocationsManager().GetCurrent()
if has_inbox or has_trash:
self._icon_panel.Show()
if has_inbox:
self._inbox_icon.Show()
else:
self._inbox_icon.Hide()
if has_trash:
self._trash_icon.Show()
else:
self._trash_icon.Hide()
else:
self._icon_panel.Hide()
remote_strings = self._current_media.GetLocationsManager().GetRemoteLocationStrings()
if len( remote_strings ) == 0:
self._file_repos.Hide()
else:
remote_string = os.linesep.join( remote_strings )
self._file_repos.SetLabelText( remote_string )
self._file_repos.Show()
self.Fit()
self._SizeAndPosition()
def EventMouseWheel( self, event ):
event.ResumePropagation( 1 )
event.Skip()
def ProcessContentUpdates( self, service_keys_to_content_updates ):
if self._current_media is not None:
my_hash = self._current_media.GetHash()
do_redraw = False
for ( service_key, content_updates ) in service_keys_to_content_updates.items():
if True in ( my_hash in content_update.GetHashes() for content_update in content_updates ):
if True in ( content_update.IsInboxRelated() for content_update in content_updates ):
do_redraw = True
break
if do_redraw:
self._ResetData()
def SetDisplayMedia( self, canvas_key, media ):
if canvas_key == self._canvas_key:
FullscreenHoverFrame.SetDisplayMedia( self, canvas_key, media )
self._ResetData()
class FullscreenHoverFrameTags( FullscreenHoverFrame ):
def __init__( self, parent, canvas_key ):
FullscreenHoverFrame.__init__( self, parent, canvas_key )
vbox = wx.BoxSizer( wx.VERTICAL )
self._tags = ClientGUIListBoxes.ListBoxTagsSelectionHoverFrame( self, self._canvas_key )
vbox.AddF( self._tags, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
self.SetSizer( vbox )
HydrusGlobals.client_controller.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
def _GetIdealSizeAndPosition( self ):
parent = self.GetParent()
( parent_width, parent_height ) = parent.GetClientSize()
( my_width, my_height ) = self.GetSize()
my_ideal_width = int( parent_width * 0.2 )
my_ideal_height = parent_height
should_resize = my_ideal_width != my_width or my_ideal_height != my_height
ideal_size = ( my_ideal_width, my_ideal_height )
ideal_position = parent.ClientToScreenXY( 0, 0 )
return ( should_resize, ideal_size, ideal_position )
def _ResetTags( self ):
if self._current_media is not None:
self._tags.SetTagsByMedia( [ self._current_media ], force_reload = True )
def ProcessContentUpdates( self, service_keys_to_content_updates ):
if self._current_media is not None:
my_hash = self._current_media.GetHash()
do_redraw = False
for ( service_key, content_updates ) in service_keys_to_content_updates.items():
if True in ( my_hash in content_update.GetHashes() for content_update in content_updates ):
do_redraw = True
break
if do_redraw:
self._ResetTags()
def SetDisplayMedia( self, canvas_key, media ):
if canvas_key == self._canvas_key:
FullscreenHoverFrame.SetDisplayMedia( self, canvas_key, media )
self._ResetTags()