patternSlots.py (13202B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\cosmetics\ship\pages\studio\patternSlots.py 2 import eveicon 3 from carbonui import Align, PickState 4 from carbonui.control.contextMenu.menuData import MenuData 5 from carbonui.primitives.container import Container 6 from clientsettings.setting import SessionSettingEnum 7 from carbonui.uianimations import animations 8 from cosmetics.client.ships.skins.live_data import current_skin_design, current_skin_design_signals 9 from cosmetics.common.ships.skins.static_data.pattern_attribute import PatternAttribute 10 from cosmetics.common.ships.skins.static_data.pattern_blend_mode import PatternBlendMode, NO_SECONDARY_COLOR_BLEND_MODES 11 from cosmetics.common.ships.skins.static_data.slot import SlotsDataLoader 12 from cosmetics.common.ships.skins.static_data.slot_name import SlotID, PATTERN_RELATED_SLOT_IDS 13 from eve.client.script.ui.cosmetics.ship.pages.studio import studioUtil 14 from eve.client.script.ui.cosmetics.ship.pages.studio.areaToggleButtonMenuIcon import AreaToggleButtonMenuIcon 15 from eve.client.script.ui.cosmetics.ship.pages.studio.circularButtonIcon import CircularButtonIcon, CircularMenuButtonIcon 16 from eve.client.script.ui.cosmetics.ship.pages.studio.cosmeticSlot import PatternCosmeticSlot 17 from localization import GetByLabel 18 SLOT_LEFT = 100 19 SLOT_TOP = 66 20 MATERIAL_OFFSET = 64 21 SLOT_LEFT_TOP_BY_ID = {SlotID.SECONDARY_PATTERN: (-SLOT_LEFT, -SLOT_TOP), 22 SlotID.SECONDARY_PATTERN_MATERIAL: (-SLOT_LEFT + MATERIAL_OFFSET, -SLOT_TOP - MATERIAL_OFFSET), 23 SlotID.PATTERN: (-SLOT_LEFT, SLOT_TOP), 24 SlotID.PATTERN_MATERIAL: (-SLOT_LEFT + MATERIAL_OFFSET, SLOT_TOP + MATERIAL_OFFSET)} 25 26 class PatternSlots(Container): 27 default_width = 360 28 default_height = 400 29 30 def __init__(self, *args, **kwargs): 31 super(PatternSlots, self).__init__(*args, **kwargs) 32 self.slots_by_id = {} 33 self.construct_layout() 34 self.update() 35 self.connect_signals() 36 37 def Close(self): 38 try: 39 self.disconnect_signals() 40 finally: 41 super(PatternSlots, self).Close() 42 43 def connect_signals(self): 44 current_skin_design_signals.on_slot_fitting_changed.connect(self.on_slot_fitting_changed) 45 current_skin_design_signals.on_slot_selected.connect(self.on_slot_selected) 46 current_skin_design_signals.on_pattern_blend_mode_changed.connect(self.on_pattern_blend_mode_changed) 47 current_skin_design_signals.on_component_attribute_changed.connect(self.on_component_attribute_changed) 48 49 def disconnect_signals(self): 50 current_skin_design_signals.on_slot_fitting_changed.disconnect(self.on_slot_fitting_changed) 51 current_skin_design_signals.on_slot_selected.disconnect(self.on_slot_selected) 52 current_skin_design_signals.on_pattern_blend_mode_changed.disconnect(self.on_pattern_blend_mode_changed) 53 current_skin_design_signals.on_component_attribute_changed.disconnect(self.on_component_attribute_changed) 54 55 def on_component_attribute_changed(self, slot_id, attribute_id, value): 56 if attribute_id == PatternAttribute.MIRROR: 57 self.update_mirror_toggle_buttons() 58 59 def on_pattern_blend_mode_changed(self, blend_mode): 60 self.update_slots() 61 62 def construct_layout(self): 63 self.construct_mirror_toggle_buttons() 64 self.construct_area_toggle_buttons() 65 self.reconstruct_slots() 66 self.construct_switch_pattern_button() 67 self.construct_blendmode_button() 68 69 def construct_mirror_toggle_buttons(self): 70 self.primary_mirror_toggle_button = MirrorToggleButtonIcon(parent=self, align=Align.CENTER, left=-161, top=88, display=False, pickState=PickState.ON) 71 self.secondary_mirror_toggle_button = MirrorSecondaryToggleButtonIcon(parent=self, align=Align.CENTER, left=-161, top=-88, display=False, pickState=PickState.ON) 72 73 def construct_area_toggle_buttons(self): 74 self.primary_area_toggle_button = AreaToggleButtonMenuIcon(parent=self, align=Align.CENTER, left=-161, top=46, slot_id=SlotID.PATTERN, display=False, pickState=PickState.ON) 75 self.secondary_area_toggle_button = AreaToggleButtonMenuIcon(parent=self, align=Align.CENTER, left=-161, top=-46, slot_id=SlotID.SECONDARY_PATTERN, display=False, pickState=PickState.ON) 76 77 def reconstruct_slots(self): 78 for slot in self.slots_by_id.values(): 79 slot.Close() 80 81 self.slots_by_id.clear() 82 for slot_id in current_skin_design.get().slot_layout.slots: 83 if slot_id not in PATTERN_RELATED_SLOT_IDS: 84 continue 85 slot_data = SlotsDataLoader.get_slot_data(slot_id) 86 is_pattern = slot_data.unique_id in (SlotID.PATTERN, SlotID.SECONDARY_PATTERN) 87 self.slots_by_id[slot_data.unique_id] = PatternCosmeticSlot(name='slot_{name}'.format(name=slot_data.internal_name), parent=self, slot_data=slot_data, opacity=0.0, license_selector_align=Align.CENTERRIGHT if is_pattern else Align.CENTERLEFT) 88 89 def construct_switch_pattern_button(self): 90 self.switch_pattern_button = SwitchPatternButtonIcon(name='switch_pattern_button', parent=self, pickState=PickState.OFF, align=Align.CENTER, opacity=0.0, func=self.on_switch_pattern_button, left=-100) 91 92 def construct_blendmode_button(self): 93 self.blendmode_button = BlendModeButton(name='blendmode_button', parent=self, pickState=PickState.OFF, align=Align.CENTER, opacity=0.0, left=-50) 94 95 def update(self): 96 self.update_slots() 97 self.update_blend_and_switch_buttons() 98 self.update_primary_buttons() 99 self.update_secondary_buttons() 100 101 def update_primary_buttons(self): 102 show_primary_buttons = self.has_primary_pattern and current_skin_design.get_selected_slot_id() in (SlotID.PATTERN, SlotID.PATTERN_MATERIAL) 103 self.primary_mirror_toggle_button.display = show_primary_buttons 104 self.primary_area_toggle_button.display = show_primary_buttons 105 self.primary_area_toggle_button.update_selected() 106 107 def update_secondary_buttons(self): 108 show_secondary_buttons = self.has_secondary_pattern and current_skin_design.get_selected_slot_id() in (SlotID.SECONDARY_PATTERN, SlotID.SECONDARY_PATTERN_MATERIAL) 109 self.secondary_mirror_toggle_button.display = show_secondary_buttons 110 self.secondary_area_toggle_button.display = show_secondary_buttons 111 self.secondary_area_toggle_button.update_selected() 112 113 def update_slots(self): 114 for slot_id, slot in self.slots_by_id.items(): 115 if self.should_display_slot(slot_id): 116 slot.show() 117 animations.MoveTo(obj=slot, startPos=(slot.left, slot.top), endPos=self.get_slot_left_top(slot_id), duration=0.25) 118 else: 119 slot.hide() 120 121 self.update_mirror_toggle_buttons() 122 123 def update_mirror_toggle_buttons(self): 124 component_instance = current_skin_design.get().get_fitted_component_instance(SlotID.PATTERN) 125 if component_instance: 126 if component_instance.mirrored: 127 self.primary_mirror_toggle_button.SetSelected() 128 else: 129 self.primary_mirror_toggle_button.SetDeselected() 130 component_instance = current_skin_design.get().get_fitted_component_instance(SlotID.SECONDARY_PATTERN) 131 if component_instance: 132 if component_instance.mirrored: 133 self.secondary_mirror_toggle_button.SetSelected() 134 else: 135 self.secondary_mirror_toggle_button.SetDeselected() 136 137 def update_blend_and_switch_buttons(self): 138 for button in (self.blendmode_button, self.switch_pattern_button): 139 if self.has_two_patterns: 140 button.pickState = PickState.ON 141 button.Enable() 142 else: 143 button.pickState = PickState.OFF 144 button.Disable() 145 target_opacity = 1.0 if self.has_primary_pattern else 0.0 146 animations.FadeTo(button, button.opacity, target_opacity, duration=0.25) 147 148 def populate_from_design(self): 149 for slot_id in self.slots_by_id.keys(): 150 component_instance = current_skin_design.get().slot_layout.fitted_slots.get(slot_id, None) 151 self.slots_by_id[slot_id].on_slot_fitting_changed(slot_id, component_instance) 152 153 self.update() 154 155 def update_radial_position(self, radius): 156 self.left, self.top = studioUtil.get_radial_position(radius, 0) 157 158 def on_switch_pattern_button(self, *args): 159 pass 160 161 def on_slot_fitting_changed(self, slot_id, component_instance): 162 self.update() 163 self.blendmode_button.update_selected() 164 165 def on_slot_selected(self, slot_id): 166 self.update_primary_buttons() 167 self.update_secondary_buttons() 168 169 def get_slot_left_top(self, slot_id): 170 if not self.has_primary_pattern: 171 return (-50, 0) 172 else: 173 return SLOT_LEFT_TOP_BY_ID[slot_id] 174 175 def should_display_slot(self, slot_id): 176 if slot_id == SlotID.PATTERN: 177 return True 178 if slot_id == SlotID.SECONDARY_PATTERN_MATERIAL: 179 if current_skin_design.get().slot_layout.pattern_blend_mode in NO_SECONDARY_COLOR_BLEND_MODES: 180 return False 181 else: 182 return self.has_secondary_pattern 183 else: 184 return self.has_primary_pattern 185 186 def is_slot_fitted(self, slot_id): 187 return current_skin_design.get().get_fitted_component_instance(slot_id) is not None 188 189 @property 190 def has_primary_pattern(self): 191 return self.is_slot_fitted(SlotID.PATTERN) 192 193 @property 194 def has_secondary_pattern(self): 195 return self.is_slot_fitted(SlotID.SECONDARY_PATTERN) 196 197 @property 198 def has_two_patterns(self): 199 return self.has_primary_pattern and self.has_secondary_pattern 200 201 202 class BlendModeButton(CircularMenuButtonIcon): 203 default_texturePath = eveicon.blend_modes 204 default_hint = GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/BlendModes') 205 206 def __init__(self, **kwargs): 207 super(BlendModeButton, self).__init__(**kwargs) 208 self.update_selected() 209 210 def on_blend_mode_setting_changed(self, value): 211 current_skin_design.get().slot_layout.pattern_blend_mode = value 212 self.update_selected() 213 current_skin_design.add_to_undo_history() 214 215 def update_selected(self): 216 if not self.enabled or current_skin_design.get().slot_layout.pattern_blend_mode == PatternBlendMode.OVERLAY: 217 self.SetDeselected() 218 else: 219 self.SetSelected() 220 221 def Enable(self): 222 super(BlendModeButton, self).Enable() 223 self.update_selected() 224 225 def Disable(self): 226 super(BlendModeButton, self).Disable() 227 self.update_selected() 228 229 def GetMenu(self): 230 pattern_blend_mode_setting = SessionSettingEnum(current_skin_design.get().slot_layout.pattern_blend_mode) 231 pattern_blend_mode_setting.on_change.connect(self.on_blend_mode_setting_changed) 232 m = MenuData() 233 m.AddRadioButton(GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/BlendMode/Normal'), PatternBlendMode.OVERLAY, pattern_blend_mode_setting) 234 m.AddRadioButton(GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/BlendMode/Subtractive'), PatternBlendMode.SUBTRACT, pattern_blend_mode_setting) 235 m.AddRadioButton(GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/BlendMode/Exclusion'), PatternBlendMode.EXCLUSION, pattern_blend_mode_setting) 236 m.AddRadioButton(GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/BlendMode/Nested'), PatternBlendMode.NESTED, pattern_blend_mode_setting) 237 m.AddRadioButton(GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/BlendMode/NestedInverted'), PatternBlendMode.NESTED_INVERTED, pattern_blend_mode_setting) 238 return m 239 240 241 class MirrorToggleButtonIcon(CircularButtonIcon): 242 default_texturePath = eveicon.mirror 243 default_hint = GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/Gizmo/MirrorToggle') 244 245 def _ExecuteFunction(self, *args): 246 self.ToggleSelected() 247 component_instance = current_skin_design.get().get_fitted_component_instance(SlotID.PATTERN) 248 if component_instance: 249 component_instance.mirrored = self.isSelected 250 current_skin_design.add_to_undo_history() 251 252 253 class MirrorSecondaryToggleButtonIcon(CircularButtonIcon): 254 default_texturePath = eveicon.mirror 255 default_hint = GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/Gizmo/MirrorToggle') 256 257 def _ExecuteFunction(self, *args): 258 self.ToggleSelected() 259 component_instance = current_skin_design.get().get_fitted_component_instance(SlotID.SECONDARY_PATTERN) 260 if component_instance: 261 component_instance.mirrored = self.isSelected 262 current_skin_design.add_to_undo_history() 263 264 265 class SwitchPatternButtonIcon(CircularButtonIcon): 266 default_texturePath = eveicon.switch 267 default_hint = GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/Switch') 268 269 def _ExecuteFunction(self, *args): 270 current_skin_design.get().swap_slots(SlotID.PATTERN, SlotID.SECONDARY_PATTERN) 271 current_skin_design.add_to_undo_history()