infoPanelAchievement.py (20177B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\infoPanels\infoPanelAchievement.py 2 import eveicon 3 import threadutils 4 from achievement_system.client.api.error import DefinitionNotFoundError 5 from achievement_system.client.api.repository import get_repository 6 from achievement_system.client.api.signal import on_achievement_tracked, on_achievement_untracked, on_achievement_progressed, on_achievement_completed, on_achievement_milestone_reached, on_admin_achievement_reset, on_admin_achievement_reset_all, on_achievement_milestone_reward_claimed 7 from achievement_system.client.model.definition.achievement.entry import AchievementDefinitionEntry 8 from achievement_system.client.ui.controller.achievement_entry import AchievementEntryController 9 from achievement_system.client.ui.window.const import TRANSITION_DURATION 10 from achievement_system.client.ui.window.window import AchievementsWindow 11 from carbon.common.script.util.format import FmtAmt 12 from carbonui import Align, ButtonFrameType, Density, TextColor, uiconst, PickState, ButtonStyle 13 from carbonui.button.menu import MenuButtonIcon 14 from carbonui.control.button import Button 15 from carbonui.control.contextMenu.menuData import MenuData 16 from carbonui.primitives.container import Container 17 from carbonui.primitives.containerAutoSize import ContainerAutoSize 18 from carbonui.primitives.fill import Fill 19 from carbonui.primitives.gridcontainer import GridContainer 20 from carbonui.primitives.sprite import Sprite 21 from carbonui.text.styles import TextBody, TextDetail 22 from carbonui.uianimations import animations 23 from carbonui.uiconst import OutputMode 24 from eve.client.script.ui import eveColor 25 from eve.client.script.ui.control.eveLabel import EveLabelLarge 26 from eve.client.script.ui.control.gauge import Gauge 27 from eve.client.script.ui.shared.infoPanels.InfoPanelBase import InfoPanelBase 28 from eve.client.script.ui.shared.infoPanels.const import infoPanelConst, infoPanelUIConst 29 from localization import GetByLabel 30 from signals import Signal 31 from uihider import UiHiderMixin 32 from uihighlighting.uniqueNameConst import UNIQUE_NAME_ACHIEVEMENT_INFO_PANEL 33 on_infopanel_achievement_expanded = Signal('on_infopanel_achievement_expanded') 34 35 class InfoPanelAchievement(UiHiderMixin, InfoPanelBase): 36 __guid__ = 'uicls.InfoPanelAchievement' 37 default_name = 'InfoPanelAchievement' 38 uniqueUiName = UNIQUE_NAME_ACHIEVEMENT_INFO_PANEL 39 panelTypeID = infoPanelConst.PANEL_ACHIEVEMENT 40 label = 'UI/Achievements/Window/Title' 41 default_iconTexturePath = 'res:/UI/Texture/WindowIcons/achievements.png' 42 default_mode = infoPanelConst.MODE_NORMAL 43 44 def ApplyAttributes(self, attributes): 45 super(InfoPanelAchievement, self).ApplyAttributes(attributes) 46 self.construct_layout() 47 self.connect_signals() 48 49 def Close(self): 50 try: 51 self.disconnect_signals() 52 finally: 53 super(InfoPanelAchievement, self).Close() 54 55 def connect_signals(self): 56 on_achievement_tracked.connect(self.on_achievement_tracked) 57 58 def disconnect_signals(self): 59 on_achievement_tracked.disconnect(self.on_achievement_tracked) 60 61 def construct_layout(self): 62 self.mainCont.padTop = 4 63 self.headerCls(name='header_label', parent=self.headerCont, align=uiconst.CENTERLEFT, text=GetByLabel('UI/Achievements/Window/Title')) 64 tracked_achievement_ids = get_repository().activity.get_tracked_achievements() 65 auto_expand = len(tracked_achievement_ids) == 1 66 for achievement_id in tracked_achievement_ids: 67 self.add_achievement(achievement_id, auto_expand) 68 69 @staticmethod 70 def IsAvailable(): 71 return get_repository().activity.has_tracked_achievements() 72 73 def ConstructHeaderButton(self): 74 button = self.ConstructSimpleHeaderButton() 75 button.OnClick = self.on_header_button_click 76 77 def add_achievement(self, achievement_id, auto_expand = False): 78 controller = self.get_achievement_entry_controller(achievement_id) 79 if controller is None: 80 return 81 TrackedAchievement(name='tracked_achievement', parent=self.mainCont, align=Align.TOTOP, controller=controller, auto_expand=auto_expand, padBottom=8) 82 83 def get_achievement_entry_controller(self, achievement_id): 84 if achievement_id is None: 85 return 86 try: 87 achievement_attributes = get_repository().definitions.get_achievement(achievement_id) 88 except DefinitionNotFoundError: 89 return 90 91 achievement_entry = AchievementDefinitionEntry(achievement_id, achievement_attributes) 92 return AchievementEntryController(achievement_entry) 93 94 def on_header_button_click(self, *args): 95 wnd = AchievementsWindow.GetIfOpen() 96 if wnd and not wnd.destroyed: 97 wnd.Maximize() 98 else: 99 AchievementsWindow.Open() 100 101 def on_achievement_tracked(self, achievement_id): 102 self.add_achievement(achievement_id, auto_expand=True) 103 104 105 class TrackedAchievement(ContainerAutoSize): 106 107 def __init__(self, controller, auto_expand = False, *args, **kwargs): 108 super(TrackedAchievement, self).__init__(*args, **kwargs) 109 self.controller = controller 110 self.auto_expand = auto_expand 111 self.is_expanded = False 112 self.construct_layout() 113 self.update(animate=False) 114 self.connect_signals() 115 116 def Close(self): 117 try: 118 self.disconnect_signals() 119 finally: 120 super(TrackedAchievement, self).Close() 121 122 def connect_signals(self): 123 on_achievement_progressed.connect(self.on_achievement_progressed) 124 on_admin_achievement_reset.connect(self.on_reset) 125 on_admin_achievement_reset_all.connect(self.on_reset_all) 126 on_achievement_completed.connect(self.on_achievement_completed) 127 on_achievement_milestone_reached.connect(self.on_milestone_reached) 128 on_achievement_milestone_reward_claimed.connect(self.on_achievement_milestone_reward_claimed) 129 on_achievement_untracked.connect(self.on_achievement_untracked) 130 on_infopanel_achievement_expanded.connect(self.on_infopanel_achievement_expanded) 131 self.on_size_changed.connect(self.on_size_changed_signal) 132 133 def disconnect_signals(self): 134 on_achievement_progressed.disconnect(self.on_achievement_progressed) 135 on_admin_achievement_reset.disconnect(self.on_reset) 136 on_admin_achievement_reset_all.disconnect(self.on_reset_all) 137 on_achievement_completed.disconnect(self.on_achievement_completed) 138 on_achievement_milestone_reached.disconnect(self.on_milestone_reached) 139 on_achievement_milestone_reward_claimed.disconnect(self.on_achievement_milestone_reward_claimed) 140 on_achievement_untracked.disconnect(self.on_achievement_untracked) 141 on_infopanel_achievement_expanded.disconnect(self.on_infopanel_achievement_expanded) 142 self.on_size_changed.disconnect(self.on_size_changed_signal) 143 144 def construct_layout(self): 145 self.content_container = ContainerAutoSize(name='content_container', parent=self, align=uiconst.TOTOP, alignMode=Align.TOTOP) 146 self.construct_header() 147 self.construct_details() 148 149 def construct_header(self): 150 self.header_container = Container(name='header_container', parent=self.content_container, align=Align.TOTOP) 151 Fill(bgParent=self.header_container, color=eveColor.BLACK, opacity=0.35) 152 header_contents = Container(name='header_contents', parent=self.header_container, padding=(8, 0, 8, 0)) 153 header_icon_container = Container(name='header_icon_container', parent=header_contents, align=Align.TOLEFT, width=16) 154 self.header_icon = Sprite(name='header_icon', parent=header_icon_container, align=Align.CENTER, color=eveColor.WHITE, outputMode=OutputMode.COLOR_AND_GLOW, glowBrightness=0.0, opacity=0.75, hint=GetByLabel('UI/Achievements/ViewCategory'), pos=(0, 0, 16, 16)) 155 self.header_icon.OnClick = self.on_header_icon_click 156 self.header_icon.OnMouseEnter = self.on_header_icon_enter 157 self.header_icon.OnMouseExit = self.on_header_icon_exit 158 self.menu_container = Container(name='menu_container', parent=header_contents, align=Align.TORIGHT, clipChildren=True, width=0) 159 MenuButtonIcon(name='menu_button_icon', parent=self.menu_container, align=Align.CENTERRIGHT, get_menu_func=self.get_options_menu, hint=None, width=16) 160 self.header_label_container = Container(name='header_label_container', parent=header_contents, align=Align.VERTICALLY_CENTERED, padLeft=8) 161 self.header_progress_label = EveLabelLarge(name='header_progress_label', parent=self.header_label_container, align=Align.TORIGHT, state=uiconst.UI_NORMAL, padLeft=8) 162 self.header_progress_label.OnClick = self.on_header_clicked 163 self.header_name_label = EveLabelLarge(name='header_name_label', parent=self.header_label_container, align=Align.VERTICALLY_CENTERED, color=TextColor.HIGHLIGHT, maxLines=1, showEllipsis=True) 164 header_interaction_container = Container(name='header_interaction_container', parent=self.header_container, state=uiconst.UI_NORMAL) 165 header_interaction_container.OnClick = self.on_header_clicked 166 167 def construct_details(self): 168 self.details_container = Container(name='details_container', parent=self.content_container, align=Align.TOTOP, clipChildren=True, height=0) 169 Fill(bgParent=self.details_container, color=eveColor.BLACK, opacity=0.25) 170 self.details_contents = ContainerAutoSize(name='details_contents', parent=self.details_container, align=Align.TOTOP, padding=(8, 4, 8, 0)) 171 self.description_label = TextBody(parent=self.details_contents, name='description_label', align=Align.TOTOP) 172 if self.controller.has_multiple_milestones: 173 self.milestones = Milestones(name='milestones', parent=self.details_contents, align=Align.TOTOP, controller=self.controller, padTop=8) 174 self.progress = Progress(name='progress', parent=self.details_contents, align=Align.TOTOP, controller=self.controller, padTop=8) 175 self.construct_claim_button() 176 177 def construct_claim_button(self): 178 self.claim_button = ClaimButton(parent=self.details_contents, name='claim_button', align=Align.TOTOP, padTop=16, display=False) 179 180 @threadutils.highlander_threaded 181 def update(self, animate = True): 182 self.update_header() 183 self.update_details(animate) 184 185 def update_header(self): 186 name_text = self.controller.name 187 _, header_text_height = EveLabelLarge.MeasureTextSize(name_text) 188 self.header_label_container.height = header_text_height 189 self.header_container.height = header_text_height + 16 190 self.header_icon.texturePath = self.controller.category_icon 191 self.header_name_label.text = name_text 192 self.header_progress_label.text = self.controller.progress_score_text_for_current_milestone 193 self.header_progress_label.hint = self.controller.progress_score_hint_for_current_milestone 194 self.header_progress_label.display = not self.is_expanded 195 196 def update_details(self, animate): 197 self.description_label.text = self.controller.description 198 if self.controller.has_multiple_milestones: 199 self.milestones.update() 200 self.progress.update() 201 self.claim_button.display = self.controller.is_completed and self.controller.has_unclaimed_rewards 202 if animate: 203 self.animate_details_container() 204 else: 205 self.details_container.height = self.details_target_height 206 207 def animate_details_container(self): 208 animations.MorphScalar(obj=self.details_container, attrName='height', startVal=self.details_container.height, endVal=self.details_target_height, duration=TRANSITION_DURATION) 209 210 @property 211 def details_target_height(self): 212 if not self.is_expanded: 213 return 0 214 measure_width = infoPanelUIConst.PANELWIDTH - infoPanelUIConst.LEFTPAD - 16 215 _, text_height = TextBody.MeasureTextSize(self.controller.description, width=measure_width) 216 if self.controller.is_completed and self.controller.has_unclaimed_rewards: 217 text_height += self.claim_button.height + self.claim_button.padTop 218 if self.controller.has_multiple_milestones: 219 text_height += self.milestones.height + self.milestones.padTop 220 return text_height + 12 + self.progress.height + self.progress.padTop 221 222 def get_options_menu(self): 223 data = MenuData() 224 data.AddEntry(text=GetByLabel('UI/Achievements/ViewDetails'), func=self.on_menu_view_details) 225 data.AddEntry(text=GetByLabel('UI/Common/Untrack'), func=self.on_menu_untrack, texturePath=eveicon.camera_untrack) 226 return data 227 228 def on_menu_view_details(self, *args): 229 AchievementsWindow.open_achievement(self.controller.achievement_entry.identifier) 230 wnd = AchievementsWindow.GetIfOpen() 231 if wnd: 232 wnd.Maximize() 233 234 def on_menu_untrack(self, *args): 235 self.controller.untrack() 236 237 def on_size_changed_signal(self, width, height): 238 if not self.auto_expand: 239 return 240 self.auto_expand = False 241 self.on_header_clicked() 242 243 def on_header_clicked(self, *args): 244 self.is_expanded = not self.is_expanded 245 self.update() 246 if self.is_expanded: 247 on_infopanel_achievement_expanded(self.controller.achievement_entry.identifier) 248 249 def on_header_icon_click(self, *args): 250 AchievementsWindow.open_category(self.controller.achievement_entry.attributes.parent_category) 251 252 def on_header_icon_enter(self, *args): 253 animations.MorphScalar(obj=self.header_icon, attrName='glowBrightness', startVal=self.header_icon.glowBrightness, endVal=0.3, duration=TRANSITION_DURATION * 0.5) 254 255 def on_header_icon_exit(self, *args): 256 animations.MorphScalar(obj=self.header_icon, attrName='glowBrightness', startVal=self.header_icon.glowBrightness, endVal=0.0, duration=TRANSITION_DURATION * 0.5) 257 258 def on_achievement_progressed(self, achievement_id, achievement_state): 259 if achievement_id == self.controller.achievement_entry.identifier: 260 self.update() 261 262 def on_achievement_completed(self, achievement_id): 263 if achievement_id == self.controller.achievement_entry.identifier: 264 self.update() 265 266 def on_milestone_reached(self, achievement_id, milestone_id): 267 if achievement_id == self.controller.achievement_entry.identifier: 268 self.update() 269 270 def on_reset(self, achievement_id): 271 if achievement_id == self.controller.achievement_entry.identifier: 272 self.update() 273 274 def on_reset_all(self): 275 self.update() 276 277 def on_untrack_button_clicked(self, *args): 278 self.controller.untrack() 279 280 def on_achievement_milestone_reward_claimed(self, achievement_id, milestone_id): 281 if achievement_id == self.controller.achievement_entry.identifier: 282 if self.controller.is_completed and not self.controller.has_unclaimed_rewards: 283 self.controller.untrack() 284 285 def on_achievement_untracked(self, achievement_id): 286 if achievement_id == self.controller.achievement_entry.identifier: 287 self.Close() 288 289 def on_infopanel_achievement_expanded(self, achievement_id): 290 if achievement_id != self.controller.achievement_entry.identifier: 291 self.is_expanded = False 292 self.update() 293 294 def OnMouseEnter(self, *args): 295 animations.MorphScalar(obj=self.menu_container, attrName='width', startVal=self.menu_container.width, endVal=20, duration=TRANSITION_DURATION * 0.5) 296 297 def OnMouseExit(self, *args): 298 animations.MorphScalar(obj=self.menu_container, attrName='width', startVal=self.menu_container.width, endVal=0, duration=TRANSITION_DURATION * 0.5) 299 300 def OnGlobalFontSizeChanged(self): 301 super(TrackedAchievement, self).OnGlobalFontSizeChanged() 302 self.update() 303 304 305 class Milestones(ContainerAutoSize): 306 default_alignMode = Align.TOTOP 307 308 def __init__(self, controller, *args, **kwargs): 309 super(Milestones, self).__init__(*args, **kwargs) 310 self.controller = controller 311 self.construct_layout() 312 313 def construct_layout(self): 314 label_container = ContainerAutoSize(name='label_container', parent=self, align=Align.TOTOP, alignMode=Align.TOTOP) 315 self.progress_label = TextDetail(name='progress_label', parent=label_container, align=Align.TORIGHT, padLeft=8) 316 TextDetail(name='title_label', parent=label_container, align=Align.TOTOP, text=GetByLabel('UI/Achievements/Window/Card/CurrentMilestone')) 317 self.marker_container = GridContainer(name='marker_container', parent=self, align=uiconst.TOTOP, height=4, contentSpacing=(4, 4), padTop=4) 318 319 def construct_markers(self): 320 self.marker_container.Flush() 321 total_milestones = self.controller.total_milestones 322 if total_milestones == 0: 323 return 324 self.marker_container.columns = min(total_milestones, 5) 325 for index in range(0, self.controller.total_milestones): 326 is_completed = index < self.controller.completed_milestones 327 is_current = index == self.controller.current_milestone_index 328 if is_completed: 329 color = eveColor.SUCCESS_GREEN 330 elif is_current: 331 color = eveColor.FOCUS_BLUE 332 else: 333 color = eveColor.WHITE 334 if is_completed or is_current: 335 opacity = 1.0 336 glow_brightness = 0.5 337 else: 338 opacity = 0.2 339 glow_brightness = 0.0 340 Fill(parent=self.marker_container, color=color, outputMode=OutputMode.COLOR_AND_GLOW, glowBrightness=glow_brightness, opacity=opacity) 341 342 @threadutils.highlander_threaded 343 def update(self): 344 self.progress_label.text = '(%s/%s)' % (self.controller.current_milestone_index + 1, self.controller.total_milestones) 345 self.construct_markers() 346 347 348 class Progress(ContainerAutoSize): 349 default_alignMode = Align.TOTOP 350 351 def __init__(self, controller, *args, **kwargs): 352 super(Progress, self).__init__(*args, **kwargs) 353 self.controller = controller 354 self.construct_layout() 355 356 def construct_layout(self): 357 label_container = ContainerAutoSize(name='label_container', parent=self, align=Align.TOTOP, alignMode=Align.TOTOP) 358 self.progress_label = TextDetail(name='progress_label', parent=label_container, align=Align.TORIGHT, state=uiconst.UI_NORMAL, padLeft=8) 359 TextDetail(name='title_label', parent=label_container, align=Align.TOTOP, text=GetByLabel('UI/Achievements/Progress')) 360 self.progress_bar = Gauge(name='progress_bar', parent=self, align=Align.TOTOP, gaugeHeight=4, padTop=4) 361 362 @threadutils.highlander_threaded 363 def update(self): 364 progress = self.controller.progress 365 target = self.controller.target_for_milestone_index(self.controller.current_milestone_index) 366 if target <= 100000: 367 progress_text = FmtAmt(progress) 368 target_text = FmtAmt(target) 369 else: 370 progress_text = FmtAmt(progress, fmt='sn') 371 target_text = FmtAmt(target, fmt='sn') 372 self.progress_label.hint = self.controller.progress_score_hint_for_current_milestone 373 self.progress_label.text = '%s/%s' % (progress_text, target_text) 374 self.progress_bar.SetColor(self.controller.progress_bar_color) 375 self.progress_bar.SetValue(self.controller.percent_progress_towards_current_milestone) 376 377 378 class ClaimButton(Button): 379 default_pickState = PickState.ON 380 default_label = GetByLabel('UI/Achievements/Window/Rewards/ClaimRewards') 381 default_density = Density.COMPACT 382 default_style = ButtonStyle.SUCCESS 383 default_frame_type = ButtonFrameType.CUT_BOTTOM_LEFT_RIGHT 384 385 def __init__(self, *args, **kwargs): 386 super(ClaimButton, self).__init__(*args, **kwargs) 387 self.func = self.on_claim_rewards_clicked 388 389 def on_claim_rewards_clicked(self, *args): 390 AchievementsWindow.open_unclaimed_rewards()