buySellMultiBase.py (14776B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\market\buySellMultiBase.py 2 import math 3 import eveformat 4 import evelink.client 5 from carbon.common.script.util.format import FmtAmt 6 from carbonui import TextColor, uiconst 7 from carbonui.control.scrollContainer import ScrollContainer 8 from carbonui.primitives.container import Container 9 from carbonui.primitives.sprite import Sprite 10 from carbonui.button.group import ButtonGroup 11 from carbonui.control.checkbox import Checkbox 12 from eve.client.script.ui.control.eveIcon import Icon 13 from eve.client.script.ui.control.eveLabel import EveCaptionSmall 14 from carbonui.control.window import Window 15 from eve.client.script.ui.control.utilMenu import UtilMenu 16 from eve.client.script.ui.shared.market.accessControl import MarketAccessControl 17 from eve.client.script.ui.shared.pointerTool.pointerToolConst import UNIQUE_NAME_MARKET_ORDER_DURATION 18 from eve.common.lib.appConst import corpRoleAccountant, corpRoleTrader 19 import evetypes 20 from inventorycommon.const import typePlex 21 from localization import GetByLabel 22 import uthread 23 from carbonui.uicore import uicore 24 from eve.client.script.ui.tooltips.tooltipUtil import SetTooltipHeaderAndDescription 25 from eveprefs import boot 26 from marketutil.feature_flags.client import is_global_plex_market_experiment_enabled 27 from player_messaging.client.ui_message import prompt_player_fsd_dialog 28 COL_GREEN = (0.3, 0.9, 0.1) 29 COL_RED = (1.0, 0.275, 0.0) 30 COL_WHITE = (1.0, 1.0, 1.0) 31 32 class SellBuyItemsWindow(Window): 33 __notifyevents__ = ['OnSessionChanged'] 34 default_width = 520 35 default_height = 390 36 default_minSize = (default_width, default_height) 37 default_windowID = 'SellBuyItemsWindow' 38 captionTextPath = 'UI/Inventory/ItemActions/MultiBuy' 39 scrollId = 'MultiBuyScroll' 40 tradeForCorpSettingConfig = 'buyUseCorp' 41 tradeTextPath = 'UI/Market/MarketQuote/CommandSell' 42 orderCap = 'MultiSellOrderCap' 43 tradeOnConfirm = True 44 corpCheckboxTop = 38 45 numbersGridTop = 6 46 dropLabelPath = 'UI/Market/Marketbase/DropItemsToAdd' 47 cannotBeTradeLabelPath = 'UI/Market/MarketQuote/CannotBeSold' 48 badDeltaWarningPath = 'UI/Market/MarketQuote/MultiBuyTypesAboveAverage' 49 salesTaxToolTipHeaderLabelPath = 'UI/Market/MarketQuote/SalesTaxTooltipHeader' 50 salesTaxToolTipDescriptionLabelPath = 'UI/Market/MarketQuote/SalesTaxTooltipDescription' 51 brokersFeeTooltipHeaderLabelPath = 'UI/Market/MarketQuote/BrokersFeeTooltipHeader' 52 brokersFeeTooltipDescriptionLabelPath = 'UI/Market/MarketQuote/BrokersFeeTooltipDescription' 53 importHintLabelPath = '' 54 exportHintLabelPath = '' 55 56 def ApplyAttributes(self, attributes): 57 Window.ApplyAttributes(self, attributes) 58 self.isReadOnly = MarketAccessControl().is_sell_items_read_only 59 self.marketQuoteSvc = sm.GetService('marketQuote') 60 self.InitializeVariables(attributes) 61 self.SetCaption(GetByLabel(self.captionTextPath)) 62 self.scope = uiconst.SCOPE_INGAME 63 self.mainCont = mainCont = Container(parent=self.sr.main, name='mainCont') 64 self.infoCont = Container(parent=mainCont, name='infoCont', align=uiconst.TOBOTTOM, height=92) 65 self.bottomLeft = Container(parent=self.infoCont, name='bottomLeft', align=uiconst.TOLEFT, width=250, state=uiconst.UI_PICKCHILDREN, uniqueUiName=UNIQUE_NAME_MARKET_ORDER_DURATION) 66 self.bottomRight = Container(parent=self.infoCont, name='bottomRight', align=uiconst.TORIGHT, width=250) 67 self.AddImportExportButtons() 68 self.dropCont = Container(name='dropCont', parent=mainCont, align=uiconst.TOTOP, state=uiconst.UI_NORMAL, height=32, padding=(32, 0, 32, 0)) 69 self.dropLabel = EveCaptionSmall(parent=self.dropCont, align=uiconst.CENTER, text=GetByLabel(self.dropLabelPath), color=TextColor.SECONDARY) 70 self.fakeItemsCont = Container(parent=self.dropCont, align=uiconst.TOALL, clipChildren=True) 71 self.locationCont = Container(parent=mainCont, name='locationCont', align=uiconst.TOTOP) 72 self.scrollCont = Container(parent=mainCont, name='scrollCont', padding=(0, 8, 0, 8)) 73 self.itemsScroll = ScrollContainer(parent=self.scrollCont, id=self.scrollId) 74 self.btnGroup = ButtonGroup(parent=self.sr.main, idx=0, line=False) 75 self.tradeButton = self.btnGroup.AddButton(GetByLabel(self.tradeTextPath), self.PerformTrade, isDefault=self.tradeOnConfirm, uiName='confirm_sell_button') 76 self.btnGroup.AddButton(GetByLabel('UI/Generic/Cancel'), self.Cancel, uiName='cancel_sell_button') 77 self.DrawNumbers() 78 corpAcctName = self._CanTradeForCorp() 79 if corpAcctName is not None: 80 self.DrawCheckBox(corpAcctName) 81 self.globalDragHover = uicore.event.RegisterForTriuiEvents(uiconst.UI_MOUSEHOVER, self.OnGlobalMouseHover) 82 83 def StartAddItemsThread(self): 84 if len(self.preItems): 85 self.addItemsThread = uthread.new(self.AddPreItems, self.preItems) 86 87 def InitializeVariables(self, attributes): 88 self.globalDragHover = None 89 self.cannotTradeItemList = [] 90 self.itemList = [] 91 self.preItems = attributes.preItems or [] 92 self.useCorp = None 93 self.hasDrawn = False 94 self.addItemsThread = None 95 self.baseStationID = None 96 97 def DrawNumbers(self): 98 pass 99 100 def SetupBrokersFeeTooltips(self): 101 SetTooltipHeaderAndDescription(self.brokersFee, GetByLabel(self.brokersFeeTooltipHeaderLabelPath), GetByLabel(self.brokersFeeTooltipDescriptionLabelPath)) 102 SetTooltipHeaderAndDescription(self.brokersFeeAmt, GetByLabel(self.brokersFeeTooltipHeaderLabelPath), GetByLabel(self.brokersFeeTooltipDescriptionLabelPath)) 103 104 def SetupSalesTaxTooltips(self): 105 SetTooltipHeaderAndDescription(self.salesTax, GetByLabel(self.salesTaxToolTipHeaderLabelPath), GetByLabel(self.salesTaxToolTipDescriptionLabelPath)) 106 SetTooltipHeaderAndDescription(self.salesTaxAmt, GetByLabel(self.salesTaxToolTipHeaderLabelPath), GetByLabel(self.salesTaxToolTipDescriptionLabelPath)) 107 108 def DrawCheckBox(self, corpAcctName): 109 useCorpWallet = settings.user.ui.Get(self.tradeForCorpSettingConfig, False) 110 top = self.corpCheckboxTop 111 self.useCorp = Checkbox(text=GetByLabel('UI/Market/MarketQuote/UseCorpAccount', accountName=corpAcctName), parent=self.bottomLeft, settingsKey='usecorp', checked=useCorpWallet, callback=self.OnUseCorp, pos=(0, 112 top, 113 350, 114 0), align=uiconst.TOPLEFT) 115 116 def AddImportExportButtons(self): 117 self._AddImportButton() 118 self._AddExportButton() 119 120 def _AddImportButton(self): 121 importMenu = UtilMenu(name='importMenu', menuAlign=uiconst.TOPLEFT, parent=self.mainCont, align=uiconst.TOPLEFT, pos=(0, 0, 32, 32), GetUtilMenu=self.GetImportMenu, texturePath='res:/UI/Texture/Shared/pasteFrom.png', iconSize=28, hint=GetByLabel(self.importHintLabelPath)) 122 123 def _AddExportButton(self): 124 exportMenu = UtilMenu(name='exportMenu', menuAlign=uiconst.TOPLEFT, parent=self.mainCont, align=uiconst.TOPRIGHT, pos=(4, 0, 28, 28), GetUtilMenu=self.GetExportMenu, texturePath='res:/UI/Texture/Shared/copyTo.png', iconSize=28, hint=GetByLabel(self.exportHintLabelPath)) 125 126 def _CanTradeForCorp(self): 127 if session.corprole & (corpRoleAccountant | corpRoleTrader): 128 corpAcctName = sm.GetService('corp').GetMyCorpAccountName() 129 if corpAcctName is not None: 130 return corpAcctName 131 132 def OnUseCorp(self, *args): 133 if self.useCorp.checked: 134 newValue = True 135 else: 136 newValue = False 137 settings.user.ui.Set(self.tradeForCorpSettingConfig, newValue) 138 self.UpdateNumbers() 139 140 def TradingForCorp(self): 141 if self.useCorp: 142 useCorp = self.useCorp.checked 143 else: 144 useCorp = False 145 return useCorp 146 147 def GetImportMenu(self, menuParent): 148 pass 149 150 def GetExportMenu(self, menuParent): 151 pass 152 153 def DropItems(self, dragObj, nodes): 154 pass 155 156 def PerformTrade(self, *args): 157 pass 158 159 def UpdateNumbers(self): 160 pass 161 162 def GetItems(self): 163 return self.itemList 164 165 def AddPreItems(self, preItems): 166 pass 167 168 def IsAllowedDragData(self, dragData): 169 return True 170 171 def DrawDraggedItems(self, dragData): 172 if not self.IsAllowedDragData(dragData): 173 return 174 self.hasDrawn = True 175 uicore.animations.FadeOut(self.dropLabel, duration=0.15) 176 noOfItems = len(dragData) 177 noOfAvailable = math.floor((self.width - 16 - self.dropCont.padLeft - self.dropCont.padRight) / 28) 178 for i, dragItem in enumerate(dragData): 179 c = Container(parent=self.fakeItemsCont, align=uiconst.TOLEFT, padding=2, width=24) 180 if noOfItems > noOfAvailable and i == noOfAvailable - 1: 181 icon = Sprite(parent=c, texturePath='res:/UI/Texture/classes/MultiSell/DotDotDot.png', state=uiconst.UI_DISABLED, width=24, height=24, align=uiconst.CENTER) 182 icon.SetAlpha(0.6) 183 return 184 typeID = self.GetTypeIDFromDragItem(dragItem) 185 icon = Icon(parent=c, typeID=typeID, state=uiconst.UI_DISABLED) 186 icon.SetSize(24, 24) 187 188 def GetTypeIDFromDragItem(self, dragItem): 189 getTypeID = dragItem.item.typeID 190 return getTypeID 191 192 def OnDropData(self, dragSource, dragData): 193 self.ClearDragData() 194 195 def ClearDragData(self): 196 self.fakeItemsCont.Flush() 197 uicore.animations.FadeIn(self.dropLabel, 0.6, duration=0.3) 198 self.hasDrawn = False 199 200 def OnGlobalMouseHover(self, *args, **kw): 201 shouldClearDragData = True 202 if uicore.IsDragging() and uicore.dragObject: 203 mo = uicore.uilib.mouseOver 204 if mo == self or mo.IsUnder(self): 205 shouldClearDragData = False 206 if not self.hasDrawn: 207 self.DrawDraggedItems(uicore.dragObject.dragData) 208 if shouldClearDragData: 209 self.ClearDragData() 210 return True 211 212 def Cancel(self, *args): 213 self.Close() 214 215 def Close(self, *args, **kwds): 216 Window.Close(self, *args, **kwds) 217 if self.addItemsThread: 218 self.addItemsThread.kill() 219 uicore.event.UnregisterForTriuiEvents(self.globalDragHover) 220 221 def CheckOrderAvailability(self, preItems): 222 availableOrders = int(sm.GetService('machoNet').GetGlobalConfig().get(self.orderCap, 100)) - len(self.itemList) 223 if len(preItems) > availableOrders: 224 prompt_player_fsd_dialog('CustomNotify', {'notify': GetByLabel('UI/Market/MarketQuote/TooManyItemsForOrder')}) 225 return preItems[:availableOrders] 226 return preItems 227 228 def RemoveItem(self, itemEntry): 229 self.itemsScroll._RemoveChild(itemEntry) 230 self.itemList.remove(itemEntry) 231 self.RemoveItemFromCollection(itemEntry) 232 self.UpdateNumbers() 233 self.UpdateHeaderCount() 234 235 def RemoveItemFromCollection(self, itemEntry): 236 pass 237 238 def DoAddItem(self, item): 239 itemEntry = self.GetItemEntry(item) 240 self.AddItemToCollection(item, itemEntry) 241 itemEntry.state = uiconst.UI_NORMAL 242 self.itemsScroll._InsertChild(0, itemEntry) 243 self.itemList.append(itemEntry) 244 self.UpdateNumbers() 245 self.UpdateHeaderCount() 246 return itemEntry 247 248 def UpdateHeaderCount(self): 249 if is_global_plex_market_experiment_enabled() and any((x.typeID == typePlex for x in self.itemList)): 250 self.SetCaption('%s (%i)' % (GetByLabel(self.captionTextPath), len(self.itemList))) 251 else: 252 self.SetCaption('%s (%i) - %s' % (GetByLabel(self.captionTextPath), len(self.itemList), self.GetStationLocationText())) 253 254 def GetStationLocationText(self): 255 if self.baseStationID is None: 256 return '' 257 stationLocation = cfg.evelocations.Get(self.baseStationID).locationName 258 return stationLocation 259 260 def DisplayErrorHints(self): 261 hintTextList = self.GetErrorHints() 262 if hintTextList: 263 hintText = '<br>'.join(hintTextList) 264 prompt_player_fsd_dialog('CustomNotify', {'notify': hintText}) 265 266 def GetErrorHints(self): 267 hintTextList = self.BuildHintTextList(self.cannotTradeItemList, self.cannotBeTradeLabelPath) 268 return hintTextList 269 270 def BuildHintTextList(self, itemList, labelPath): 271 hintTextList = [] 272 if len(itemList): 273 hintTextList.append(eveformat.bold(GetByLabel(labelPath))) 274 for item in itemList: 275 hintTextList.append(evelink.type_link(type_id=item.typeID)) 276 277 return hintTextList 278 279 def ClearErrorLists(self): 280 self.cannotTradeItemList = [] 281 282 def GetValidatedItem(self, item): 283 return None 284 285 def GetItemsIterator(self, onlyValid = False): 286 for item in self.GetItems(): 287 if not item: 288 continue 289 if onlyValid and not self.GetValidatedItem(item): 290 continue 291 yield item 292 293 def GetOrderDeltaTextForWarning(self): 294 return '' 295 296 def GetItemsWithBadDelta(self, args): 297 return [] 298 299 def ContinueAfterWarning(self, buyItemList): 300 highItems = self.GetItemsWithBadDelta(buyItemList) 301 orderText = self.GetOrderDeltaTextForWarning() 302 hightText = '' 303 if highItems: 304 highTextList = [GetByLabel(self.badDeltaWarningPath)] 305 highItems.sort(key=lambda x: x[0], reverse=True) 306 for perc, item in highItems: 307 percText = GetByLabel('UI/Common/Percentage', percentage=FmtAmt(perc * 100, showFraction=0)) 308 highTextList.append('- %s (%s)' % (evetypes.GetName(item.typeID), percText)) 309 310 hightText = '<br>'.join(highTextList) 311 if orderText or hightText: 312 warningTextList = [] 313 if orderText: 314 warningTextList.append(orderText) 315 warningTextList.append('') 316 if hightText: 317 warningTextList.append(hightText) 318 warningTextList.append('') 319 warningTextList.append(GetByLabel('UI/Market/MarketQuote/MultiBuyAboveAverageConfirmation')) 320 warningText = '<br>'.join(warningTextList) 321 headerLabel = GetByLabel('UI/Generic/Warning') 322 ret = prompt_player_fsd_dialog('CustomQuestion', {'header': headerLabel, 323 'question': warningText}, uiconst.YESNO, default=uiconst.ID_NO) 324 if ret != uiconst.ID_YES: 325 return False 326 return True 327 328 def AreExtraExportOptionsAvailable(self): 329 extraOptions = boot.region != 'optic' and session.languageID != 'EN' 330 return extraOptions