hydrus/include/ClientGUITopLevelWindows.py

899 lines
26 KiB
Python
Raw Normal View History

2016-07-13 17:37:44 +00:00
import ClientCaches
import ClientConstants as CC
2018-01-17 22:52:10 +00:00
import ClientGUIMenus
2018-05-16 20:09:50 +00:00
import ClientGUIShortcuts
2016-07-13 17:37:44 +00:00
import HydrusConstants as HC
import HydrusData
2017-03-02 02:14:56 +00:00
import HydrusExceptions
2017-05-10 21:33:58 +00:00
import HydrusGlobals as HG
2016-07-13 17:37:44 +00:00
import os
import wx
2018-01-31 22:58:15 +00:00
( OKEvent, EVT_OK ) = wx.lib.newevent.NewCommandEvent()
2018-02-21 21:59:37 +00:00
CHILD_POSITION_PADDING = 24
2017-04-05 21:16:40 +00:00
FUZZY_PADDING = 15
2016-07-13 17:37:44 +00:00
2016-12-21 22:30:54 +00:00
def GetDisplayPosition( window ):
display_index = wx.Display.GetFromWindow( window )
if display_index == wx.NOT_FOUND:
display_index = 0 # default to primary
display = wx.Display( display_index )
rect = display.GetClientArea()
2018-01-03 22:37:30 +00:00
return tuple( rect.GetPosition() )
2016-12-21 22:30:54 +00:00
def GetDisplaySize( window ):
display_index = wx.Display.GetFromWindow( window )
if display_index == wx.NOT_FOUND:
display_index = 0 # default to primary
display = wx.Display( display_index )
rect = display.GetClientArea()
2018-01-03 22:37:30 +00:00
return tuple( rect.GetSize() )
2016-12-21 22:30:54 +00:00
2016-07-13 17:37:44 +00:00
def GetSafePosition( position ):
( p_x, p_y ) = position
# some window managers size the windows just off screen to cut off borders
# so choose a test position that's a little more lenient
( test_x, test_y ) = ( p_x + FUZZY_PADDING, p_y + FUZZY_PADDING )
display_index = wx.Display.GetFromPoint( ( test_x, test_y ) )
if display_index == wx.NOT_FOUND:
return wx.DefaultPosition
else:
return position
def GetSafeSize( tlw, min_size, gravity ):
( min_width, min_height ) = min_size
parent = tlw.GetParent()
if parent is None:
width = min_width
height = min_height
else:
( parent_window_width, parent_window_height ) = parent.GetTopLevelParent().GetSize()
( width_gravity, height_gravity ) = gravity
if width_gravity == -1:
width = min_width
else:
2017-08-02 21:32:54 +00:00
max_width = parent_window_width - 2 * CHILD_POSITION_PADDING
2016-07-13 17:37:44 +00:00
width = int( width_gravity * max_width )
if height_gravity == -1:
height = min_height
else:
2017-08-02 21:32:54 +00:00
max_height = parent_window_height - 2 * CHILD_POSITION_PADDING
2016-07-13 17:37:44 +00:00
height = int( height_gravity * max_height )
2016-12-21 22:30:54 +00:00
( display_width, display_height ) = GetDisplaySize( tlw )
2016-07-13 17:37:44 +00:00
width = min( display_width, width )
height = min( display_height, height )
return ( width, height )
def ExpandTLWIfPossible( tlw, frame_key, desired_size_delta ):
2017-12-06 22:06:56 +00:00
new_options = HG.client_controller.new_options
2016-07-13 17:37:44 +00:00
( remember_size, remember_position, last_size, last_position, default_gravity, default_position, maximised, fullscreen ) = new_options.GetFrameLocation( frame_key )
if not tlw.IsMaximized() and not tlw.IsFullScreen():
( current_width, current_height ) = tlw.GetSize()
( desired_delta_width, desired_delta_height ) = desired_size_delta
2016-12-21 22:30:54 +00:00
desired_width = current_width + desired_delta_width + FUZZY_PADDING
desired_height = current_height + desired_delta_height + FUZZY_PADDING
2016-07-13 17:37:44 +00:00
2016-12-21 22:30:54 +00:00
( width, height ) = GetSafeSize( tlw, ( desired_width, desired_height ), default_gravity )
2016-07-13 17:37:44 +00:00
if width > current_width or height > current_height:
tlw.SetSize( ( width, height ) )
2016-12-21 22:30:54 +00:00
SlideOffScreenTLWUpAndLeft( tlw )
2017-11-08 22:07:12 +00:00
2016-07-13 17:37:44 +00:00
2017-09-06 20:18:20 +00:00
def MouseIsOnMyDisplay( window ):
window_display_index = wx.Display.GetFromWindow( window )
mouse_display_index = wx.Display.GetFromPoint( wx.GetMousePosition() )
return window_display_index == mouse_display_index
2017-05-24 20:28:24 +00:00
def PostSizeChangedEvent( window ):
event = CC.SizeChangedEvent( -1 )
2018-02-21 21:59:37 +00:00
wx.QueueEvent( window.GetEventHandler(), event )
2017-05-24 20:28:24 +00:00
2016-07-13 17:37:44 +00:00
def SaveTLWSizeAndPosition( tlw, frame_key ):
2017-12-06 22:06:56 +00:00
new_options = HG.client_controller.new_options
2016-07-13 17:37:44 +00:00
( remember_size, remember_position, last_size, last_position, default_gravity, default_position, maximised, fullscreen ) = new_options.GetFrameLocation( frame_key )
maximised = tlw.IsMaximized()
fullscreen = tlw.IsFullScreen()
if not ( maximised or fullscreen ):
2018-01-03 22:37:30 +00:00
safe_position = GetSafePosition( tuple( tlw.GetPosition() ) )
2016-07-13 17:37:44 +00:00
if safe_position != wx.DefaultPosition:
2018-01-03 22:37:30 +00:00
last_size = tuple( tlw.GetSize() )
2016-07-13 17:37:44 +00:00
last_position = safe_position
new_options.SetFrameLocation( frame_key, remember_size, remember_position, last_size, last_position, default_gravity, default_position, maximised, fullscreen )
2018-02-14 21:47:18 +00:00
def SetInitialTLWSizeAndPosition( tlw, frame_key ):
2016-07-13 17:37:44 +00:00
2017-12-06 22:06:56 +00:00
new_options = HG.client_controller.new_options
2016-07-13 17:37:44 +00:00
( remember_size, remember_position, last_size, last_position, default_gravity, default_position, maximised, fullscreen ) = new_options.GetFrameLocation( frame_key )
parent = tlw.GetParent()
if remember_size and last_size is not None:
( width, height ) = last_size
else:
( min_width, min_height ) = tlw.GetEffectiveMinSize()
min_width += FUZZY_PADDING
min_height += FUZZY_PADDING
( width, height ) = GetSafeSize( tlw, ( min_width, min_height ), default_gravity )
tlw.SetInitialSize( ( width, height ) )
min_width = min( 240, width )
min_height = min( 240, height )
tlw.SetMinSize( ( min_width, min_height ) )
#
if remember_position and last_position is not None:
safe_position = GetSafePosition( last_position )
tlw.SetPosition( safe_position )
elif default_position == 'topleft':
if parent is not None:
if isinstance( parent, wx.TopLevelWindow ):
parent_tlp = parent
else:
parent_tlp = parent.GetTopLevelParent()
2018-01-03 22:37:30 +00:00
( parent_x, parent_y ) = parent_tlp.GetPosition()
2016-07-13 17:37:44 +00:00
tlw.SetPosition( ( parent_x + CHILD_POSITION_PADDING, parent_y + CHILD_POSITION_PADDING ) )
else:
safe_position = GetSafePosition( ( 0 + CHILD_POSITION_PADDING, 0 + CHILD_POSITION_PADDING ) )
tlw.SetPosition( safe_position )
2017-11-08 22:07:12 +00:00
SlideOffScreenTLWUpAndLeft( tlw )
2016-07-13 17:37:44 +00:00
elif default_position == 'center':
wx.CallAfter( tlw.Center )
# if these aren't callafter, the size and pos calls don't stick if a restore event happens
if maximised:
wx.CallAfter( tlw.Maximize )
if fullscreen:
wx.CallAfter( tlw.ShowFullScreen, True, wx.FULLSCREEN_ALL )
2016-12-21 22:30:54 +00:00
def SlideOffScreenTLWUpAndLeft( tlw ):
( tlw_width, tlw_height ) = tlw.GetSize()
( tlw_x, tlw_y ) = tlw.GetPosition()
tlw_right = tlw_x + tlw_width
tlw_bottom = tlw_y + tlw_height
( display_width, display_height ) = GetDisplaySize( tlw )
( display_x, display_y ) = GetDisplayPosition( tlw )
display_right = display_x + display_width
display_bottom = display_y + display_height
move_x = tlw_right > display_right
move_y = tlw_bottom > display_bottom
if move_x or move_y:
delta_x = min( display_right - tlw_right, 0 )
delta_y = min( display_bottom - tlw_bottom, 0 )
tlw.SetPosition( ( tlw_x + delta_x, tlw_y + delta_y ) )
2016-07-13 17:37:44 +00:00
class NewDialog( wx.Dialog ):
2017-08-02 21:32:54 +00:00
def __init__( self, parent, title, style_override = None ):
2016-07-13 17:37:44 +00:00
2017-08-02 21:32:54 +00:00
if style_override is None:
style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER
if not HC.PLATFORM_LINUX and parent is not None:
style |= wx.FRAME_FLOAT_ON_PARENT
else:
2016-07-13 17:37:44 +00:00
2017-08-02 21:32:54 +00:00
style = style_override
2016-07-13 17:37:44 +00:00
wx.Dialog.__init__( self, parent, title = title, style = style )
2017-12-06 22:06:56 +00:00
self._new_options = HG.client_controller.new_options
2016-07-13 17:37:44 +00:00
2016-08-10 19:04:08 +00:00
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_FRAMEBK ) )
2016-07-13 17:37:44 +00:00
2017-11-15 22:35:49 +00:00
self.SetIcon( HG.client_controller.frame_icon )
2016-07-13 17:37:44 +00:00
self.Bind( wx.EVT_BUTTON, self.EventDialogButton )
2017-01-25 22:56:55 +00:00
self.Bind( wx.EVT_MENU_CLOSE, self.EventMenuClose )
self.Bind( wx.EVT_MENU_HIGHLIGHT_ALL, self.EventMenuHighlight )
self.Bind( wx.EVT_MENU_OPEN, self.EventMenuOpen )
self._menu_stack = []
self._menu_text_stack = []
2017-05-10 21:33:58 +00:00
HG.client_controller.ResetIdleTimer()
2016-07-13 17:37:44 +00:00
2017-10-18 19:41:25 +00:00
def _CanCancel( self ):
return True
2017-01-25 22:56:55 +00:00
def EventMenuClose( self, event ):
menu = event.GetMenu()
if menu is not None and menu in self._menu_stack:
index = self._menu_stack.index( menu )
del self._menu_stack[ index ]
previous_text = self._menu_text_stack.pop()
2017-05-10 21:33:58 +00:00
status_bar = HG.client_controller.GetGUI().GetStatusBar()
2017-01-25 22:56:55 +00:00
status_bar.SetStatusText( previous_text )
def EventMenuHighlight( self, event ):
if len( self._menu_stack ) > 0:
text = ''
menu = self._menu_stack[-1]
2018-01-17 22:52:10 +00:00
while ClientGUIMenus.MenuIsDead( menu ):
2018-01-10 22:41:51 +00:00
2018-01-17 22:52:10 +00:00
if len( self._menu_stack ) == 0:
return
2018-01-10 22:41:51 +00:00
2018-01-17 22:52:10 +00:00
del self._menu_stack[-1]
2017-01-25 22:56:55 +00:00
2018-01-17 22:52:10 +00:00
menu = self._menu_stack[-1]
2017-01-25 22:56:55 +00:00
2018-01-17 22:52:10 +00:00
menu_item = menu.FindItemById( event.GetMenuId() )
if menu_item is not None:
text = menu_item.GetHelp()
2017-01-25 22:56:55 +00:00
2018-01-10 22:41:51 +00:00
status_bar = HG.client_controller.GetGUI().GetStatusBar()
2017-01-25 22:56:55 +00:00
status_bar.SetStatusText( text )
def EventMenuOpen( self, event ):
menu = event.GetMenu()
if menu is not None:
2017-05-10 21:33:58 +00:00
status_bar = HG.client_controller.GetGUI().GetStatusBar()
2017-01-25 22:56:55 +00:00
previous_text = status_bar.GetStatusText()
self._menu_stack.append( menu )
self._menu_text_stack.append( previous_text )
2017-04-05 21:16:40 +00:00
def EventDialogButton( self, event ):
2017-10-18 19:41:25 +00:00
event_id = event.GetId()
if event_id == wx.ID_CANCEL:
if not self._CanCancel():
return
2018-04-11 22:30:40 +00:00
if not self.IsModal(): # in some rare cases (including spammy AutoHotkey, looks like), this can be fired before the dialog can clean itself up
return
2017-10-18 19:41:25 +00:00
self.EndModal( event_id )
2017-04-05 21:16:40 +00:00
2016-07-13 17:37:44 +00:00
class DialogThatResizes( NewDialog ):
2017-08-02 21:32:54 +00:00
def __init__( self, parent, title, frame_key, style_override = None ):
2016-07-13 17:37:44 +00:00
self._frame_key = frame_key
2017-08-02 21:32:54 +00:00
NewDialog.__init__( self, parent, title, style_override = style_override )
2016-07-13 17:37:44 +00:00
class DialogThatTakesScrollablePanel( DialogThatResizes ):
2017-08-02 21:32:54 +00:00
def __init__( self, parent, title, frame_key = 'regular_dialog', style_override = None ):
2016-07-13 17:37:44 +00:00
self._panel = None
2017-08-02 21:32:54 +00:00
DialogThatResizes.__init__( self, parent, title, frame_key, style_override = style_override )
2016-07-13 17:37:44 +00:00
2016-11-16 20:21:43 +00:00
self._InitialiseButtons()
2016-07-13 17:37:44 +00:00
2018-01-31 22:58:15 +00:00
self.Bind( EVT_OK, self.EventOK )
2016-07-13 17:37:44 +00:00
self.Bind( CC.EVT_SIZE_CHANGED, self.EventChildSizeChanged )
2017-10-18 19:41:25 +00:00
def _CanCancel( self ):
return self._panel.CanCancel()
2016-11-16 20:21:43 +00:00
def _GetButtonBox( self ):
raise NotImplementedError()
def _InitialiseButtons( self ):
raise NotImplementedError()
2018-11-07 23:09:40 +00:00
def _TryEndModal( self, value ):
try:
self.EndModal( value )
except Exception as e:
HydrusData.ShowText( 'This dialog seems to have been unable to close for some reason. I am printing the stack to the log. The dialog may have already closed, or may attempt to close now. Please inform hydrus dev of this situation. I recommend you restart the client if you can. If the UI is locked, you will have to kill it via task manager.' )
HydrusData.PrintException( e )
import traceback
HydrusData.DebugPrint( ''.join( traceback.format_stack() ) )
try:
self.Close()
except:
HydrusData.ShowText( 'The dialog would not close on command.' )
try:
self.Destroy()
except:
HydrusData.ShowText( 'The dialog would not destroy on command.' )
2017-06-21 21:15:59 +00:00
def DoOK( self ):
raise NotImplementedError()
2016-07-13 17:37:44 +00:00
def EventChildSizeChanged( self, event ):
if self._panel is not None:
# the min size here is to compensate for wx.Notebook and anything else that don't update virtualsize on page change
( current_panel_width, current_panel_height ) = self._panel.GetSize()
( desired_panel_width, desired_panel_height ) = self._panel.GetVirtualSize()
( min_panel_width, min_panel_height ) = self._panel.GetEffectiveMinSize()
desired_delta_width = max( 0, desired_panel_width - current_panel_width, min_panel_width - current_panel_width )
desired_delta_height = max( 0, desired_panel_height - current_panel_height, min_panel_height - current_panel_height )
if desired_delta_width > 0 or desired_delta_height > 0:
ExpandTLWIfPossible( self, self._frame_key, ( desired_delta_width, desired_delta_height ) )
2017-06-07 22:05:15 +00:00
def EventOK( self, event ):
2016-07-13 17:37:44 +00:00
2018-05-30 20:13:21 +00:00
if not self:
return
2017-06-21 21:15:59 +00:00
self.DoOK()
2016-07-13 17:37:44 +00:00
def SetPanel( self, panel ):
self._panel = panel
2016-11-16 20:21:43 +00:00
buttonbox = self._GetButtonBox()
2016-07-13 17:37:44 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( self._panel, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.Add( buttonbox, CC.FLAGS_BUTTON_SIZER )
2016-07-13 17:37:44 +00:00
self.SetSizer( vbox )
2018-02-14 21:47:18 +00:00
SetInitialTLWSizeAndPosition( self, self._frame_key )
2016-07-13 17:37:44 +00:00
2018-08-01 20:44:57 +00:00
self._panel.SetupScrolling( scrollIntoView = False ) # this changes geteffectiveminsize calc, so it needs to be below settlwsizeandpos
2017-08-02 21:32:54 +00:00
2018-08-01 20:44:57 +00:00
PostSizeChangedEvent( self ) # helps deal with some Linux/otherscrollbar weirdness where setupscrolling changes inherent virtual size
2016-07-13 17:37:44 +00:00
2016-11-16 20:21:43 +00:00
class DialogThatTakesScrollablePanelClose( DialogThatTakesScrollablePanel ):
def _GetButtonBox( self ):
buttonbox = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
buttonbox.Add( self._close, CC.FLAGS_VCENTER )
2016-11-16 20:21:43 +00:00
return buttonbox
def _InitialiseButtons( self ):
self._close = wx.Button( self, id = wx.ID_OK, label = 'close' )
2017-06-07 22:05:15 +00:00
self._close.Bind( wx.EVT_BUTTON, self.EventOK )
2016-11-16 20:21:43 +00:00
self._cancel = wx.Button( self, id = wx.ID_CANCEL )
self._cancel.Hide()
class DialogNullipotent( DialogThatTakesScrollablePanelClose ):
def __init__( self, parent, title ):
2017-04-19 20:58:30 +00:00
DialogThatTakesScrollablePanelClose.__init__( self, parent, title )
2016-11-16 20:21:43 +00:00
2017-06-21 21:15:59 +00:00
def DoOK( self ):
2016-11-16 20:21:43 +00:00
2017-12-20 22:55:48 +00:00
if not self.IsModal():
return
2016-11-16 20:21:43 +00:00
SaveTLWSizeAndPosition( self, self._frame_key )
2018-11-07 23:09:40 +00:00
self._TryEndModal( wx.ID_OK )
2016-11-16 20:21:43 +00:00
2017-07-27 00:47:13 +00:00
class DialogNullipotentVetoable( DialogThatTakesScrollablePanelClose ):
2018-02-21 21:59:37 +00:00
def __init__( self, parent, title, style_override = None, hide_close_button = False ):
2017-07-27 00:47:13 +00:00
2017-08-02 21:32:54 +00:00
DialogThatTakesScrollablePanelClose.__init__( self, parent, title, style_override = style_override )
2018-02-21 21:59:37 +00:00
if hide_close_button:
self._close.Hide()
self.Bind( wx.EVT_CLOSE, self.EventOK ) # the close event no longer goes to the default button, since it is hidden, wew
2017-07-27 00:47:13 +00:00
def DoOK( self ):
2017-12-20 22:55:48 +00:00
if not self.IsModal():
2017-08-02 21:32:54 +00:00
return
2017-07-27 00:47:13 +00:00
try:
self._panel.TryToClose()
2017-12-13 22:33:07 +00:00
except HydrusExceptions.VetoException as e:
2018-03-14 21:01:02 +00:00
message = HydrusData.ToUnicode( e )
2017-12-13 22:33:07 +00:00
if len( message ) > 0:
wx.MessageBox( message )
2017-07-27 00:47:13 +00:00
return
SaveTLWSizeAndPosition( self, self._frame_key )
2018-11-07 23:09:40 +00:00
self._TryEndModal( wx.ID_OK )
2017-07-27 00:47:13 +00:00
2016-11-16 20:21:43 +00:00
class DialogThatTakesScrollablePanelApplyCancel( DialogThatTakesScrollablePanel ):
def _GetButtonBox( self ):
buttonbox = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
buttonbox.Add( self._apply, CC.FLAGS_VCENTER )
buttonbox.Add( self._cancel, CC.FLAGS_VCENTER )
2016-11-16 20:21:43 +00:00
return buttonbox
def _InitialiseButtons( self ):
self._apply = wx.Button( self, id = wx.ID_OK, label = 'apply' )
2017-06-07 22:05:15 +00:00
self._apply.Bind( wx.EVT_BUTTON, self.EventOK )
2016-11-16 20:21:43 +00:00
self._apply.SetForegroundColour( ( 0, 128, 0 ) )
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'cancel' )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
class DialogEdit( DialogThatTakesScrollablePanelApplyCancel ):
2016-07-13 17:37:44 +00:00
2017-11-22 21:03:07 +00:00
def __init__( self, parent, title, frame_key = 'regular_dialog' ):
2016-07-13 17:37:44 +00:00
2017-11-22 21:03:07 +00:00
DialogThatTakesScrollablePanelApplyCancel.__init__( self, parent, title, frame_key = frame_key )
2016-07-13 17:37:44 +00:00
2017-06-21 21:15:59 +00:00
def DoOK( self ):
2016-07-13 17:37:44 +00:00
2017-12-20 22:55:48 +00:00
if not self.IsModal():
return
2017-03-02 02:14:56 +00:00
try:
value = self._panel.GetValue()
2017-12-13 22:33:07 +00:00
except HydrusExceptions.VetoException as e:
2018-03-14 21:01:02 +00:00
message = HydrusData.ToUnicode( e )
2017-12-13 22:33:07 +00:00
if len( message ) > 0:
wx.MessageBox( message )
2017-03-02 02:14:56 +00:00
return
2016-07-13 17:37:44 +00:00
SaveTLWSizeAndPosition( self, self._frame_key )
2018-11-07 23:09:40 +00:00
self._TryEndModal( wx.ID_OK )
2016-07-13 17:37:44 +00:00
2016-11-16 20:21:43 +00:00
class DialogManage( DialogThatTakesScrollablePanelApplyCancel ):
2016-07-13 17:37:44 +00:00
2017-06-21 21:15:59 +00:00
def DoOK( self ):
2016-07-13 17:37:44 +00:00
2017-12-20 22:55:48 +00:00
if not self.IsModal():
return
2017-04-05 21:16:40 +00:00
try:
self._panel.CommitChanges()
2017-12-13 22:33:07 +00:00
except HydrusExceptions.VetoException as e:
2018-03-14 21:01:02 +00:00
message = HydrusData.ToUnicode( e )
2017-12-13 22:33:07 +00:00
if len( message ) > 0:
wx.MessageBox( message )
2017-04-05 21:16:40 +00:00
return
2016-07-13 17:37:44 +00:00
SaveTLWSizeAndPosition( self, self._frame_key )
2018-11-07 23:09:40 +00:00
self._TryEndModal( wx.ID_OK )
2016-07-13 17:37:44 +00:00
class Frame( wx.Frame ):
def __init__( self, parent, title, float_on_parent = True ):
style = wx.DEFAULT_FRAME_STYLE
if float_on_parent:
style |= wx.FRAME_FLOAT_ON_PARENT
wx.Frame.__init__( self, parent, title = title, style = style )
2017-12-06 22:06:56 +00:00
self._new_options = HG.client_controller.new_options
2016-07-13 17:37:44 +00:00
2016-08-10 19:04:08 +00:00
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_FRAMEBK ) )
2016-07-13 17:37:44 +00:00
2017-11-15 22:35:49 +00:00
self.SetIcon( HG.client_controller.frame_icon )
2016-07-13 17:37:44 +00:00
2017-01-25 22:56:55 +00:00
self.Bind( wx.EVT_MENU_CLOSE, self.EventMenuClose )
self.Bind( wx.EVT_MENU_HIGHLIGHT_ALL, self.EventMenuHighlight )
self.Bind( wx.EVT_MENU_OPEN, self.EventMenuOpen )
self._menu_stack = []
self._menu_text_stack = []
2017-05-10 21:33:58 +00:00
HG.client_controller.ResetIdleTimer()
2016-07-13 17:37:44 +00:00
2017-01-25 22:56:55 +00:00
def EventMenuClose( self, event ):
menu = event.GetMenu()
if menu is not None and menu in self._menu_stack:
index = self._menu_stack.index( menu )
del self._menu_stack[ index ]
previous_text = self._menu_text_stack.pop()
2017-05-10 21:33:58 +00:00
status_bar = HG.client_controller.GetGUI().GetStatusBar()
2017-01-25 22:56:55 +00:00
status_bar.SetStatusText( previous_text )
def EventMenuHighlight( self, event ):
if len( self._menu_stack ) > 0:
text = ''
menu = self._menu_stack[-1]
2018-01-17 22:52:10 +00:00
while ClientGUIMenus.MenuIsDead( menu ):
2018-01-10 22:41:51 +00:00
2018-01-17 22:52:10 +00:00
del self._menu_stack[-1]
2017-01-25 22:56:55 +00:00
2018-01-17 22:52:10 +00:00
if len( self._menu_stack ) == 0:
2017-01-25 22:56:55 +00:00
2018-01-17 22:52:10 +00:00
return
2017-01-25 22:56:55 +00:00
2018-01-17 22:52:10 +00:00
menu = self._menu_stack[-1]
menu_item = menu.FindItemById( event.GetMenuId() )
if menu_item is not None:
text = menu_item.GetHelp()
2017-01-25 22:56:55 +00:00
2018-01-10 22:41:51 +00:00
status_bar = HG.client_controller.GetGUI().GetStatusBar()
2017-01-25 22:56:55 +00:00
status_bar.SetStatusText( text )
def EventMenuOpen( self, event ):
menu = event.GetMenu()
if menu is not None:
2017-05-10 21:33:58 +00:00
status_bar = HG.client_controller.GetGUI().GetStatusBar()
2017-01-25 22:56:55 +00:00
previous_text = status_bar.GetStatusText()
self._menu_stack.append( menu )
self._menu_text_stack.append( previous_text )
2016-07-13 17:37:44 +00:00
class FrameThatResizes( Frame ):
def __init__( self, parent, title, frame_key, float_on_parent = True ):
self._frame_key = frame_key
Frame.__init__( self, parent, title, float_on_parent )
self.Bind( wx.EVT_SIZE, self.EventSizeAndPositionChanged )
self.Bind( wx.EVT_MOVE_END, self.EventSizeAndPositionChanged )
self.Bind( wx.EVT_CLOSE, self.EventSizeAndPositionChanged )
self.Bind( wx.EVT_MAXIMIZE, self.EventSizeAndPositionChanged )
def EventSizeAndPositionChanged( self, event ):
SaveTLWSizeAndPosition( self, self._frame_key )
event.Skip()
class FrameThatTakesScrollablePanel( FrameThatResizes ):
2017-07-12 20:03:45 +00:00
def __init__( self, parent, title, frame_key = 'regular_dialog', float_on_parent = True ):
2016-07-13 17:37:44 +00:00
self._panel = None
FrameThatResizes.__init__( self, parent, title, frame_key, float_on_parent )
2016-07-27 21:53:34 +00:00
self._ok = wx.Button( self, id = wx.ID_OK, label = 'close' )
2018-01-31 22:58:15 +00:00
self._ok.Bind( wx.EVT_BUTTON, self.EventClose )
2016-07-13 17:37:44 +00:00
2018-01-31 22:58:15 +00:00
self.Bind( EVT_OK, self.EventClose )
2016-07-13 17:37:44 +00:00
self.Bind( CC.EVT_SIZE_CHANGED, self.EventChildSizeChanged )
2016-11-30 20:24:17 +00:00
self.Bind( wx.EVT_CHAR_HOOK, self.EventCharHook )
def EventCharHook( self, event ):
2018-05-16 20:09:50 +00:00
( modifier, key ) = ClientGUIShortcuts.ConvertKeyEventToSimpleTuple( event )
2017-04-05 21:16:40 +00:00
if key == wx.WXK_ESCAPE:
2016-11-30 20:24:17 +00:00
self.Close()
2016-12-07 22:12:52 +00:00
else:
event.Skip()
2016-11-30 20:24:17 +00:00
2016-07-13 17:37:44 +00:00
2018-01-31 22:58:15 +00:00
def EventClose( self, event ):
2016-07-13 17:37:44 +00:00
self.Close()
def EventChildSizeChanged( self, event ):
if self._panel is not None:
# the min size here is to compensate for wx.Notebook and anything else that don't update virtualsize on page change
( current_panel_width, current_panel_height ) = self._panel.GetSize()
( desired_panel_width, desired_panel_height ) = self._panel.GetVirtualSize()
( min_panel_width, min_panel_height ) = self._panel.GetEffectiveMinSize()
desired_delta_width = max( 0, desired_panel_width - current_panel_width, min_panel_width - current_panel_width )
desired_delta_height = max( 0, desired_panel_height - current_panel_height, min_panel_height - current_panel_height )
if desired_delta_width > 0 or desired_delta_height > 0:
ExpandTLWIfPossible( self, self._frame_key, ( desired_delta_width, desired_delta_height ) )
def SetPanel( self, panel ):
self._panel = panel
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( self._panel, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.Add( self._ok, CC.FLAGS_LONE_BUTTON )
2016-07-13 17:37:44 +00:00
self.SetSizer( vbox )
2018-02-14 21:47:18 +00:00
SetInitialTLWSizeAndPosition( self, self._frame_key )
2016-07-13 17:37:44 +00:00
self.Show( True )
2018-08-01 20:44:57 +00:00
self._panel.SetupScrolling( scrollIntoView = False ) # this changes geteffectiveminsize calc, so it needs to be below settlwsizeandpos
2016-07-13 17:37:44 +00:00
2018-08-01 20:44:57 +00:00
PostSizeChangedEvent( self ) # helps deal with some Linux/otherscrollbar weirdness where setupscrolling changes inherent virtual size
2018-02-14 21:47:18 +00:00
2016-12-07 22:12:52 +00:00