hydrus/hydrus/client/gui/canvas/ClientGUICanvasHoverFrames.py

1608 lines
62 KiB
Python
Raw Normal View History

2015-06-17 20:01:41 +00:00
import os
2020-04-22 21:00:35 +00:00
2019-11-14 03:56:30 +00:00
from qtpy import QtCore as QC
from qtpy import QtWidgets as QW
from qtpy import QtGui as QG
2020-04-22 21:00:35 +00:00
from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusData
from hydrus.core import HydrusGlobals as HG
from hydrus.core import HydrusSerialisable
2020-07-29 20:52:44 +00:00
from hydrus.client import ClientApplicationCommand as CAC
2020-04-22 21:00:35 +00:00
from hydrus.client import ClientConstants as CC
from hydrus.client import ClientData
from hydrus.client.gui import ClientGUIDragDrop
from hydrus.client.gui import ClientGUICore as CGC
from hydrus.client.gui import ClientGUIFunctions
from hydrus.client.gui import ClientGUIMediaControls
from hydrus.client.gui import ClientGUIMenus
from hydrus.client.gui import ClientGUIMPV
from hydrus.client.gui import ClientGUIRatings
2020-04-22 21:00:35 +00:00
from hydrus.client.gui import ClientGUIScrolledPanelsEdit
from hydrus.client.gui import ClientGUIShortcuts
from hydrus.client.gui import ClientGUIShortcutControls
2020-04-29 21:44:12 +00:00
from hydrus.client.gui import ClientGUITopLevelWindows
from hydrus.client.gui import ClientGUITopLevelWindowsPanels
2020-04-22 21:00:35 +00:00
from hydrus.client.gui import QtPorting as QP
2020-07-15 20:52:09 +00:00
from hydrus.client.gui.lists import ClientGUIListBoxes
2021-03-17 21:59:28 +00:00
from hydrus.client.gui.widgets import ClientGUICommon
from hydrus.client.gui.widgets import ClientGUIMenuButton
2020-07-29 20:52:44 +00:00
from hydrus.client.media import ClientMedia
from hydrus.client.metadata import ClientRatings
2015-06-17 20:01:41 +00:00
class RatingLikeCanvas( ClientGUIRatings.RatingLike ):
2020-03-25 21:15:57 +00:00
def __init__( self, parent, service_key, canvas_key ):
ClientGUIRatings.RatingLike.__init__( self, parent, service_key )
2020-03-25 21:15:57 +00:00
self._canvas_key = canvas_key
self._current_media = None
self._rating_state = None
service = HG.client_controller.services_manager.GetService( service_key )
name = service.GetName()
self.setToolTip( name )
HG.client_controller.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
HG.client_controller.sub( self, 'SetDisplayMedia', 'canvas_new_display_media' )
def _Draw( self, painter ):
painter.setBackground( QG.QBrush( QP.GetBackgroundColour( self.parentWidget() ) ) )
painter.eraseRect( painter.viewport() )
if self._current_media is not None:
self._rating_state = ClientRatings.GetLikeStateFromMedia( ( self._current_media, ), self._service_key )
ClientGUIRatings.DrawLike( painter, 0, 0, self._service_key, self._rating_state )
2020-03-25 21:15:57 +00:00
self._dirty = False
def EventLeftDown( self, event ):
if self._current_media is not None:
if self._rating_state == ClientRatings.LIKE: rating = None
else: rating = 1
content_update = HydrusData.ContentUpdate( HC.CONTENT_TYPE_RATINGS, HC.CONTENT_UPDATE_ADD, ( rating, self._hashes ) )
HG.client_controller.Write( 'content_updates', { self._service_key : ( content_update, ) } )
def EventRightDown( self, event ):
if self._current_media is not None:
if self._rating_state == ClientRatings.DISLIKE: rating = None
else: rating = 0
content_update = HydrusData.ContentUpdate( HC.CONTENT_TYPE_RATINGS, HC.CONTENT_UPDATE_ADD, ( rating, self._hashes ) )
HG.client_controller.Write( 'content_updates', { self._service_key : ( content_update, ) } )
def ProcessContentUpdates( self, service_keys_to_content_updates ):
if self._current_media is not None:
2021-04-28 21:43:16 +00:00
for ( service_key, content_updates ) in service_keys_to_content_updates.items():
2020-03-25 21:15:57 +00:00
for content_update in content_updates:
( data_type, action, row ) = content_update.ToTuple()
if data_type == HC.CONTENT_TYPE_RATINGS:
hashes = content_update.GetHashes()
2020-10-28 22:20:33 +00:00
if HydrusData.SetsIntersect( self._hashes, hashes ):
2020-03-25 21:15:57 +00:00
self._dirty = True
self.update()
return
def SetDisplayMedia( self, canvas_key, media ):
if canvas_key == self._canvas_key:
self._current_media = media
if self._current_media is None:
self._hashes = set()
else:
self._hashes = self._current_media.GetHashes()
self._dirty = True
self.update()
class RatingNumericalCanvas( ClientGUIRatings.RatingNumerical ):
2020-03-25 21:15:57 +00:00
def __init__( self, parent, service_key, canvas_key ):
ClientGUIRatings.RatingNumerical.__init__( self, parent, service_key )
2020-03-25 21:15:57 +00:00
self._canvas_key = canvas_key
self._current_media = None
self._rating_state = None
self._rating = None
self._hashes = set()
name = self._service.GetName()
self.setToolTip( name )
HG.client_controller.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
HG.client_controller.sub( self, 'SetDisplayMedia', 'canvas_new_display_media' )
def _ClearRating( self ):
ClientGUIRatings.RatingNumerical._ClearRating( self )
2020-03-25 21:15:57 +00:00
if self._current_media is not None:
rating = None
content_update = HydrusData.ContentUpdate( HC.CONTENT_TYPE_RATINGS, HC.CONTENT_UPDATE_ADD, ( rating, self._hashes ) )
HG.client_controller.Write( 'content_updates', { self._service_key : ( content_update, ) } )
def _Draw( self, painter ):
painter.setBackground( QG.QBrush( QP.GetBackgroundColour( self.parentWidget() ) ) )
painter.eraseRect( painter.viewport() )
if self._current_media is not None:
( self._rating_state, self._rating ) = ClientRatings.GetNumericalStateFromMedia( ( self._current_media, ), self._service_key )
ClientGUIRatings.DrawNumerical( painter, 0, 0, self._service_key, self._rating_state, self._rating )
2020-03-25 21:15:57 +00:00
self._dirty = False
def _SetRating( self, rating ):
ClientGUIRatings.RatingNumerical._SetRating( self, rating )
2020-03-25 21:15:57 +00:00
if self._current_media is not None and rating is not None:
content_update = HydrusData.ContentUpdate( HC.CONTENT_TYPE_RATINGS, HC.CONTENT_UPDATE_ADD, ( rating, self._hashes ) )
HG.client_controller.Write( 'content_updates', { self._service_key : ( content_update, ) } )
def ProcessContentUpdates( self, service_keys_to_content_updates ):
if self._current_media is not None:
for ( service_key, content_updates ) in service_keys_to_content_updates.items():
for content_update in content_updates:
( data_type, action, row ) = content_update.ToTuple()
if data_type == HC.CONTENT_TYPE_RATINGS:
hashes = content_update.GetHashes()
2020-10-28 22:20:33 +00:00
if HydrusData.SetsIntersect( self._hashes, hashes ):
2020-03-25 21:15:57 +00:00
self._dirty = True
self.update()
return
def SetDisplayMedia( self, canvas_key, media ):
if canvas_key == self._canvas_key:
self._current_media = media
if self._current_media is None:
self._hashes = set()
else:
self._hashes = self._current_media.GetHashes()
self._dirty = True
self.update()
class CanvasHoverFrame( QW.QFrame ):
2015-06-17 20:01:41 +00:00
2018-12-05 22:35:30 +00:00
def __init__( self, parent, my_canvas, canvas_key ):
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
QW.QFrame.__init__( self, parent )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self.setWindowFlags( QC.Qt.FramelessWindowHint | QC.Qt.Tool )
2019-12-05 05:29:32 +00:00
2019-11-14 03:56:30 +00:00
self.setAttribute( QC.Qt.WA_ShowWithoutActivating )
self.setAttribute( QC.Qt.WA_DeleteOnClose )
2015-06-17 20:01:41 +00:00
2019-12-05 05:29:32 +00:00
self.setFrameStyle( QW.QFrame.Panel | QW.QFrame.Raised )
self.setLineWidth( 2 )
2020-08-19 22:38:20 +00:00
self._my_parent_tlw = parent.window()
2018-12-05 22:35:30 +00:00
self._my_canvas = my_canvas
2015-06-17 20:01:41 +00:00
self._canvas_key = canvas_key
self._current_media = None
2019-05-08 21:06:42 +00:00
self._always_on_top = False
2015-12-02 22:32:18 +00:00
self._last_ideal_position = None
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self.setCursor( QG.QCursor( QC.Qt.ArrowCursor ) )
2015-06-17 20:01:41 +00:00
2016-12-07 22:12:52 +00:00
self._hide_until = None
2020-01-22 21:04:43 +00:00
self._position_initialised = False
2019-06-26 21:27:18 +00:00
2020-08-19 22:38:20 +00:00
self._my_parent_tlw.installEventFilter( self )
2017-05-10 21:33:58 +00:00
HG.client_controller.sub( self, 'SetDisplayMedia', 'canvas_new_display_media' )
2015-06-17 20:01:41 +00:00
2018-01-03 22:37:30 +00:00
HG.client_controller.gui.RegisterUIUpdateWindow( self )
2015-06-17 20:01:41 +00:00
def _GetIdealSizeAndPosition( self ):
raise NotImplementedError()
2019-12-11 23:18:37 +00:00
def _SizeAndPosition( self, force = False ):
2015-06-17 20:01:41 +00:00
2019-12-11 23:18:37 +00:00
if self.parentWidget().isVisible() or force:
2017-05-17 21:53:02 +00:00
2017-05-24 20:28:24 +00:00
( should_resize, my_ideal_size, my_ideal_position ) = self._GetIdealSizeAndPosition()
2017-05-17 21:53:02 +00:00
2017-05-24 20:28:24 +00:00
if should_resize:
2020-08-19 22:38:20 +00:00
self.resize( my_ideal_size )
2020-02-26 22:28:52 +00:00
2020-08-19 22:38:20 +00:00
if my_ideal_position != self.pos():
2020-02-26 22:28:52 +00:00
self.move( my_ideal_position )
2017-05-24 20:28:24 +00:00
2015-06-17 20:01:41 +00:00
2020-01-22 21:04:43 +00:00
self._position_initialised = True
2015-06-17 20:01:41 +00:00
2016-12-07 22:12:52 +00:00
2020-08-19 22:38:20 +00:00
def eventFilter( self, watched, event ):
if watched == self._my_parent_tlw:
if event.type() in ( QC.QEvent.Move, QC.QEvent.Resize ):
self._position_initialised = False
return False
2015-06-17 20:01:41 +00:00
def SetDisplayMedia( self, canvas_key, media ):
if canvas_key == self._canvas_key:
self._current_media = media
2018-01-03 22:37:30 +00:00
def TIMERUIUpdate( self ):
2020-01-22 21:04:43 +00:00
if not self._position_initialised:
self._SizeAndPosition()
2019-12-11 23:18:37 +00:00
current_focus_tlw = QW.QApplication.activeWindow()
2019-05-15 20:35:00 +00:00
2019-12-11 23:18:37 +00:00
focus_is_on_descendant = ClientGUIFunctions.IsQtAncestor( current_focus_tlw, self._my_canvas.window(), through_tlws = True )
2020-03-25 21:15:57 +00:00
focus_has_right_window_type = isinstance( current_focus_tlw, ( ClientGUITopLevelWindows.FrameThatResizesWithHovers, CanvasHoverFrame ) )
2019-05-15 20:35:00 +00:00
focus_is_good = focus_is_on_descendant and focus_has_right_window_type
2020-02-05 22:55:21 +00:00
mouse_is_over_self_or_child = False
for tlw in QW.QApplication.topLevelWidgets():
if tlw == self or ClientGUIFunctions.IsQtAncestor( tlw, self, through_tlws = True ):
if tlw.underMouse():
mouse_is_over_self_or_child = True
break
2019-12-11 23:18:37 +00:00
if self._always_on_top:
2015-06-17 20:01:41 +00:00
2018-01-03 22:37:30 +00:00
self._SizeAndPosition()
2017-09-13 20:50:41 +00:00
2019-11-14 03:56:30 +00:00
self.show()
2017-09-13 20:50:41 +00:00
2018-01-03 22:37:30 +00:00
return
2016-12-07 22:12:52 +00:00
2018-01-03 22:37:30 +00:00
if self._hide_until is not None:
if HydrusData.TimeHasPassed( self._hide_until ):
2015-06-17 20:01:41 +00:00
2018-01-03 22:37:30 +00:00
self._hide_until = None
2015-06-17 20:01:41 +00:00
2015-11-18 22:44:07 +00:00
else:
2015-06-17 20:01:41 +00:00
2018-01-03 22:37:30 +00:00
return
2015-11-18 22:44:07 +00:00
2018-01-03 22:37:30 +00:00
2019-11-14 03:56:30 +00:00
if self._current_media is None or not self._my_canvas.isVisible():
2018-01-03 22:37:30 +00:00
2019-11-14 03:56:30 +00:00
if self.isVisible():
2018-01-17 22:52:10 +00:00
if HG.hover_window_report_mode:
HydrusData.ShowText( repr( self ) + ' - hiding because nothing to show or parent hidden.' )
2019-11-14 03:56:30 +00:00
self.hide()
2018-01-17 22:52:10 +00:00
2018-01-03 22:37:30 +00:00
else:
2020-02-26 22:28:52 +00:00
mouse_pos = QG.QCursor.pos()
mouse_x = mouse_pos.x()
mouse_y = mouse_pos.y()
my_size = self.size()
my_width = my_size.width()
my_height = my_size.height()
2018-01-03 22:37:30 +00:00
2020-02-26 22:28:52 +00:00
my_pos = self.pos()
2018-01-03 22:37:30 +00:00
2020-02-26 22:28:52 +00:00
my_x = my_pos.x()
my_y = my_pos.y()
( should_resize, my_ideal_size, my_ideal_pos ) = self._GetIdealSizeAndPosition()
my_ideal_width = my_ideal_size.width()
my_ideal_height = my_ideal_size.height()
my_ideal_x = my_ideal_pos.x()
my_ideal_y = my_ideal_pos.y()
2018-01-03 22:37:30 +00:00
if my_ideal_width == -1:
2015-11-18 22:44:07 +00:00
2018-01-03 22:37:30 +00:00
my_ideal_width = max( my_width, 50 )
2015-11-18 22:44:07 +00:00
2018-01-03 22:37:30 +00:00
if my_ideal_height == -1:
2015-11-18 22:44:07 +00:00
2018-01-03 22:37:30 +00:00
my_ideal_height = max( my_height, 50 )
2015-06-17 20:01:41 +00:00
2018-01-03 22:37:30 +00:00
2020-02-26 22:28:52 +00:00
in_ideal_x = my_ideal_x <= mouse_x <= my_ideal_x + my_ideal_width
in_ideal_y = my_ideal_y <= mouse_y <= my_ideal_y + my_ideal_height
2018-01-03 22:37:30 +00:00
2020-02-26 22:28:52 +00:00
in_actual_x = my_x <= mouse_x <= my_x + my_width
in_actual_y = my_y <= mouse_y <= my_y + my_height
2018-01-03 22:37:30 +00:00
# we test both ideal and actual here because setposition is not always honoured by the OS
2019-06-26 21:27:18 +00:00
# for instance, in some Linux window managers on a fullscreen view, the top taskbar is hidden, but when hover window is shown, it takes focus and causes taskbar to reappear
2018-01-03 22:37:30 +00:00
# the reappearance shuffles the screen coordinates down a bit so the hover sits +20px y despite wanting to be lined up with the underlying fullscreen viewer
# wew lad
in_position = ( in_ideal_x or in_actual_x ) and ( in_ideal_y or in_actual_y )
2020-03-04 22:12:53 +00:00
menu_open = CGC.core().MenuIsOpen()
2018-01-03 22:37:30 +00:00
2020-02-26 22:28:52 +00:00
dialog_is_open = ClientGUIFunctions.DialogIsOpen()
2015-11-18 22:44:07 +00:00
2019-05-08 21:06:42 +00:00
mouse_is_near_animation_bar = self._my_canvas.MouseIsNearAnimationBar()
2015-11-18 22:44:07 +00:00
2020-02-05 22:55:21 +00:00
# this used to have the flash media window test to ensure mouse over flash window hid hovers going over it
mouse_is_over_something_else_important = mouse_is_near_animation_bar
2015-11-18 22:44:07 +00:00
2019-12-11 23:18:37 +00:00
hide_focus_is_good = focus_is_good or current_focus_tlw is None # don't hide if focus is either gone to another problem or temporarily sperging-out due to a click-transition or similar
2019-06-26 21:27:18 +00:00
2020-02-26 22:28:52 +00:00
ready_to_show = in_position and not mouse_is_over_something_else_important and focus_is_good and not dialog_is_open and not menu_open
ready_to_hide = not menu_open and not mouse_is_over_self_or_child and ( not in_position or dialog_is_open or not hide_focus_is_good )
2018-01-03 22:37:30 +00:00
2018-01-17 22:52:10 +00:00
def get_logic_report_string():
tuples = []
2019-06-05 19:42:39 +00:00
tuples.append( ( 'mouse: ', ( mouse_x, mouse_y ) ) )
tuples.append( ( 'winpos: ', ( my_x, my_y ) ) )
2019-06-26 21:27:18 +00:00
tuples.append( ( 'ideal winpos: ', ( my_ideal_x, my_ideal_y ) ) )
2019-06-05 19:42:39 +00:00
tuples.append( ( 'winsize: ', ( my_width, my_height ) ) )
2019-06-26 21:27:18 +00:00
tuples.append( ( 'ideal winsize: ', ( my_ideal_width, my_ideal_height ) ) )
2018-01-17 22:52:10 +00:00
tuples.append( ( 'in position: ', in_position ) )
tuples.append( ( 'menu open: ', menu_open ) )
2020-02-26 22:28:52 +00:00
tuples.append( ( 'dialog open: ', dialog_is_open ) )
2018-01-17 22:52:10 +00:00
tuples.append( ( 'mouse near animation bar: ', mouse_is_near_animation_bar ) )
tuples.append( ( 'focus is good: ', focus_is_good ) )
2019-06-19 22:08:48 +00:00
tuples.append( ( 'focus is on descendant: ', focus_is_on_descendant ) )
2019-12-11 23:18:37 +00:00
tuples.append( ( 'current focus tlw: ', current_focus_tlw ) )
2018-01-17 22:52:10 +00:00
2019-06-05 19:42:39 +00:00
message = os.linesep * 2 + os.linesep.join( ( a + str( b ) for ( a, b ) in tuples ) )
2018-01-17 22:52:10 +00:00
return message
2018-01-03 22:37:30 +00:00
if ready_to_show:
self._SizeAndPosition()
2019-11-14 03:56:30 +00:00
if not self.isVisible():
2018-01-17 22:52:10 +00:00
if HG.hover_window_report_mode:
HydrusData.ShowText( repr( self ) + ' - showing.' + get_logic_report_string() )
2019-11-14 03:56:30 +00:00
self.show()
2018-01-17 22:52:10 +00:00
2018-01-03 22:37:30 +00:00
elif ready_to_hide:
2019-11-14 03:56:30 +00:00
if self.isVisible():
2018-01-17 22:52:10 +00:00
if HG.hover_window_report_mode:
HydrusData.ShowText( repr( self ) + ' - hiding.' + get_logic_report_string() )
2019-11-14 03:56:30 +00:00
self.hide()
2018-01-17 22:52:10 +00:00
2018-01-03 22:37:30 +00:00
2017-03-29 19:39:34 +00:00
2020-03-25 21:15:57 +00:00
class CanvasHoverFrameRightDuplicates( CanvasHoverFrame ):
2019-05-08 21:06:42 +00:00
def __init__( self, parent, my_canvas, canvas_key ):
2020-03-25 21:15:57 +00:00
CanvasHoverFrame.__init__( self, parent, my_canvas, canvas_key )
2019-05-08 21:06:42 +00:00
self._always_on_top = True
self._current_index_string = ''
self._comparison_media = None
2020-03-11 21:52:11 +00:00
self._trash_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().delete, HG.client_controller.pub, 'canvas_delete', self._canvas_key )
2019-11-14 03:56:30 +00:00
self._trash_button.setToolTip( 'send to trash' )
2019-06-05 19:42:39 +00:00
2019-05-08 21:06:42 +00:00
menu_items = []
2019-05-29 21:34:43 +00:00
menu_items.append( ( 'normal', 'edit duplicate metadata merge options for \'this is better\'', 'edit what content is merged when you filter files', HydrusData.Call( self._EditMergeOptions, HC.DUPLICATE_BETTER ) ) )
menu_items.append( ( 'normal', 'edit duplicate metadata merge options for \'same quality\'', 'edit what content is merged when you filter files', HydrusData.Call( self._EditMergeOptions, HC.DUPLICATE_SAME_QUALITY ) ) )
2019-06-05 19:42:39 +00:00
if HG.client_controller.new_options.GetBoolean( 'advanced_mode' ):
menu_items.append( ( 'normal', 'edit duplicate metadata merge options for \'alternates\' (advanced!)', 'edit what content is merged when you filter files', HydrusData.Call( self._EditMergeOptions, HC.DUPLICATE_ALTERNATE ) ) )
2019-05-08 21:06:42 +00:00
menu_items.append( ( 'separator', None, None, None ) )
menu_items.append( ( 'normal', 'edit background lighten/darken switch intensity', 'edit how much the background will brighten or darken as you switch between the pair', self._EditBackgroundSwitchIntensity ) )
2021-03-17 21:59:28 +00:00
self._cog_button = ClientGUIMenuButton.MenuBitmapButton( self, CC.global_pixmaps().cog, menu_items )
2019-06-05 19:42:39 +00:00
2020-03-11 21:52:11 +00:00
close_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().stop, HG.client_controller.pub, 'canvas_close', self._canvas_key )
2019-11-14 03:56:30 +00:00
close_button.setToolTip( 'close filter' )
2019-07-31 22:01:02 +00:00
2021-08-25 21:59:05 +00:00
self._back_a_pair = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().first, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_BACK ), self._canvas_key )
self._back_a_pair.SetToolTipWithShortcuts( 'go back a pair', CAC.SIMPLE_DUPLICATE_FILTER_BACK )
2019-05-08 21:06:42 +00:00
self._index_text = ClientGUICommon.BetterStaticText( self, 'index' )
2021-08-25 21:59:05 +00:00
self._next_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().pair, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_NEXT ), self._canvas_key )
self._next_button.SetToolTipWithShortcuts( 'next', CAC.SIMPLE_VIEW_NEXT )
2019-05-08 21:06:42 +00:00
2021-08-25 21:59:05 +00:00
self._skip_a_pair = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().last, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_SKIP ), self._canvas_key )
self._skip_a_pair.SetToolTipWithShortcuts( 'show a different pair', CAC.SIMPLE_DUPLICATE_FILTER_SKIP )
2019-05-08 21:06:42 +00:00
2019-11-14 03:56:30 +00:00
command_button_vbox = QP.VBoxLayout()
2019-05-22 22:35:06 +00:00
dupe_boxes = []
dupe_commands = []
2021-08-25 21:59:05 +00:00
dupe_commands.append( ( 'this is better, and delete the other', 'Set that the current file you are looking at is better than the other in the pair, and set the other file to be deleted.', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_THIS_IS_BETTER_AND_DELETE_OTHER ) ) )
dupe_commands.append( ( 'this is better, but keep both', 'Set that the current file you are looking at is better than the other in the pair, but keep both files.', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_THIS_IS_BETTER_BUT_KEEP_BOTH ) ) )
dupe_commands.append( ( 'they are the same quality', 'Set that the two files are duplicates of very similar quality.', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_EXACTLY_THE_SAME ) ) )
2019-05-22 22:35:06 +00:00
dupe_boxes.append( ( 'they are duplicates', dupe_commands ) )
2019-05-08 21:06:42 +00:00
dupe_commands = []
2021-08-25 21:59:05 +00:00
dupe_commands.append( ( 'they are related alternates', 'Set that the files are not duplicates, but that one is derived from the other or that they are both descendants of a common ancestor.', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_ALTERNATES ) ) )
dupe_commands.append( ( 'they are not related', 'Set that the files are not duplicates or otherwise related--that this potential pair is a false positive match.', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_FALSE_POSITIVE ) ) )
dupe_commands.append( ( 'custom action', 'Choose one of the other actions but customise the merge and delete options for this specific decision.', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_CUSTOM_ACTION ) ) )
2019-05-08 21:06:42 +00:00
2019-05-22 22:35:06 +00:00
dupe_boxes.append( ( 'other', dupe_commands ) )
2019-05-08 21:06:42 +00:00
2019-05-22 22:35:06 +00:00
for ( panel_name, dupe_commands ) in dupe_boxes:
2019-05-08 21:06:42 +00:00
2019-05-22 22:35:06 +00:00
button_panel = ClientGUICommon.StaticBox( self, panel_name )
2019-05-08 21:06:42 +00:00
2019-05-22 22:35:06 +00:00
for ( label, tooltip, command ) in dupe_commands:
command_button = ClientGUICommon.BetterButton( button_panel, label, HG.client_controller.pub, 'canvas_application_command', command, self._canvas_key )
2021-08-25 21:59:05 +00:00
command_button.SetToolTipWithShortcuts( tooltip, command.GetSimpleAction() )
2019-05-22 22:35:06 +00:00
button_panel.Add( command_button, CC.FLAGS_EXPAND_PERPENDICULAR )
2019-05-08 21:06:42 +00:00
2019-11-14 03:56:30 +00:00
QP.AddToLayout( command_button_vbox, button_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
2019-05-08 21:06:42 +00:00
2019-11-14 03:56:30 +00:00
self._comparison_statements_vbox = QP.VBoxLayout()
2019-05-08 21:06:42 +00:00
2019-07-31 22:01:02 +00:00
self._comparison_statement_names = [ 'filesize', 'resolution', 'ratio', 'mime', 'num_tags', 'time_imported', 'jpeg_quality', 'pixel_duplicates' ]
2019-05-08 21:06:42 +00:00
self._comparison_statements_sts = {}
for name in self._comparison_statement_names:
2019-11-14 03:56:30 +00:00
panel = QW.QWidget( self )
2019-05-08 21:06:42 +00:00
st = ClientGUICommon.BetterStaticText( panel, 'init' )
self._comparison_statements_sts[ name ] = ( panel, st )
2019-11-14 03:56:30 +00:00
hbox = QP.HBoxLayout()
2019-05-08 21:06:42 +00:00
2020-07-22 20:59:16 +00:00
QP.AddToLayout( hbox, st, CC.FLAGS_CENTER )
2019-05-08 21:06:42 +00:00
2019-11-14 03:56:30 +00:00
panel.setLayout( hbox )
2019-05-08 21:06:42 +00:00
2019-11-14 03:56:30 +00:00
panel.setVisible( False )
2019-05-08 21:06:42 +00:00
2019-11-14 03:56:30 +00:00
QP.AddToLayout( self._comparison_statements_vbox, panel, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
2019-05-08 21:06:42 +00:00
#
2019-11-14 03:56:30 +00:00
top_button_hbox = QP.HBoxLayout()
2019-06-05 19:42:39 +00:00
2021-02-11 01:59:52 +00:00
QP.AddToLayout( top_button_hbox, self._next_button, CC.FLAGS_EXPAND_BOTH_WAYS )
2020-07-29 20:52:44 +00:00
QP.AddToLayout( top_button_hbox, self._trash_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( top_button_hbox, self._cog_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( top_button_hbox, close_button, CC.FLAGS_CENTER_PERPENDICULAR )
2019-06-05 19:42:39 +00:00
2019-11-14 03:56:30 +00:00
navigation_button_hbox = QP.HBoxLayout()
2019-05-08 21:06:42 +00:00
2020-07-29 20:52:44 +00:00
QP.AddToLayout( navigation_button_hbox, self._back_a_pair, CC.FLAGS_CENTER_PERPENDICULAR )
2020-07-22 20:59:16 +00:00
navigation_button_hbox.addStretch( 1 )
2020-07-29 20:52:44 +00:00
QP.AddToLayout( navigation_button_hbox, self._index_text, CC.FLAGS_CENTER_PERPENDICULAR )
2020-07-22 20:59:16 +00:00
navigation_button_hbox.addStretch( 1 )
2020-07-29 20:52:44 +00:00
QP.AddToLayout( navigation_button_hbox, self._skip_a_pair, CC.FLAGS_CENTER_PERPENDICULAR )
2019-05-08 21:06:42 +00:00
2019-11-14 03:56:30 +00:00
vbox = QP.VBoxLayout()
2019-05-08 21:06:42 +00:00
2019-11-14 03:56:30 +00:00
QP.AddToLayout( vbox, navigation_button_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
2021-02-11 01:59:52 +00:00
#QP.AddToLayout( vbox, self._next_button, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, top_button_hbox, CC.FLAGS_EXPAND_PERPENDICULAR )
2019-11-14 03:56:30 +00:00
QP.AddToLayout( vbox, command_button_vbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
QP.AddToLayout( vbox, self._comparison_statements_vbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
2019-05-08 21:06:42 +00:00
2019-11-14 03:56:30 +00:00
self.setLayout( vbox )
2019-05-08 21:06:42 +00:00
HG.client_controller.sub( self, 'SetDuplicatePair', 'canvas_new_duplicate_pair' )
HG.client_controller.sub( self, 'SetIndexString', 'canvas_new_index_string' )
def _EditBackgroundSwitchIntensity( self ):
new_options = HG.client_controller.new_options
value = new_options.GetNoneableInteger( 'duplicate_background_switch_intensity' )
2020-04-29 21:44:12 +00:00
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit lighten/darken intensity' ) as dlg:
2019-05-08 21:06:42 +00:00
panel = ClientGUIScrolledPanelsEdit.EditNoneableIntegerPanel( dlg, value, message = 'intensity: ', none_phrase = 'do not change', min = 1, max = 9 )
dlg.SetPanel( panel )
2019-11-14 03:56:30 +00:00
if dlg.exec() == QW.QDialog.Accepted:
2019-05-08 21:06:42 +00:00
new_value = panel.GetValue()
new_options.SetNoneableInteger( 'duplicate_background_switch_intensity', new_value )
def _EditMergeOptions( self, duplicate_type ):
new_options = HG.client_controller.new_options
duplicate_action_options = new_options.GetDuplicateActionOptions( duplicate_type )
2020-04-29 21:44:12 +00:00
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit duplicate merge options' ) as dlg:
2019-05-08 21:06:42 +00:00
panel = ClientGUIScrolledPanelsEdit.EditDuplicateActionOptionsPanel( dlg, duplicate_type, duplicate_action_options )
dlg.SetPanel( panel )
2019-11-14 03:56:30 +00:00
if dlg.exec() == QW.QDialog.Accepted:
2019-05-08 21:06:42 +00:00
duplicate_action_options = panel.GetValue()
new_options.SetDuplicateActionOptions( duplicate_type, duplicate_action_options )
def _GetIdealSizeAndPosition( self ):
2019-11-14 03:56:30 +00:00
parent_window = self.parentWidget().window()
2019-05-08 21:06:42 +00:00
2020-02-26 22:28:52 +00:00
parent_size = parent_window.size()
parent_width = parent_size.width()
parent_height = parent_size.height()
my_size = self.size()
2019-05-08 21:06:42 +00:00
2020-02-26 22:28:52 +00:00
my_width = my_size.width()
my_height = my_size.height()
2019-05-08 21:06:42 +00:00
my_ideal_width = max( int( parent_width * 0.2 ), self.sizeHint().width() )
2020-07-22 20:59:16 +00:00
my_ideal_height = self.sizeHint().height()
2019-05-08 21:06:42 +00:00
2020-01-02 03:05:35 +00:00
should_resize = my_ideal_width != my_width or my_ideal_height != my_height
2019-05-08 21:06:42 +00:00
2020-02-26 22:28:52 +00:00
ideal_size = QC.QSize( my_ideal_width, my_ideal_height )
ideal_position = ClientGUIFunctions.ClientToScreen( parent_window, QC.QPoint( int( parent_width - my_ideal_width ), int( parent_height * 0.3 ) ) )
2019-05-08 21:06:42 +00:00
2020-02-26 22:28:52 +00:00
return ( should_resize, ideal_size, ideal_position )
2019-05-08 21:06:42 +00:00
def _ResetComparisonStatements( self ):
statements_and_scores = ClientMedia.GetDuplicateComparisonStatements( self._current_media, self._comparison_media )
for name in self._comparison_statement_names:
( panel, st ) = self._comparison_statements_sts[ name ]
got_data = name in statements_and_scores
show_panel = got_data
if panel.isVisible() != show_panel:
2019-05-08 21:06:42 +00:00
panel.setVisible( show_panel )
2019-05-08 21:06:42 +00:00
if got_data:
( statement, score ) = statements_and_scores[ name ]
2019-05-08 21:06:42 +00:00
2019-11-14 03:56:30 +00:00
st.setText( statement )
2019-05-08 21:06:42 +00:00
if score > 0:
object_name = 'HydrusValid'
2019-05-08 21:06:42 +00:00
elif score < 0:
object_name = 'HydrusInvalid'
2019-05-08 21:06:42 +00:00
else:
object_name = 'HydrusIndeterminate'
2019-05-08 21:06:42 +00:00
st.setObjectName( object_name )
2019-05-08 21:06:42 +00:00
st.style().polish( st )
2019-05-08 21:06:42 +00:00
2019-11-14 03:56:30 +00:00
def wheelEvent( self, event ):
2019-05-08 21:06:42 +00:00
2019-11-14 03:56:30 +00:00
QW.QApplication.sendEvent( self.parentWidget(), event )
2019-05-08 21:06:42 +00:00
def SetDuplicatePair( self, canvas_key, shown_media, comparison_media ):
if canvas_key == self._canvas_key:
self._current_media = shown_media
self._comparison_media = comparison_media
self._ResetComparisonStatements()
2020-01-02 03:05:35 +00:00
# minimumsize is not immediately updated without this
self.layout().activate()
self._SizeAndPosition( force = True )
2019-05-08 21:06:42 +00:00
def SetIndexString( self, canvas_key, text ):
if canvas_key == self._canvas_key:
self._current_index_string = text
2019-11-14 03:56:30 +00:00
self._index_text.setText( self._current_index_string )
2019-05-08 21:06:42 +00:00
2020-03-25 21:15:57 +00:00
class CanvasHoverFrameTop( CanvasHoverFrame ):
2015-06-17 20:01:41 +00:00
2018-12-05 22:35:30 +00:00
def __init__( self, parent, my_canvas, canvas_key ):
2015-06-17 20:01:41 +00:00
2020-03-25 21:15:57 +00:00
CanvasHoverFrame.__init__( self, parent, my_canvas, canvas_key )
2015-06-17 20:01:41 +00:00
self._current_zoom = 1.0
self._current_index_string = ''
2019-11-14 03:56:30 +00:00
self._top_hbox = QP.HBoxLayout()
2019-11-20 23:10:46 +00:00
2019-11-14 03:56:30 +00:00
self._title_text = ClientGUICommon.BetterStaticText( self, 'title', ellipsize_end = True )
self._info_text = ClientGUICommon.BetterStaticText( self, 'info', ellipsize_end = True )
2017-03-29 19:39:34 +00:00
2019-11-20 23:10:46 +00:00
self._title_text.setAlignment( QC.Qt.AlignHCenter | QC.Qt.AlignVCenter )
self._info_text.setAlignment( QC.Qt.AlignHCenter | QC.Qt.AlignVCenter )
2017-03-29 19:39:34 +00:00
self._PopulateLeftButtons()
2020-07-22 20:59:16 +00:00
self._top_hbox.addStretch( 1 )
2017-03-29 19:39:34 +00:00
self._PopulateCenterButtons()
2020-07-22 20:59:16 +00:00
self._top_hbox.addStretch( 1 )
2017-03-29 19:39:34 +00:00
self._PopulateRightButtons()
2019-11-14 03:56:30 +00:00
vbox = QP.VBoxLayout()
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
QP.AddToLayout( vbox, self._top_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
2019-11-20 23:10:46 +00:00
QP.AddToLayout( vbox, self._title_text, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._info_text, CC.FLAGS_EXPAND_PERPENDICULAR )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self.setLayout( vbox )
2015-06-17 20:01:41 +00:00
2017-05-10 21:33:58 +00:00
HG.client_controller.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
HG.client_controller.sub( self, 'SetCurrentZoom', 'canvas_new_zoom' )
HG.client_controller.sub( self, 'SetIndexString', 'canvas_new_index_string' )
2015-06-17 20:01:41 +00:00
2017-03-29 19:39:34 +00:00
def _Archive( self ):
2015-06-17 20:01:41 +00:00
2017-03-29 19:39:34 +00:00
if self._current_media.HasInbox():
2021-08-25 21:59:05 +00:00
command = CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_FILE )
2017-03-29 19:39:34 +00:00
else:
2021-08-25 21:59:05 +00:00
command = CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_INBOX_FILE )
2017-03-29 19:39:34 +00:00
2018-03-14 21:01:02 +00:00
HG.client_controller.pub( 'canvas_application_command', command, self._canvas_key )
2017-05-10 21:33:58 +00:00
2017-03-29 19:39:34 +00:00
def _GetIdealSizeAndPosition( self ):
2015-06-17 20:01:41 +00:00
2019-12-11 23:18:37 +00:00
# clip this and friends to availableScreenGeometry for size and position, not rely 100% on parent
2019-11-14 03:56:30 +00:00
parent_window = self.parentWidget().window()
2017-03-29 19:39:34 +00:00
2020-02-26 22:28:52 +00:00
parent_size = parent_window.size()
2017-03-29 19:39:34 +00:00
2020-02-26 22:28:52 +00:00
parent_width = parent_size.width()
my_size = self.size()
my_width = my_size.width()
my_height = my_size.height()
2017-03-29 19:39:34 +00:00
2020-08-19 22:38:20 +00:00
my_ideal_width = max( int( parent_width * 0.6 ), self.sizeHint().width() )
2017-03-29 19:39:34 +00:00
2019-11-14 03:56:30 +00:00
my_ideal_height = self.sizeHint().height()
should_resize = my_ideal_width != my_width or my_ideal_height != my_height
2017-03-29 19:39:34 +00:00
2020-02-26 22:28:52 +00:00
ideal_size = QC.QSize( my_ideal_width, my_ideal_height )
ideal_position = ClientGUIFunctions.ClientToScreen( parent_window, QC.QPoint( int( parent_width * 0.2 ), 0 ) )
2017-03-29 19:39:34 +00:00
2020-02-26 22:28:52 +00:00
return ( should_resize, ideal_size, ideal_position )
2017-03-29 19:39:34 +00:00
def _PopulateCenterButtons( self ):
2020-03-11 21:52:11 +00:00
self._archive_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().archive, self._Archive )
2017-03-29 19:39:34 +00:00
2020-03-11 21:52:11 +00:00
self._trash_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().delete, HG.client_controller.pub, 'canvas_delete', self._canvas_key )
2019-11-14 03:56:30 +00:00
self._trash_button.setToolTip( 'send to trash' )
2015-08-05 18:42:35 +00:00
2020-03-11 21:52:11 +00:00
self._delete_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().trash_delete, HG.client_controller.pub, 'canvas_delete', self._canvas_key )
2019-11-14 03:56:30 +00:00
self._delete_button.setToolTip( 'delete completely' )
2015-08-05 18:42:35 +00:00
2020-03-11 21:52:11 +00:00
self._undelete_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().undelete, HG.client_controller.pub, 'canvas_undelete', self._canvas_key )
2019-11-14 03:56:30 +00:00
self._undelete_button.setToolTip( 'undelete' )
2015-06-17 20:01:41 +00:00
2020-07-29 20:52:44 +00:00
QP.AddToLayout( self._top_hbox, self._archive_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, self._trash_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, self._delete_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, self._undelete_button, CC.FLAGS_CENTER_PERPENDICULAR )
2017-03-29 19:39:34 +00:00
def _PopulateLeftButtons( self ):
2017-04-19 20:58:30 +00:00
self._index_text = ClientGUICommon.BetterStaticText( self, 'index' )
2017-03-29 19:39:34 +00:00
2020-07-29 20:52:44 +00:00
QP.AddToLayout( self._top_hbox, self._index_text, CC.FLAGS_CENTER_PERPENDICULAR )
2017-03-29 19:39:34 +00:00
def _PopulateRightButtons( self ):
2017-04-19 20:58:30 +00:00
self._zoom_text = ClientGUICommon.BetterStaticText( self, 'zoom' )
2015-06-17 20:01:41 +00:00
2021-08-25 21:59:05 +00:00
zoom_in = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().zoom_in, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ZOOM_IN_VIEWER_CENTER ), self._canvas_key )
zoom_in.SetToolTipWithShortcuts( 'zoom in', CAC.SIMPLE_ZOOM_IN )
2015-06-17 20:01:41 +00:00
2021-08-25 21:59:05 +00:00
zoom_out = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().zoom_out, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ZOOM_OUT_VIEWER_CENTER ), self._canvas_key )
zoom_out.SetToolTipWithShortcuts( 'zoom out', CAC.SIMPLE_ZOOM_OUT )
2015-06-17 20:01:41 +00:00
2021-08-25 21:59:05 +00:00
zoom_switch = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().zoom_switch, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_SWITCH_BETWEEN_100_PERCENT_AND_CANVAS_ZOOM_VIEWER_CENTER ), self._canvas_key )
zoom_switch.SetToolTipWithShortcuts( 'zoom switch', CAC.SIMPLE_SWITCH_BETWEEN_100_PERCENT_AND_CANVAS_ZOOM )
2015-06-17 20:01:41 +00:00
2020-02-05 22:55:21 +00:00
self._volume_control = ClientGUIMediaControls.VolumeControl( self, ClientGUICommon.CANVAS_MEDIA_VIEWER )
2020-01-22 21:04:43 +00:00
if not ClientGUIMPV.MPV_IS_AVAILABLE:
2020-02-05 22:55:21 +00:00
self._volume_control.hide()
2020-01-22 21:04:43 +00:00
2020-03-11 21:52:11 +00:00
shortcuts = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().keyboard, self._ShowShortcutMenu )
2019-11-14 03:56:30 +00:00
shortcuts.setToolTip( 'shortcuts' )
2015-06-17 20:01:41 +00:00
2020-03-11 21:52:11 +00:00
fullscreen_switch = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().fullscreen_switch, HG.client_controller.pub, 'canvas_fullscreen_switch', self._canvas_key )
2019-11-14 03:56:30 +00:00
fullscreen_switch.setToolTip( 'fullscreen switch' )
2015-08-05 18:42:35 +00:00
2019-11-20 23:10:46 +00:00
if HC.PLATFORM_MACOS:
2019-11-14 03:56:30 +00:00
fullscreen_switch.hide()
2018-03-28 21:55:58 +00:00
2021-08-25 21:59:05 +00:00
open_externally = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().open_externally, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_OPEN_FILE_IN_EXTERNAL_PROGRAM ), self._canvas_key )
open_externally.SetToolTipWithShortcuts( 'open externally', CAC.SIMPLE_OPEN_FILE_IN_EXTERNAL_PROGRAM )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
drag_button = QW.QPushButton( self )
2020-03-11 21:52:11 +00:00
drag_button.setIcon( QG.QIcon( CC.global_pixmaps().drag ) )
drag_button.setIconSize( CC.global_pixmaps().drag.size() )
2019-11-14 03:56:30 +00:00
drag_button.setToolTip( 'drag from here to export file' )
drag_button.pressed.connect( self.EventDragButton )
2020-03-11 21:52:11 +00:00
close = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().stop, HG.client_controller.pub, 'canvas_close', self._canvas_key )
2019-11-14 03:56:30 +00:00
close.setToolTip( 'close' )
2020-07-29 20:52:44 +00:00
QP.AddToLayout( self._top_hbox, self._zoom_text, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, zoom_in, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, zoom_out, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, zoom_switch, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, self._volume_control, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, shortcuts, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, fullscreen_switch, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, open_externally, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, drag_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, close, CC.FLAGS_CENTER_PERPENDICULAR )
2015-06-17 20:01:41 +00:00
2017-03-29 19:39:34 +00:00
def _ResetArchiveButton( self ):
2015-06-17 20:01:41 +00:00
2017-03-29 19:39:34 +00:00
if self._current_media.HasInbox():
2020-03-11 21:52:11 +00:00
ClientGUIFunctions.SetBitmapButtonBitmap( self._archive_button, CC.global_pixmaps().archive )
2019-11-14 03:56:30 +00:00
self._archive_button.setToolTip( 'archive' )
2017-03-29 19:39:34 +00:00
else:
2020-03-11 21:52:11 +00:00
ClientGUIFunctions.SetBitmapButtonBitmap( self._archive_button, CC.global_pixmaps().to_inbox )
2019-11-14 03:56:30 +00:00
self._archive_button.setToolTip( 'return to inbox' )
2017-03-29 19:39:34 +00:00
2015-06-17 20:01:41 +00:00
def _ResetButtons( self ):
if self._current_media is not None:
2017-03-29 19:39:34 +00:00
self._ResetArchiveButton()
2015-06-17 20:01:41 +00:00
2021-04-28 21:43:16 +00:00
locations_manager = self._current_media.GetLocationsManager()
2015-08-05 18:42:35 +00:00
2021-04-28 21:43:16 +00:00
if CC.LOCAL_FILE_SERVICE_KEY in locations_manager.GetCurrent():
2015-08-05 18:42:35 +00:00
2019-11-14 03:56:30 +00:00
self._trash_button.show()
self._delete_button.hide()
self._undelete_button.hide()
2015-08-05 18:42:35 +00:00
2021-04-28 21:43:16 +00:00
elif locations_manager.IsTrashed():
2015-08-05 18:42:35 +00:00
2019-11-14 03:56:30 +00:00
self._trash_button.hide()
self._delete_button.show()
self._undelete_button.show()
2015-08-05 18:42:35 +00:00
2015-06-17 20:01:41 +00:00
def _ResetText( self ):
if self._current_media is None:
2019-11-14 03:56:30 +00:00
self._title_text.hide()
self._info_text.hide()
2015-06-17 20:01:41 +00:00
else:
label = self._current_media.GetTitleString()
if len( label ) > 0:
2019-11-14 03:56:30 +00:00
self._title_text.setText( label )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self._title_text.show()
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
else: self._title_text.hide()
2015-06-17 20:01:41 +00:00
2016-04-20 20:42:21 +00:00
lines = self._current_media.GetPrettyInfoLines()
label = ' | '.join( lines )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self._info_text.setText( label )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self._info_text.show()
2015-06-17 20:01:41 +00:00
2018-12-05 22:35:30 +00:00
def _FlipActiveDefaultCustomShortcut( self, name ):
2017-04-19 20:58:30 +00:00
2017-12-06 22:06:56 +00:00
new_options = HG.client_controller.new_options
2017-04-19 20:58:30 +00:00
2018-12-05 22:35:30 +00:00
default_media_viewer_custom_shortcuts = list( new_options.GetStringList( 'default_media_viewer_custom_shortcuts' ) )
if name in default_media_viewer_custom_shortcuts:
default_media_viewer_custom_shortcuts.remove( name )
else:
default_media_viewer_custom_shortcuts.append( name )
default_media_viewer_custom_shortcuts.sort()
new_options.SetStringList( 'default_media_viewer_custom_shortcuts', default_media_viewer_custom_shortcuts )
def _ShowShortcutMenu( self ):
2017-04-19 20:58:30 +00:00
2019-06-05 19:42:39 +00:00
all_shortcut_names = HG.client_controller.Read( 'serialisable_names', HydrusSerialisable.SERIALISABLE_TYPE_SHORTCUT_SET )
2017-04-19 20:58:30 +00:00
2020-02-19 21:48:36 +00:00
custom_shortcuts_names = [ name for name in all_shortcut_names if name not in ClientGUIShortcuts.SHORTCUTS_RESERVED_NAMES ]
2017-04-19 20:58:30 +00:00
2019-11-14 03:56:30 +00:00
menu = QW.QMenu()
2020-03-25 21:15:57 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'edit shortcuts', 'edit your sets of shortcuts, and change what shortcuts are currently active on this media viewer', ClientGUIShortcutControls.ManageShortcuts, self )
2018-12-05 22:35:30 +00:00
if len( custom_shortcuts_names ) > 0:
2017-04-19 20:58:30 +00:00
2018-12-05 22:35:30 +00:00
my_canvas_active_custom_shortcuts = self._my_canvas.GetActiveCustomShortcutNames()
default_media_viewer_custom_shortcuts = HG.client_controller.new_options.GetStringList( 'default_media_viewer_custom_shortcuts' )
2017-04-19 20:58:30 +00:00
2019-11-14 03:56:30 +00:00
current_menu = QW.QMenu( menu )
2017-04-19 20:58:30 +00:00
2018-12-05 22:35:30 +00:00
for name in custom_shortcuts_names:
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuCheckItem( current_menu, name, 'turn this shortcut set on/off', name in my_canvas_active_custom_shortcuts, self._my_canvas.FlipActiveCustomShortcutName, name )
2018-12-05 22:35:30 +00:00
2017-04-19 20:58:30 +00:00
2018-12-05 22:35:30 +00:00
ClientGUIMenus.AppendMenu( menu, current_menu, 'set current shortcuts' )
2017-04-19 20:58:30 +00:00
2019-11-14 03:56:30 +00:00
defaults_menu = QW.QMenu( menu )
2017-04-19 20:58:30 +00:00
2018-12-05 22:35:30 +00:00
for name in custom_shortcuts_names:
2017-04-19 20:58:30 +00:00
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuCheckItem( defaults_menu, name, 'turn this shortcut set on/off by default', name in default_media_viewer_custom_shortcuts, self._FlipActiveDefaultCustomShortcut, name )
2017-04-19 20:58:30 +00:00
2018-12-05 22:35:30 +00:00
ClientGUIMenus.AppendMenu( menu, defaults_menu, 'set default shortcuts' )
2020-03-04 22:12:53 +00:00
CGC.core().PopupMenu( self, menu )
2017-04-19 20:58:30 +00:00
2019-11-14 03:56:30 +00:00
def EventDragButton( self ):
2018-03-28 21:55:58 +00:00
if self._current_media is None:
2019-11-14 03:56:30 +00:00
return True # was: event.ignore()
2018-03-28 21:55:58 +00:00
page_key = None
media = [ self._current_media ]
2019-11-14 03:56:30 +00:00
alt_down = QW.QApplication.keyboardModifiers() & QC.Qt.AltModifier
2018-03-28 21:55:58 +00:00
2020-03-11 21:52:11 +00:00
result = ClientGUIDragDrop.DoFileExportDragDrop( self, page_key, media, alt_down )
2018-03-28 21:55:58 +00:00
2019-11-14 03:56:30 +00:00
if result != QC.Qt.IgnoreAction:
2018-03-28 21:55:58 +00:00
2021-08-25 21:59:05 +00:00
HG.client_controller.pub( 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_PAUSE_MEDIA ), self._canvas_key )
2018-03-28 21:55:58 +00:00
2019-11-14 03:56:30 +00:00
def resizeEvent( self, event ):
# reset wrap width
self._ResetText()
event.ignore()
def wheelEvent( self, event ):
2015-09-16 18:11:00 +00:00
2019-11-14 03:56:30 +00:00
QW.QApplication.sendEvent( self.parentWidget(), event )
2015-09-16 18:11:00 +00:00
2015-06-17 20:01:41 +00:00
def ProcessContentUpdates( self, service_keys_to_content_updates ):
if self._current_media is not None:
my_hash = self._current_media.GetHash()
do_redraw = False
2021-04-28 21:43:16 +00:00
for ( service_key, content_updates ) in service_keys_to_content_updates.items():
2015-06-17 20:01:41 +00:00
if True in ( my_hash in content_update.GetHashes() for content_update in content_updates ):
do_redraw = True
break
if do_redraw:
2021-08-18 21:10:01 +00:00
self._ResetText()
2015-06-17 20:01:41 +00:00
self._ResetButtons()
def SetCurrentZoom( self, canvas_key, zoom ):
if canvas_key == self._canvas_key:
self._current_zoom = zoom
2015-08-26 21:18:39 +00:00
label = ClientData.ConvertZoomToPercentage( self._current_zoom )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self._zoom_text.setText( label )
2015-06-17 20:01:41 +00:00
def SetDisplayMedia( self, canvas_key, media ):
if canvas_key == self._canvas_key:
2020-03-25 21:15:57 +00:00
CanvasHoverFrame.SetDisplayMedia( self, canvas_key, media )
2015-06-17 20:01:41 +00:00
self._ResetText()
2017-03-29 19:39:34 +00:00
self._ResetButtons()
2015-07-15 20:28:26 +00:00
2019-12-11 23:18:37 +00:00
# minimumsize is not immediately updated without this
self.layout().activate()
self._SizeAndPosition( force = True )
2015-06-17 20:01:41 +00:00
def SetIndexString( self, canvas_key, text ):
if canvas_key == self._canvas_key:
self._current_index_string = text
2019-11-14 03:56:30 +00:00
self._index_text.setText( self._current_index_string )
2015-06-17 20:01:41 +00:00
2020-03-25 21:15:57 +00:00
class CanvasHoverFrameTopArchiveDeleteFilter( CanvasHoverFrameTop ):
2017-05-10 21:33:58 +00:00
def _Archive( self ):
2021-08-25 21:59:05 +00:00
HG.client_controller.pub( 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_FILE ), self._canvas_key )
2017-05-10 21:33:58 +00:00
def _PopulateLeftButtons( self ):
2021-08-25 21:59:05 +00:00
self._back_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().previous, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_BACK ), self._canvas_key )
self._back_button.SetToolTipWithShortcuts( 'back', CAC.SIMPLE_ARCHIVE_DELETE_FILTER_BACK )
2017-05-31 21:50:53 +00:00
2020-07-29 20:52:44 +00:00
QP.AddToLayout( self._top_hbox, self._back_button, CC.FLAGS_CENTER_PERPENDICULAR )
2017-05-31 21:50:53 +00:00
2020-03-25 21:15:57 +00:00
CanvasHoverFrameTop._PopulateLeftButtons( self )
2017-05-10 21:33:58 +00:00
2021-08-25 21:59:05 +00:00
self._skip_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().next_bmp, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_DELETE_FILTER_SKIP ), self._canvas_key )
self._skip_button.SetToolTipWithShortcuts( 'skip', CAC.SIMPLE_ARCHIVE_DELETE_FILTER_SKIP )
2017-05-31 21:50:53 +00:00
2020-07-29 20:52:44 +00:00
QP.AddToLayout( self._top_hbox, self._skip_button, CC.FLAGS_CENTER_PERPENDICULAR )
2017-05-10 21:33:58 +00:00
def _ResetArchiveButton( self ):
2020-03-11 21:52:11 +00:00
ClientGUIFunctions.SetBitmapButtonBitmap( self._archive_button, CC.global_pixmaps().archive )
2019-11-14 03:56:30 +00:00
self._archive_button.setToolTip( 'archive' )
2017-05-10 21:33:58 +00:00
2020-03-25 21:15:57 +00:00
class CanvasHoverFrameTopNavigable( CanvasHoverFrameTop ):
2017-05-31 21:50:53 +00:00
def _PopulateLeftButtons( self ):
2021-08-25 21:59:05 +00:00
self._previous_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().previous, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_PREVIOUS ), self._canvas_key )
self._previous_button.SetToolTipWithShortcuts( 'previous', CAC.SIMPLE_VIEW_PREVIOUS )
2017-05-31 21:50:53 +00:00
self._index_text = ClientGUICommon.BetterStaticText( self, 'index' )
2021-08-25 21:59:05 +00:00
self._next_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().next_bmp, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_NEXT ), self._canvas_key )
self._next_button.SetToolTipWithShortcuts( 'next', CAC.SIMPLE_VIEW_NEXT )
2017-05-31 21:50:53 +00:00
2020-07-29 20:52:44 +00:00
QP.AddToLayout( self._top_hbox, self._previous_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, self._index_text, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( self._top_hbox, self._next_button, CC.FLAGS_CENTER_PERPENDICULAR )
2017-05-31 21:50:53 +00:00
2020-03-25 21:15:57 +00:00
class CanvasHoverFrameTopDuplicatesFilter( CanvasHoverFrameTopNavigable ):
2017-03-29 19:39:34 +00:00
def _PopulateLeftButtons( self ):
2021-08-25 21:59:05 +00:00
self._first_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().first, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_BACK ), self._canvas_key )
self._first_button.SetToolTipWithShortcuts( 'go back a pair', CAC.SIMPLE_DUPLICATE_FILTER_BACK )
2017-05-17 21:53:02 +00:00
2020-07-29 20:52:44 +00:00
QP.AddToLayout( self._top_hbox, self._first_button, CC.FLAGS_CENTER_PERPENDICULAR )
2017-05-17 21:53:02 +00:00
2020-03-25 21:15:57 +00:00
CanvasHoverFrameTopNavigable._PopulateLeftButtons( self )
2017-03-29 19:39:34 +00:00
2021-08-25 21:59:05 +00:00
self._last_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().last, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_DUPLICATE_FILTER_SKIP ), self._canvas_key )
self._last_button.SetToolTipWithShortcuts( 'show a different pair', CAC.SIMPLE_DUPLICATE_FILTER_SKIP )
2017-03-29 19:39:34 +00:00
2020-07-29 20:52:44 +00:00
QP.AddToLayout( self._top_hbox, self._last_button, CC.FLAGS_CENTER_PERPENDICULAR )
2017-03-29 19:39:34 +00:00
2020-03-25 21:15:57 +00:00
class CanvasHoverFrameTopNavigableList( CanvasHoverFrameTopNavigable ):
2017-03-29 19:39:34 +00:00
def _PopulateLeftButtons( self ):
2021-08-25 21:59:05 +00:00
self._first_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().first, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_FIRST ), self._canvas_key )
self._first_button.SetToolTipWithShortcuts( 'first', CAC.SIMPLE_VIEW_FIRST )
2017-03-29 19:39:34 +00:00
2020-07-29 20:52:44 +00:00
QP.AddToLayout( self._top_hbox, self._first_button, CC.FLAGS_CENTER_PERPENDICULAR )
2017-03-29 19:39:34 +00:00
2020-03-25 21:15:57 +00:00
CanvasHoverFrameTopNavigable._PopulateLeftButtons( self )
2017-03-29 19:39:34 +00:00
2021-08-25 21:59:05 +00:00
self._last_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().last, HG.client_controller.pub, 'canvas_application_command', CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_VIEW_LAST ), self._canvas_key )
self._last_button.SetToolTipWithShortcuts( 'last', CAC.SIMPLE_VIEW_LAST )
2017-03-29 19:39:34 +00:00
2020-07-29 20:52:44 +00:00
QP.AddToLayout( self._top_hbox, self._last_button, CC.FLAGS_CENTER_PERPENDICULAR )
2017-03-29 19:39:34 +00:00
2020-03-25 21:15:57 +00:00
class CanvasHoverFrameTopRight( CanvasHoverFrame ):
2015-06-17 20:01:41 +00:00
def __init__( self, parent, my_canvas, top_hover: CanvasHoverFrameTop, canvas_key ):
2015-06-17 20:01:41 +00:00
2020-03-25 21:15:57 +00:00
CanvasHoverFrame.__init__( self, parent, my_canvas, canvas_key )
2015-06-17 20:01:41 +00:00
self._top_hover = top_hover
2019-11-14 03:56:30 +00:00
vbox = QP.VBoxLayout()
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self._icon_panel = QW.QWidget( self )
2015-06-17 20:01:41 +00:00
2020-03-11 21:52:11 +00:00
self._trash_icon = ClientGUICommon.BufferedWindowIcon( self._icon_panel, CC.global_pixmaps().trash )
2020-05-06 21:31:41 +00:00
self._inbox_icon = ClientGUICommon.BufferedWindowIcon( self._icon_panel, CC.global_pixmaps().inbox, click_callable = self._Archive )
self._notes_icon = ClientGUICommon.BufferedWindowIcon( self._icon_panel, CC.global_pixmaps().notes, click_callable = self._EditNotes )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
icon_hbox = QP.HBoxLayout( spacing = 0 )
2015-06-17 20:01:41 +00:00
2020-07-22 20:59:16 +00:00
icon_hbox.addStretch( 1 )
2020-07-29 20:52:44 +00:00
QP.AddToLayout( icon_hbox, self._inbox_icon, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( icon_hbox, self._trash_icon, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( icon_hbox, self._notes_icon, CC.FLAGS_CENTER_PERPENDICULAR )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self._icon_panel.setLayout( icon_hbox )
2015-06-17 20:01:41 +00:00
# repo strings
2019-11-14 03:56:30 +00:00
self._file_repos = QP.MakeQLabelWithAlignment( '', self, QC.Qt.AlignRight | QC.Qt.AlignVCenter )
2015-06-17 20:01:41 +00:00
2017-04-26 21:58:12 +00:00
# urls
self._last_seen_urls = []
2019-11-14 03:56:30 +00:00
self._urls_vbox = QP.VBoxLayout()
2017-04-26 21:58:12 +00:00
2015-06-17 20:01:41 +00:00
# likes
2019-11-14 03:56:30 +00:00
like_hbox = QP.HBoxLayout( spacing = 0 )
2015-06-17 20:01:41 +00:00
2020-03-11 21:52:11 +00:00
like_services = HG.client_controller.services_manager.GetServices( ( HC.LOCAL_RATING_LIKE, ) )
2015-06-17 20:01:41 +00:00
2018-08-15 20:40:30 +00:00
if len( like_services ) > 0:
2020-07-22 20:59:16 +00:00
like_hbox.addStretch( 1 )
2018-08-15 20:40:30 +00:00
2015-06-17 20:01:41 +00:00
for service in like_services:
service_key = service.GetServiceKey()
2020-03-25 21:15:57 +00:00
control = RatingLikeCanvas( self, service_key, canvas_key )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
QP.AddToLayout( like_hbox, control, CC.FLAGS_NONE )
2015-06-17 20:01:41 +00:00
# each numerical one in turn
2019-11-14 03:56:30 +00:00
QP.AddToLayout( vbox, like_hbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
2015-06-17 20:01:41 +00:00
2020-03-11 21:52:11 +00:00
numerical_services = HG.client_controller.services_manager.GetServices( ( HC.LOCAL_RATING_NUMERICAL, ) )
2015-06-17 20:01:41 +00:00
for service in numerical_services:
service_key = service.GetServiceKey()
2020-03-25 21:15:57 +00:00
control = RatingNumericalCanvas( self, service_key, canvas_key )
2015-06-17 20:01:41 +00:00
2020-07-22 20:59:16 +00:00
QP.AddToLayout( vbox, control, CC.FLAGS_NONE )
2015-06-17 20:01:41 +00:00
2020-07-22 20:59:16 +00:00
vbox.setAlignment( control, QC.Qt.AlignRight )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
QP.AddToLayout( vbox, self._icon_panel, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
QP.AddToLayout( vbox, self._file_repos, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._urls_vbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
2017-05-10 21:33:58 +00:00
2019-11-14 03:56:30 +00:00
self.setLayout( vbox )
2015-06-17 20:01:41 +00:00
self._ResetData()
2017-05-10 21:33:58 +00:00
HG.client_controller.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
2015-09-16 18:11:00 +00:00
2015-06-17 20:01:41 +00:00
2020-05-06 21:31:41 +00:00
def _Archive( self ):
if self._current_media.HasInbox():
2021-08-25 21:59:05 +00:00
command = CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_ARCHIVE_FILE )
2020-05-06 21:31:41 +00:00
else:
2021-08-25 21:59:05 +00:00
command = CAC.ApplicationCommand.STATICCreateSimpleCommand( CAC.SIMPLE_INBOX_FILE )
2020-05-06 21:31:41 +00:00
HG.client_controller.pub( 'canvas_application_command', command, self._canvas_key )
def _EditNotes( self ):
HG.client_controller.pub( 'canvas_manage_notes', self._canvas_key )
2015-06-17 20:01:41 +00:00
def _GetIdealSizeAndPosition( self ):
2019-11-14 03:56:30 +00:00
parent_window = self.parentWidget().window()
2015-06-17 20:01:41 +00:00
2020-02-26 22:28:52 +00:00
parent_size = parent_window.size()
parent_width = parent_size.width()
2015-06-17 20:01:41 +00:00
2020-02-26 22:28:52 +00:00
my_size = self.size()
my_width = my_size.width()
my_height = my_size.height()
2015-06-17 20:01:41 +00:00
2020-08-19 22:38:20 +00:00
# don't use .rect() here, it (sometimes) isn't updated on a hidden window until next show, I think
top_hover_bottom_right = QC.QPoint( self._top_hover.x() + self._top_hover.width(), self._top_hover.y() + self._top_hover.height() )
width_beside_top_hover = ClientGUIFunctions.ClientToScreen( parent_window, parent_window.rect().topRight() ).x() - top_hover_bottom_right.x()
my_ideal_width = max( self.sizeHint().width(), width_beside_top_hover )
2015-06-17 20:01:41 +00:00
2020-07-22 20:59:16 +00:00
my_ideal_height = self.sizeHint().height()
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
should_resize = my_ideal_width != my_width or my_ideal_height != my_height
2020-02-26 22:28:52 +00:00
ideal_size = QC.QSize( my_ideal_width, my_ideal_height )
2020-02-26 22:28:52 +00:00
ideal_position = ClientGUIFunctions.ClientToScreen( parent_window, QC.QPoint( int( parent_width - my_ideal_width ), 0 ) )
2015-06-17 20:01:41 +00:00
if top_hover_bottom_right.x() > ideal_position.x():
ideal_position.setY( top_hover_bottom_right.y() )
2020-02-26 22:28:52 +00:00
return ( should_resize, ideal_size, ideal_position )
2015-06-17 20:01:41 +00:00
def _ResetData( self ):
if self._current_media is not None:
2015-07-08 21:45:38 +00:00
has_inbox = self._current_media.HasInbox()
2021-04-28 21:43:16 +00:00
has_trash = self._current_media.GetLocationsManager().IsTrashed()
2020-05-06 21:31:41 +00:00
has_notes = self._current_media.HasNotes()
2015-07-08 21:45:38 +00:00
2020-05-06 21:31:41 +00:00
if has_inbox or has_trash or has_notes:
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self._icon_panel.show()
2015-06-17 20:01:41 +00:00
2015-07-08 21:45:38 +00:00
if has_inbox:
2019-11-14 03:56:30 +00:00
self._inbox_icon.show()
2015-07-08 21:45:38 +00:00
else:
2019-11-14 03:56:30 +00:00
self._inbox_icon.hide()
2015-07-08 21:45:38 +00:00
if has_trash:
2019-11-14 03:56:30 +00:00
self._trash_icon.show()
2015-07-08 21:45:38 +00:00
else:
2019-11-14 03:56:30 +00:00
self._trash_icon.hide()
2015-07-08 21:45:38 +00:00
2020-05-06 21:31:41 +00:00
if has_notes:
self._notes_icon.show()
else:
self._notes_icon.hide()
2015-06-17 20:01:41 +00:00
else:
2019-11-14 03:56:30 +00:00
self._icon_panel.setVisible( False )
2015-06-17 20:01:41 +00:00
2016-02-24 21:42:54 +00:00
remote_strings = self._current_media.GetLocationsManager().GetRemoteLocationStrings()
2015-06-17 20:01:41 +00:00
2016-02-24 21:42:54 +00:00
if len( remote_strings ) == 0:
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self._file_repos.hide()
2015-06-17 20:01:41 +00:00
else:
2016-02-24 21:42:54 +00:00
remote_string = os.linesep.join( remote_strings )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self._file_repos.setText( remote_string )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self._file_repos.show()
2015-06-17 20:01:41 +00:00
2017-04-26 21:58:12 +00:00
# urls
urls = self._current_media.GetLocationsManager().GetURLs()
if urls != self._last_seen_urls:
self._last_seen_urls = list( urls )
2019-12-05 05:29:32 +00:00
QP.ClearLayout( self._urls_vbox, delete_widgets = True )
2017-04-26 21:58:12 +00:00
2017-12-06 22:06:56 +00:00
url_tuples = HG.client_controller.network_engine.domain_manager.ConvertURLsToMediaViewerTuples( urls )
for ( display_string, url ) in url_tuples:
2017-04-26 21:58:12 +00:00
2018-08-29 20:20:41 +00:00
link = ClientGUICommon.BetterHyperLink( self, display_string, url )
2017-09-20 19:47:31 +00:00
2020-07-22 20:59:16 +00:00
link.setAlignment( QC.Qt.AlignRight )
2019-12-05 05:29:32 +00:00
2020-07-22 20:59:16 +00:00
QP.AddToLayout( self._urls_vbox, link, CC.FLAGS_EXPAND_PERPENDICULAR )
2019-12-05 05:29:32 +00:00
2015-06-17 20:01:41 +00:00
self._SizeAndPosition()
2019-11-14 03:56:30 +00:00
def wheelEvent( self, event ):
2015-09-16 18:11:00 +00:00
2019-12-05 05:29:32 +00:00
QW.QApplication.sendEvent( self.parentWidget(), event )
2015-09-16 18:11:00 +00:00
2015-06-17 20:01:41 +00:00
def ProcessContentUpdates( self, service_keys_to_content_updates ):
if self._current_media is not None:
my_hash = self._current_media.GetHash()
do_redraw = False
2021-04-28 21:43:16 +00:00
for ( service_key, content_updates ) in service_keys_to_content_updates.items():
2015-06-17 20:01:41 +00:00
2017-07-27 00:47:13 +00:00
# ratings updates do not change the shape of this hover but file changes of several kinds do
if True in ( my_hash in content_update.GetHashes() for content_update in content_updates if content_update.GetDataType() == HC.CONTENT_TYPE_FILES ):
2015-06-17 20:01:41 +00:00
2017-05-10 21:33:58 +00:00
do_redraw = True
break
2015-06-17 20:01:41 +00:00
if do_redraw:
self._ResetData()
def SetDisplayMedia( self, canvas_key, media ):
if canvas_key == self._canvas_key:
2020-03-25 21:15:57 +00:00
CanvasHoverFrame.SetDisplayMedia( self, canvas_key, media )
2015-06-17 20:01:41 +00:00
self._ResetData()
2015-07-15 20:28:26 +00:00
2020-07-22 20:59:16 +00:00
# size is not immediately updated without this
2019-12-11 23:18:37 +00:00
self.layout().activate()
self._SizeAndPosition( force = True )
2015-07-15 20:28:26 +00:00
2017-04-19 20:58:30 +00:00
2020-03-25 21:15:57 +00:00
class CanvasHoverFrameTags( CanvasHoverFrame ):
2015-06-17 20:01:41 +00:00
def __init__( self, parent, my_canvas, top_hover: CanvasHoverFrameTop, canvas_key ):
2015-06-17 20:01:41 +00:00
2020-03-25 21:15:57 +00:00
CanvasHoverFrame.__init__( self, parent, my_canvas, canvas_key )
2015-06-17 20:01:41 +00:00
self._top_hover = top_hover
2019-11-14 03:56:30 +00:00
vbox = QP.VBoxLayout()
2015-06-17 20:01:41 +00:00
2020-03-25 21:15:57 +00:00
self._tags = ClientGUIListBoxes.ListBoxTagsMediaHoverFrame( self, self._canvas_key )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
QP.AddToLayout( vbox, self._tags, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
2015-06-17 20:01:41 +00:00
2019-11-14 03:56:30 +00:00
self.setLayout( vbox )
2015-06-17 20:01:41 +00:00
2017-05-10 21:33:58 +00:00
HG.client_controller.sub( self, 'ProcessContentUpdates', 'content_updates_gui' )
2015-06-17 20:01:41 +00:00
def _GetIdealSizeAndPosition( self ):
2019-11-14 03:56:30 +00:00
parent_window = self.parentWidget().window()
2015-06-17 20:01:41 +00:00
2020-02-26 22:28:52 +00:00
parent_size = parent_window.size()
parent_width = parent_size.width()
parent_height = parent_size.height()
my_size = self.size()
2015-06-17 20:01:41 +00:00
2020-02-26 22:28:52 +00:00
my_width = my_size.width()
my_height = my_size.height()
2015-06-17 20:01:41 +00:00
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
2020-02-26 22:28:52 +00:00
ideal_size = QC.QSize( my_ideal_width, my_ideal_height )
ideal_position = ClientGUIFunctions.ClientToScreen( parent_window, QC.QPoint( 0, 0 ) )
2015-06-17 20:01:41 +00:00
2020-02-26 22:28:52 +00:00
return ( should_resize, ideal_size, ideal_position )
2015-06-17 20:01:41 +00:00
def _ResetTags( self ):
2015-10-28 21:29:05 +00:00
if self._current_media is not None:
2015-06-17 20:01:41 +00:00
2020-03-25 21:15:57 +00:00
self._tags.SetTagsByMedia( [ self._current_media ] )
2015-06-17 20:01:41 +00:00
def ProcessContentUpdates( self, service_keys_to_content_updates ):
if self._current_media is not None:
my_hash = self._current_media.GetHash()
do_redraw = False
2021-04-28 21:43:16 +00:00
for ( service_key, content_updates ) in service_keys_to_content_updates.items():
2015-06-17 20:01:41 +00:00
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:
2020-03-25 21:15:57 +00:00
CanvasHoverFrame.SetDisplayMedia( self, canvas_key, media )
2015-06-17 20:01:41 +00:00
self._ResetTags()
2016-12-07 22:12:52 +00:00