contextMenu.py (9491B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\control\contextMenu\contextMenu.py 2 import logging 3 import types 4 import weakref 5 from collections import defaultdict 6 import log 7 from carbon.client.script.environment.AudioUtil import PlaySound 8 from carbonui import const as uiconst 9 from carbonui.control.contextMenu.contextMenuMixin import ContextMenuMixin 10 from carbonui.control.contextMenu.menuData import MenuData 11 from carbonui.control.contextMenu.menuDataFactory import CreateMenuDataFromRawTuples 12 from carbonui.control.contextMenu.menuEntryData import MenuEntryDataCaption, MenuEntryDataLabel, MenuEntryDataCheckbox, MenuEntryDataRadioButton, MenuEntryDataSlider 13 from carbonui.control.contextMenu.menuEntryView import MenuEntryView, MenuEntryViewCaption, MenuEntryViewLabel, MenuEntryViewCheckbox, MenuEntryViewRadioButton, MenuEntryViewSlider 14 from carbonui.control.contextMenu.menuUtil import CloseContextMenus 15 from carbonui.primitives.container import Container 16 from carbonui.primitives.containerAutoSize import ContainerAutoSize 17 from carbonui.primitives.line import Line 18 from carbonui.uicore import uicore 19 from carbonui.util.mouseTargetObject import MouseTargetObject 20 from carbonui.decorative.menuUnderlay import MenuUnderlay 21 from uihider import CommandBlockerService 22 logger = logging.getLogger(__name__) 23 24 class ContextMenu(ContainerAutoSize, ContextMenuMixin): 25 default_alignMode = uiconst.TOTOP 26 default_align = uiconst.TOPLEFT 27 default_state = uiconst.UI_NORMAL 28 __notifyevents__ = ['OnMenuHighlightActivated', 'OnMenuHighlightsCleared'] 29 30 def ApplyAttributes(self, attributes): 31 ContainerAutoSize.ApplyAttributes(self, attributes) 32 sm.RegisterNotify(self) 33 self.menuData = attributes.menuData 34 minWidth = attributes.minWidth 35 self.entries = [] 36 self.entries_by_internal_name = defaultdict(list) 37 self.highlights_svc = sm.GetService('uiHighlightingService') 38 self.mainCont = ContainerAutoSize(parent=self, name='mainCont', align=uiconst.TOTOP, padding=8) 39 self.Prepare_Background_() 40 self.ConstructEntries() 41 self.UpdateSize(minWidth) 42 self.SetupHighlights() 43 log.LogInfo('Menu.Setup Completed', id(self)) 44 MouseTargetObject(self) 45 46 def UpdateSize(self, minWidth): 47 if len(self.mainCont.children): 48 maxChildWidth = max([ entry.GetRequiredWidth() for entry in self.entries ]) 49 self.width = max(maxChildWidth + 8, minWidth or 0) + self.mainCont.padLeft + self.mainCont.padRight 50 else: 51 self.width = 100 52 self.mainCont.SetSizeAutomatically() 53 self.SetSizeAutomatically() 54 55 def ConstructEntries(self): 56 entries = self.menuData.GetEntries() 57 wasLine = 0 58 while len(entries): 59 if entries[-1] is None: 60 entries.pop(-1) 61 else: 62 break 63 64 for i, menuEntryData in enumerate(entries): 65 if menuEntryData is None: 66 if not len(self.mainCont.children) or i == len(entries) - 1 or wasLine: 67 continue 68 self._ConstructLine() 69 wasLine = 1 70 else: 71 self._ConstructMenuEntry(menuEntryData) 72 wasLine = 0 73 74 def _ConstructMenuEntry(self, menuEntryData): 75 menuEntryViewClass = self._GetMenuEntryViewClass(menuEntryData) 76 menuEntry = menuEntryViewClass(name=u'context_menu_{}'.format(menuEntryData.internalName or menuEntryData.text), align=uiconst.TOTOP, state=uiconst.UI_NORMAL, parent=self.mainCont, menuEntryData=menuEntryData, iconSize=self.menuData.GetIconSize(), uniqueUiName=getattr(menuEntryData, 'uniqueUiName', None)) 77 self.entries.append(menuEntry) 78 if menuEntryData.internalName: 79 self.entries_by_internal_name[menuEntryData.internalName, menuEntryData.typeID].append(menuEntry) 80 81 def _ConstructLine(self): 82 Line(align=uiconst.TOTOP, parent=self.mainCont, opacity=0.1, padding=(0, 6, 0, 6)) 83 84 def _GetMenuEntryViewClass(self, menuEntryData): 85 if menuEntryData.menuClass: 86 return menuEntryData.menuClass 87 elif isinstance(menuEntryData, MenuEntryDataCaption): 88 return MenuEntryViewCaption 89 elif isinstance(menuEntryData, MenuEntryDataLabel): 90 return MenuEntryViewLabel 91 elif isinstance(menuEntryData, MenuEntryDataRadioButton): 92 return MenuEntryViewRadioButton 93 elif isinstance(menuEntryData, MenuEntryDataCheckbox): 94 return MenuEntryViewCheckbox 95 elif isinstance(menuEntryData, MenuEntryDataSlider): 96 return MenuEntryViewSlider 97 else: 98 return MenuEntryView 99 100 def Prepare_Background_(self, *args): 101 self.underlay = MenuUnderlay(bgParent=self) 102 103 def _OnClose(self): 104 Container._OnClose(self) 105 for each in self.mainCont.children[:]: 106 if hasattr(each, 'Collapse'): 107 each.Collapse() 108 109 self.menuData = None 110 111 def SetupHighlights(self): 112 for restriction, entryViews in self.entries_by_internal_name.iteritems(): 113 internalName, typeID = restriction 114 if self.highlights_svc.is_menu_highlighted(internalName, typeID): 115 for entryView in entryViews: 116 entryView.Highlight() 117 118 def OnMenuHighlightActivated(self, menuName, menuTypeID): 119 self.HighlightEntries(menuName, menuTypeID) 120 121 def OnMenuHighlightsCleared(self): 122 self.ClearHighlights() 123 124 def HighlightEntries(self, menuName, menuTypeID): 125 for restriction, entryViews in self.entries_by_internal_name.iteritems(): 126 if restriction == (menuName, menuTypeID): 127 for entryView in entryViews: 128 entryView.Highlight() 129 130 def ClearHighlights(self): 131 for entryViews in self.entries_by_internal_name.values(): 132 for entryView in entryViews: 133 entryView.ClearHighlight() 134 135 def Collapse(self): 136 if not self.destroyed: 137 for each in self.mainCont.children: 138 if hasattr(each, 'Collapse'): 139 each.Collapse() 140 141 self.Close() 142 143 144 class ContextSubMenu(ContextMenu): 145 146 def ApplyAttributes(self, attributes): 147 self.parentEntry = attributes.parentEntry 148 super(ContextSubMenu, self).ApplyAttributes(attributes) 149 150 def SetSizeAutomatically(self): 151 super(ContextSubMenu, self).SetSizeAutomatically() 152 self._UpdatePosition() 153 154 def _UpdatePosition(self): 155 aL, aT, aW, aH = self.parentEntry.GetAbsolute() 156 if aL + aW + self.width <= uicore.desktop.width: 157 self.left = aL + aW + 2 158 else: 159 self.left = aL - self.width + -2 160 self.top = max(0, min(uicore.desktop.height - self.height, aT)) - 8 161 162 163 def CreateMenuView(menuData, parent = None, minwidth = None): 164 if menuData is None: 165 return 166 if not parent: 167 CloseContextMenus() 168 return ContextMenu(name='menuview', align=uiconst.TOPLEFT, menuData=menuData, minWidth=minwidth) 169 170 171 def ShowMenu(object, auxObject = None): 172 command_blocker = CommandBlockerService.instance() 173 if command_blocker.is_blocked(['menucore', 'menucore.expand']) and not getattr(object, 'ignore_command_blocker', False): 174 logger.info('ShowMenu: Menus disabled') 175 return 176 CloseContextMenus() 177 m = None 178 menuFunc = getattr(object, 'GetMenu', None) 179 if menuFunc: 180 if type(menuFunc) == types.TupleType: 181 func, args = menuFunc 182 m = func(args) 183 else: 184 m = menuFunc() 185 hasAuxOptions = auxObject and hasattr(auxObject, 'GetAuxiliaryMenuOptions') 186 if _IsEmptyList(m): 187 if hasAuxOptions: 188 m = auxObject.GetAuxiliaryMenuOptions() 189 else: 190 logger.info('ShowMenu: No Menu!') 191 return 192 elif hasAuxOptions: 193 m = m + auxObject.GetAuxiliaryMenuOptions() 194 if getattr(object, 'showingMenu', 0): 195 logger.info('ShowMenu: Already showing a menu') 196 return 197 object.showingMenu = 1 198 uicore.contextMenuOwner = weakref.ref(object) 199 try: 200 menuData = CreateMenuDataFromRawTuples(m) 201 if not menuData or not menuData.GetEntries(): 202 return 203 mv = CreateMenuView(menuData=menuData, minwidth=getattr(object, 'minwidth', None)) 204 if mv is not None: 205 object.menuObject_weakref = weakref.ref(mv) 206 uicore.layer.menu.children.insert(0, mv) 207 width, height = mv.GetAbsoluteSize() 208 mv.left, mv.top = _GetMenuViewPosition(width, height, object) 209 PlaySound(uiconst.SOUND_EXPAND) 210 sm.ScatterEvent('OnMenuShown') 211 finally: 212 object.showingMenu = 0 213 214 logger.info('ShowMenu finished OK') 215 216 217 def _IsEmptyList(m): 218 if isinstance(m, MenuData): 219 return False 220 return not m or not filter(None, m) 221 222 223 def _GetMenuViewPosition(width, height, object): 224 topLeft = 1 225 func = getattr(object, 'GetMenuPosition', None) 226 if func is not None: 227 ret = func(object) 228 if len(ret) == 2: 229 x, y = ret 230 else: 231 x, y, topLeft = ret 232 else: 233 x, y = uicore.uilib.x + 10, uicore.uilib.y 234 d = uicore.desktop 235 if topLeft: 236 x, y = min(d.width - width, x), min(d.height - height, y) 237 else: 238 x, y = min(d.width - width, x - width), min(d.height - height, y) 239 return (x, y)