hydrus/hydrus/client/gui/ClientGUIMenus.py

329 lines
7.9 KiB
Python
Raw Normal View History

2023-06-07 20:07:22 +00:00
import typing
2023-04-12 20:34:43 +00:00
from qtpy import QtCore as QC
2019-11-14 03:56:30 +00:00
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
2023-04-19 20:38:13 +00:00
from hydrus.core import HydrusProfiling
2020-04-22 21:00:35 +00:00
from hydrus.core import HydrusText
2024-02-14 21:20:24 +00:00
from hydrus.client import ClientGlobals as CG
2020-07-29 20:52:44 +00:00
2020-04-22 21:00:35 +00:00
from hydrus.client.gui import QtPorting as QP
2016-11-02 21:09:14 +00:00
def AppendMenu( menu, submenu, label ):
2016-12-28 22:24:52 +00:00
label = SanitiseLabel( label )
2016-11-16 20:21:43 +00:00
2019-11-14 03:56:30 +00:00
submenu.setTitle( label )
2020-09-09 20:59:19 +00:00
menu_action = menu.addMenu( submenu )
return menu_action
2023-11-15 22:40:54 +00:00
def AppendMenuIconItem( menu: QW.QMenu, label: str, description: str, icon: QG.QIcon, callable, *args, **kwargs ):
2016-11-02 21:09:14 +00:00
2019-11-14 03:56:30 +00:00
menu_item = QW.QAction( menu )
2023-11-15 22:40:54 +00:00
SetMenuTexts( menu_item, label, description )
2016-11-02 21:09:14 +00:00
menu_item.setIcon( icon )
2016-11-02 21:09:14 +00:00
2019-11-14 03:56:30 +00:00
menu.addAction(menu_item)
2016-12-28 22:24:52 +00:00
2019-11-14 03:56:30 +00:00
BindMenuItem( menu_item, callable, *args, **kwargs )
2016-11-02 21:09:14 +00:00
return menu_item
2023-11-15 22:40:54 +00:00
def AppendMenuBitmapItem( menu, label, description, bitmap, callable, *args, **kwargs ):
return AppendMenuIconItem(menu, label, description, QG.QIcon( bitmap ), callable, *args, **kwargs)
2023-11-15 22:40:54 +00:00
2019-11-14 03:56:30 +00:00
def AppendMenuCheckItem( menu, label, description, initial_value, callable, *args, **kwargs ):
2016-11-02 21:09:14 +00:00
2019-11-14 03:56:30 +00:00
menu_item = QW.QAction( menu )
2019-11-20 23:10:46 +00:00
2023-11-15 22:40:54 +00:00
SetMenuTexts( menu_item, label, description )
2016-12-28 22:24:52 +00:00
2019-11-14 03:56:30 +00:00
menu_item.setCheckable( True )
menu_item.setChecked( initial_value )
2020-03-04 22:12:53 +00:00
2019-11-14 03:56:30 +00:00
menu.addAction( menu_item )
2016-12-28 22:24:52 +00:00
2019-11-14 03:56:30 +00:00
BindMenuItem( menu_item, callable, *args, **kwargs )
2016-12-28 22:24:52 +00:00
return menu_item
def AppendMenuItem( menu, label, description, callable, *args, role: QW.QAction.MenuRole = None, **kwargs ):
2016-12-28 22:24:52 +00:00
2019-11-14 03:56:30 +00:00
menu_item = QW.QAction( menu )
2019-11-20 23:10:46 +00:00
if HC.PLATFORM_MACOS:
menu_item.setMenuRole( role if role is not None else QW.QAction.MenuRole.NoRole )
2019-11-20 23:10:46 +00:00
2023-11-15 22:40:54 +00:00
SetMenuTexts( menu_item, label, description )
2016-12-28 22:24:52 +00:00
2019-11-14 03:56:30 +00:00
menu.addAction( menu_item )
BindMenuItem( menu_item, callable, *args, **kwargs )
2016-12-28 22:24:52 +00:00
return menu_item
2023-11-22 22:29:14 +00:00
2023-06-07 20:07:22 +00:00
def AppendMenuLabel( menu, label, description = '', copy_text = '' ):
2017-01-04 22:48:23 +00:00
2023-11-22 22:29:14 +00:00
if description == label:
description = ''
2023-06-07 20:07:22 +00:00
if copy_text == '':
2023-11-15 22:40:54 +00:00
copy_text = label
2023-06-07 20:07:22 +00:00
2023-04-12 20:34:43 +00:00
if description == '':
2017-01-04 22:48:23 +00:00
2023-06-07 20:07:22 +00:00
description = f'copy "{copy_text}" to clipboard'
2017-01-04 22:48:23 +00:00
2019-11-20 23:10:46 +00:00
2019-11-14 03:56:30 +00:00
menu_item = QW.QAction( menu )
2019-11-20 23:10:46 +00:00
2023-11-15 22:40:54 +00:00
SetMenuTexts( menu_item, label, description )
2017-01-04 22:48:23 +00:00
2019-11-14 03:56:30 +00:00
menu.addAction( menu_item )
2017-01-04 22:48:23 +00:00
2024-02-14 21:20:24 +00:00
BindMenuItem( menu_item, CG.client_controller.pub, 'clipboard', 'text', copy_text )
2020-01-16 02:08:23 +00:00
2017-01-04 22:48:23 +00:00
return menu_item
2022-05-11 21:16:33 +00:00
def AppendMenuOrItem( menu, submenu_name, menu_tuples, sort_tuples = True ):
if sort_tuples:
try:
menu_tuples = sorted( menu_tuples )
except:
pass
if len( menu_tuples ) == 1:
submenu = menu
item_prefix = '{} '.format( submenu_name )
else:
2023-04-12 20:34:43 +00:00
submenu = GenerateMenu( menu )
2022-05-11 21:16:33 +00:00
AppendMenu( menu, submenu, submenu_name )
item_prefix = ''
for ( label, description, call ) in menu_tuples:
label = '{}{}'.format( item_prefix, label )
AppendMenuItem( submenu, label, description, call )
2017-03-15 20:13:04 +00:00
def AppendSeparator( menu ):
2019-11-14 03:56:30 +00:00
num_items = len( menu.actions() )
2017-03-15 20:13:04 +00:00
if num_items > 0:
2019-11-14 03:56:30 +00:00
last_item = menu.actions()[-1]
2017-03-15 20:13:04 +00:00
# got this once, who knows what happened, so we test for QAction now
# 'PySide2.QtGui.QStandardItem' object has no attribute 'isSeparator'
last_item_is_separator = isinstance( last_item, QW.QAction ) and last_item.isSeparator()
if not last_item_is_separator:
2017-03-15 20:13:04 +00:00
2019-11-14 03:56:30 +00:00
menu.addSeparator()
2017-03-15 20:13:04 +00:00
2023-06-07 20:07:22 +00:00
2019-11-14 03:56:30 +00:00
def BindMenuItem( menu_item, callable, *args, **kwargs ):
2016-12-28 22:24:52 +00:00
2017-03-08 23:23:12 +00:00
event_callable = GetEventCallable( callable, *args, **kwargs )
2016-12-28 22:24:52 +00:00
2019-11-14 03:56:30 +00:00
menu_item.triggered.connect( event_callable )
2016-11-02 21:09:14 +00:00
2023-06-07 20:07:22 +00:00
2020-04-22 21:00:35 +00:00
def DestroyMenu( menu ):
2018-02-21 21:59:37 +00:00
2020-04-22 21:00:35 +00:00
if menu is None:
2018-02-21 21:59:37 +00:00
2020-04-22 21:00:35 +00:00
return
2018-02-21 21:59:37 +00:00
2019-11-14 03:56:30 +00:00
if QP.isValid( menu ):
menu.deleteLater()
2016-12-28 22:24:52 +00:00
2023-04-12 20:34:43 +00:00
class StatusBarRedirectFilter( QC.QObject ):
def eventFilter( self, watched, event ):
2023-06-21 19:50:13 +00:00
try:
if event.type() == QC.QEvent.StatusTip:
2024-02-14 21:20:24 +00:00
QW.QApplication.instance().sendEvent( CG.client_controller.gui, event )
2023-06-21 19:50:13 +00:00
return True
except Exception as e:
2023-04-12 20:34:43 +00:00
2023-06-21 19:50:13 +00:00
HydrusData.ShowException( e )
2023-04-12 20:34:43 +00:00
return True
return False
def GenerateMenu( parent: QW.QWidget ) -> QW.QMenu:
menu = QW.QMenu( parent )
menu.setToolTipsVisible( True )
menu.installEventFilter( StatusBarRedirectFilter( menu ) )
return menu
2017-03-08 23:23:12 +00:00
def GetEventCallable( callable, *args, **kwargs ):
2016-12-28 22:24:52 +00:00
2019-11-14 03:56:30 +00:00
def event_callable( checked_state ):
2017-03-08 23:23:12 +00:00
2021-07-14 20:42:19 +00:00
if HG.profile_mode:
2018-01-03 22:37:30 +00:00
summary = 'Profiling menu: ' + repr( callable )
2023-04-19 20:38:13 +00:00
HydrusProfiling.Profile( summary, 'callable( *args, **kwargs )', globals(), locals(), min_duration_ms = HG.menu_profile_min_job_time_ms )
2018-01-03 22:37:30 +00:00
else:
callable( *args, **kwargs )
2017-03-08 23:23:12 +00:00
2016-12-28 22:24:52 +00:00
2017-03-08 23:23:12 +00:00
return event_callable
2016-12-28 22:24:52 +00:00
2021-10-06 20:59:30 +00:00
def SanitiseLabel( label: str ) -> str:
2016-12-28 22:24:52 +00:00
2017-11-01 20:37:39 +00:00
if label == '':
label = '-invalid label-'
2016-12-28 22:24:52 +00:00
return label.replace( '&', '&&' )
2023-11-15 22:40:54 +00:00
2021-10-06 20:59:30 +00:00
def SetMenuItemLabel( menu_item: QW.QAction, label: str ):
label = SanitiseLabel( label )
menu_item.setText( label )
2023-11-15 22:40:54 +00:00
def SetMenuTexts( menu_item: QW.QAction, label: str, description: str ):
label = SanitiseLabel( label )
elided_label = HydrusText.ElideText( label, 128, elide_center = True )
menu_item.setText( elided_label )
menu_item.setStatusTip( description )
if label != elided_label:
menu_item.setToolTip( label )
2023-11-22 22:29:14 +00:00
elif description != label and description != '':
2023-11-15 22:40:54 +00:00
menu_item.setToolTip( description )
menu_item.setWhatsThis( description )
2021-10-06 20:59:30 +00:00
def SetMenuTitle( menu: QW.QMenu, label: str ):
label = SanitiseLabel( label )
menu.setTitle( label )
2023-06-07 20:07:22 +00:00
def SpamItems( menu: QW.QMenu, labels_descriptions_and_calls: typing.Collection[ typing.Tuple[ str, str, typing.Callable ] ], max_allowed: int ):
if len( labels_descriptions_and_calls ) > max_allowed:
num_to_show = max_allowed - 1
else:
num_to_show = max_allowed
for ( label, description, call ) in list( labels_descriptions_and_calls )[:num_to_show]:
AppendMenuItem( menu, label, description, call )
if len( labels_descriptions_and_calls ) > num_to_show:
# maybe one day this becomes a thing that extends the menu to show them all
AppendMenuLabel( menu, '{} more...'.format( len( labels_descriptions_and_calls ) - num_to_show ) )
def SpamLabels( menu: QW.QMenu, labels_and_copy_texts: typing.Collection[ typing.Tuple[ str, str ] ], max_allowed: int ):
if len( labels_and_copy_texts ) > max_allowed:
num_to_show = max_allowed - 1
else:
num_to_show = max_allowed
for ( label, copy_text ) in list( labels_and_copy_texts )[:num_to_show]:
AppendMenuLabel( menu, label, copy_text = copy_text )
if len( labels_and_copy_texts ) > num_to_show:
# maybe one day this becomes a thing that extends the menu to show them all
AppendMenuLabel( menu, '{} more...'.format( len( labels_and_copy_texts ) - num_to_show ) )