infoPanelJobBoard.py (9676B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\infoPanels\infoPanelJobBoard.py 2 import logging 3 import blue 4 import eveui 5 import eveicon 6 from eve.client.script.ui.shared.infoPanels.InfoPanelBase import InfoPanelBase 7 from eve.client.script.ui.shared.infoPanels.const.infoPanelConst import PANEL_JOB_BOARD, MODE_NORMAL 8 from carbonui.control.buttonIcon import ButtonIcon 9 import uthread2 10 from jobboard.client import get_job_board_service, job_board_signals 11 import localization 12 from clientsettings.setting import SessionSettingNumeric 13 import eve.client.script.ui.shared.pointerTool.pointerToolConst as pConst 14 logger = logging.getLogger('job_board') 15 SCROLL_CONTAINER_HEIGHT_MAX = 450 16 17 class InfoPanelJobBoard(InfoPanelBase): 18 default_name = 'InfoPanelJobBoard' 19 panelTypeID = PANEL_JOB_BOARD 20 hasSettings = False 21 uniqueUiName = pConst.UNIQUE_NAME_AGENT_MISSION_INFO_PANEL 22 label = 'UI/Opportunities/WindowTitle' 23 default_iconTexturePath = eveicon.opportunities_board 24 expandedJobSettingsName = 'expanded_job' 25 featureID = 'opportunities' 26 __notifyevents__ = InfoPanelBase.__notifyevents__ + ['OnExpandedMissionChanged'] 27 _scroll_fraction = SessionSettingNumeric(0, 0.0, 1.0) 28 29 @staticmethod 30 def IsAvailable(): 31 service = get_job_board_service() 32 if service is None: 33 return False 34 return service.is_available and bool(service.get_tracked_jobs()) 35 36 def __init__(self, **kwargs): 37 self._expanded_job_id = None 38 self._job_entries = {} 39 self._scroll_initialized = False 40 self._constructing = True 41 super(InfoPanelJobBoard, self).__init__(**kwargs) 42 self._layout() 43 self._refresh_entries() 44 self._update_content_container_scroll_position() 45 job_board_signals.on_job_state_changed.connect(self._on_job_state_changed) 46 job_board_signals.on_job_added.connect(self._on_job_added) 47 48 def Close(self): 49 for entry in self._job_entries.values(): 50 entry.Close() 51 52 self._job_entries.clear() 53 job_board_signals.on_job_state_changed.disconnect(self._on_job_state_changed) 54 job_board_signals.on_job_added.disconnect(self._on_job_added) 55 super(InfoPanelJobBoard, self).Close() 56 57 def ConstructNormal(self): 58 if self._constructing or self.destroyed: 59 return 60 self._debounced_refresh() 61 62 @property 63 def service(self): 64 return get_job_board_service() 65 66 def _on_tracked_jobs_changed(self): 67 if self.destroyed: 68 return 69 self._debounced_refresh() 70 71 @uthread2.debounce(0.1) 72 def _debounced_refresh(self): 73 if not self.destroyed: 74 self._refresh_entries() 75 76 def _on_job_state_changed(self, job): 77 if self.destroyed: 78 return 79 if job.job_id in self._job_entries: 80 self._job_entries[job.job_id].update_state() 81 82 def _on_job_added(self, job): 83 if self.destroyed: 84 return 85 if job.is_tracked and job.job_id not in self._job_entries: 86 self._debounced_refresh() 87 88 @eveui.skip_if_destroyed 89 def _refresh_entries(self): 90 jobs = self.service.get_tracked_jobs() 91 job_ids = [ job.job_id for job in jobs ] 92 previous_job_ids = [ job_id for job_id in self._job_entries.keys() ] 93 obsolete_job_ids = list(set(previous_job_ids) - set(job_ids)) 94 for job_id in obsolete_job_ids: 95 job_entry = self._job_entries[job_id] 96 job_entry.Close() 97 self._job_entries[job_id] = None 98 self._job_entries.pop(job_id) 99 100 for index, job in enumerate(jobs): 101 if job.job_id not in previous_job_ids: 102 self._construct_job_entry(job, index) 103 else: 104 self._job_entries[job.job_id].SetOrder(index) 105 106 if not self._job_entries: 107 self._save_expanded(-1) 108 else: 109 self._check_update_expanded() 110 self._update_content_container_height() 111 112 @eveui.skip_if_destroyed 113 def _construct_job_entry(self, job, index): 114 try: 115 entry = job.INFO_PANEL_ENTRY_CLASS(parent=self._content_container, job=job, padBottom=4, padTop=4, on_click=self._on_entry_clicked, idx=index, callback=self._update_content_container_height) 116 self._job_entries[job.job_id] = entry 117 except: 118 logger.exception('Failed to construct info panel entry %s', job.job_id) 119 120 def _layout(self): 121 self._constructing = True 122 self._title = eveui.EveCaptionSmall(name='title', parent=self.headerCont, align=eveui.Align.center_left, text=localization.GetByLabel(self.label)) 123 self._content_container = eveui.ScrollContainer(name='missions_scroll_container', parent=self.mainCont, align=eveui.Align.to_top, height=0) 124 self._content_container.OnScrolledVertical = self._on_scroll 125 self._constructing = False 126 127 def ConstructHeaderButton(self): 128 container = eveui.Container(parent=self.headerBtnCont, align=eveui.Align.center_right, width=28, height=28) 129 return ButtonIcon(parent=container, align=eveui.Align.center, iconSize=18, width=18, height=18, texturePath=self.default_iconTexturePath, func=self._open_job_board) 130 131 def _open_job_board(self, *args, **kwargs): 132 self.service.open_active_page() 133 134 def _on_entry_clicked(self, job_id): 135 if job_id == self._expanded_job_id: 136 self._expand_job(None, save=True) 137 else: 138 self._expand_job(job_id, save=True) 139 140 def _expand_job(self, job_id, save = False): 141 self._update_expanded_job_id_settings(job_id) 142 self._update_expanded_entries() 143 self._scroll_to_expanded() 144 if save: 145 self._save_expanded(job_id) 146 147 def _update_expanded_entries(self): 148 for job_id, entry in self._job_entries.items(): 149 if job_id == self._expanded_job_id: 150 try: 151 entry.expand() 152 except: 153 logger.exception('Failed to expand info panel entry %s', entry.name) 154 155 else: 156 entry.collapse() 157 158 def _scroll_to_expanded(self): 159 blue.synchro.Yield() 160 job_id = self._expanded_job_id 161 if not job_id or job_id not in self._job_entries: 162 return 163 self._content_container.ScrollToRevealChildVertical(self._job_entries[job_id]) 164 165 def OnStartModeChanged(self, oldMode): 166 if not oldMode: 167 return 168 self._check_update_expanded() 169 170 def OnExpandedMissionChanged(self, featureID = None, missionID = None): 171 if not featureID or featureID == self.featureID: 172 return 173 self._expanded_job_id = -1 174 self._update_expanded_entries() 175 if self._expanded_job_id != -1: 176 self._scroll_to_expanded() 177 178 def _get_expanded_job_id_from_settings(self): 179 return settings.char.ui.Get(self.expandedJobSettingsName, self._get_default_expanded_job_id()) 180 181 def _get_default_expanded_job_id(self): 182 jobs = self.service.get_tracked_jobs() 183 for job in jobs: 184 if job.job_id in self._job_entries: 185 return job.job_id 186 187 def _update_expanded_job_id_settings(self, job_id): 188 settings.char.ui.Set(self.expandedJobSettingsName, job_id) 189 self._expanded_job_id = job_id 190 191 def _check_update_expanded(self): 192 if self.mode == MODE_NORMAL: 193 expanded_mission = sm.GetService('infoPanel').GetExpandedMission() 194 expanded_id = None 195 save = True 196 if not expanded_mission or expanded_mission['missionID'] == -1: 197 expanded_id = self._get_expanded_job_id_from_settings() 198 if expanded_id in (None, -1) or expanded_id not in self._job_entries: 199 expanded_id = self._get_default_expanded_job_id() 200 elif expanded_mission['featureID'] == self.featureID: 201 expanded_id = expanded_mission['missionID'] 202 save = settings.char.ui.Get(self.expandedJobSettingsName) != expanded_id 203 if expanded_id is not None: 204 self._expand_job(expanded_id, save=save) 205 else: 206 self._save_expanded(-1) 207 208 def _save_expanded(self, expanded_id): 209 if expanded_id == -1: 210 expanded_mission = sm.GetService('infoPanel').GetExpandedMission() 211 if expanded_mission.get('featureID') != self.featureID: 212 return 213 sm.GetService('infoPanel').SetExpandedMission(self.featureID, expanded_id) 214 215 def _update_content_container_height(self): 216 if not self._content_container or self._content_container.destroyed: 217 return 218 totalHeight = self._content_container.mainCont.height 219 self._content_container.height = min(totalHeight, SCROLL_CONTAINER_HEIGHT_MAX) 220 self._content_container.clipCont.clipChildren = totalHeight > SCROLL_CONTAINER_HEIGHT_MAX 221 222 def _update_content_container_scroll_position(self): 223 blue.synchro.Yield() 224 if not self._content_container or self._content_container.destroyed: 225 return 226 self._scroll_initialized = True 227 self._content_container.ScrollToVertical(self._scroll_fraction.get()) 228 229 def _on_scroll(self, pos_fraction): 230 if self._scroll_initialized: 231 self._scroll_fraction.set(self._content_container.GetPositionVertical()) 232 233 def get_visible_jobs(self, job_ids): 234 visible_job_ids = [ entry.name for entry in self._job_entries.values() if entry.name in job_ids and self._content_container.IsChildVisible(entry) ] 235 return visible_job_ids