conversationwindow.py (52894B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\conversations\ui\conversationwindow.py 2 from math import pi 3 import time 4 import blue 5 import carbonui.const as uiconst 6 import uthread 7 from carbonui.control.scrollContainer import ScrollContainer 8 from carbonui.fontconst import DEFAULT_FONTSIZE 9 from carbonui.primitives.container import Container 10 from carbonui.primitives.containerAutoSize import ContainerAutoSize 11 from carbonui.primitives.sprite import Sprite, StreamingVideoSprite 12 from carbonui.uianimations import animations 13 from carbonui.uicore import uicore 14 from carbonui.util.color import Color 15 from conversations.animatedtransmissionwindow import AnimatedTransmissionWindow 16 from conversations.const import CONVERSATION_WINDOW_ID 17 from conversations.ui.completedconversationui import CompletedConversationUi 18 from conversations.ui.conversationwindowstyle import ConversationWindowStyle, AGENT_ID_TO_STYLE 19 from conversations.ui.conversationwindowunderlay import ConversationWindowUnderlay 20 from carbonui.control.button import Button 21 from eve.client.script.ui.control.eveLabel import EveLabelLarge 22 from eve.client.script.ui.control.themeColored import SpriteThemeColored, LineThemeColored 23 from eve.client.script.ui.shared.pointerTool.pointerToolConst import UNIQUE_NAME_NEOCOM 24 from eve.client.script.ui.util.uix import GetTextWidth 25 from globalConfig import GetConversationLine3dPortraitEnabled 26 from localization import GetByMessageID, GetByLabel, IsPrimaryLanguage 27 from player_messaging.client.ui_message import prompt_player_fsd_dialog 28 from trinity import TR2_SBM_ADD, TR2_SBM_NONE 29 from uihider import get_ui_hider, UiHiderMixin 30 from uthread2 import call_after_wallclocktime_delay 31 import logging 32 logger = logging.getLogger(__name__) 33 COLOR_LABEL = Color.HextoRGBA('#e5f1ff') 34 DEFAULT_WIDTH = 580 35 DEFAULT_HEIGHT = 640 36 MAIN_CONTAINER_PADDING_WINDOW = 0 37 MAIN_CONTAINER_PADDING_TOP = 0 38 MAIN_CONTAINER_PADDING = (MAIN_CONTAINER_PADDING_WINDOW, 39 MAIN_CONTAINER_PADDING_WINDOW + MAIN_CONTAINER_PADDING_TOP, 40 MAIN_CONTAINER_PADDING_WINDOW, 41 MAIN_CONTAINER_PADDING_WINDOW) 42 CONTENT_WIDTH = DEFAULT_WIDTH - 2 * MAIN_CONTAINER_PADDING_WINDOW 43 CONTENT_HORIZONTAL_PADDING = 20 44 CONTENT_VERTICAL_PADDING = 12 45 AGENT_PORTRAIT_SIZE = 320 46 AGENT_PORTRAIT_VERTICAL_PADDING = 1 47 AGENT_CONTAINER_GRADIENT = 'res:/UI/Texture/classes/Seasons/lineBreakGradient.png' 48 AGENT_CONTAINER_GRADIENT_OPACITY = 1.0 49 AGENT_CONTAINER_SIDE_TEXTURE = 'res:/UI/Texture/classes/ConversationUI/sideDecoration.png' 50 AGENT_CONTAINER_SIDE_GLOW_TEXTURE = 'res:/UI/Texture/classes/ConversationUI/sideDecorationGlow.png' 51 AGENT_CONTAINER_SIDE_TEXTURE_WIDTH = 3 52 AGENT_CONTAINER_SIDE_TEXTURE_HEIGHT = 36 53 AGENT_CONTAINER_SIDE_GLOW_TEXTURE_WIDTH = 23 54 AGENT_CONTAINER_SIDE_GLOW_TEXTURE_HEIGHT = 56 55 AGENT_CONTAINER_SIDE_OPACITY = 0.8 56 LINE_HEIGHT = 1 57 TITLE_LINE_PADDING = 16 58 TITLE_LINE_OPACITY = 0.3 59 TITLE_CONTAINER_BOT_PADDING = 4 60 TITLE_OPACITY = 1.0 61 TITLE_TO_EXPAND_OPTION_PADDING = 4 62 EXPAND_OPTION_ICON_SIZE = 12 63 TEXT_TOP_PADDING = 16 64 TEXT_BOTTOM_PADDING = 6 65 TEXT_OPACITY = 1.0 66 HINTS_CONTAINER_TOP_PADDING = 16 67 HINTS_TO_BUTTONS_PADDING = 16 68 HINT_CELL_PADDING = 2 69 HINTS_COLUMN_NUMBER = 2 70 HINT_TEXT_OPACITY = 1.0 71 HINT_TEXT_SEPARATION = 4 72 NEXT_CONVERSATION_LINE_LABEL = 'UI/Conversations/UI/NextConversationLine' 73 PREVIOUS_CONVERSATION_LINE_LABEL = 'UI/Conversations/UI/PreviousConversationLine' 74 CONTINUE_BUTTON_LABEL = 'UI/Conversations/UI/Close' 75 NAVIGATION_BUTTON_LABEL_PADDING = 16 76 NAVIGATION_BUTTON_HEIGHT = 24 77 NAVIGATION_BUTTON_PADDING_TOP = 4 78 NAVIGATION_BUTTON_PADDING_BOTTOM = 4 79 MAIN_CONTAINER_MIN_HEIGHT = AGENT_PORTRAIT_SIZE + 2 * AGENT_PORTRAIT_VERTICAL_PADDING 80 AUDIO_ACTIVATION_DELAY_SECONDS = 1.0 81 ICON_TEXT_EXPAND = 'res:/UI/Texture/classes/ConversationUI/iconTextExpand.png' 82 ICON_TEXT_COLLAPSE = 'res:/UI/Texture/classes/ConversationUI/iconTextCollapse.png' 83 WINDOW_TITLE_LABEL = 'UI/Conversations/UI/ConversationWindowTitle' 84 SETTING_CONVERSATION_WINDOW_TEXT_EXPAND = 'conversation_window_text_expand' 85 COMPLETED_UI_HEIGHT = 26 86 COMPLETED_UI_PADDING = 8 87 MAX_TEXT_SCROLL_HEIGHT = 400 88 DEFAULT_HINT_ICON_SIZE = 32 89 90 def get_total_container_height(container): 91 return container.height + container.padTop + container.padBottom 92 93 94 def is_line_3d_portrait_enabled(): 95 return GetConversationLine3dPortraitEnabled(sm.GetService('machoNet')) 96 97 98 class ConversationWindow(AnimatedTransmissionWindow, UiHiderMixin): 99 __notifyevents__ = ['OnAudioActivated', 100 'OnAudioDeactivated', 101 'OnUIScalingChange', 102 'OnHideUI', 103 'OnShowUI', 104 'OnSetDevice'] 105 default_windowID = CONVERSATION_WINDOW_ID 106 default_iconNum = 'res:/UI/Texture/WindowIcons/tutorial.png' 107 default_isCollapseable = False 108 default_isStackable = False 109 default_isLightBackgroundConfigurable = False 110 default_isLockable = False 111 default_isOverlayable = False 112 default_isMinimizable = True 113 default_fixedWidth = DEFAULT_WIDTH 114 default_fixedHeight = DEFAULT_HEIGHT 115 default_left = 385 116 default_top = 75 117 default_hideHeaderIcons = False 118 default_is_content_expandable = False 119 default_is_decoration_on_sides = True 120 default_are_hints_visible = True 121 default_are_navigation_buttons_enabled = True 122 default_show_warning_on_first_close_setting = None 123 default_show_warning_on_first_close_dialog = None 124 default_close_on_audio_end = False 125 default_is_close_button_visible = False 126 default_style = ConversationWindowStyle 127 current_sound_id = None 128 default_conversation_id = None 129 default_is_completed = False 130 default_delay_seconds_between_audio_ended_and_show_next = 0 131 default_should_close_on_continue = False 132 default_should_autoprogress = True 133 134 def ApplyAttributes(self, attributes): 135 self.is_content_expandable = attributes.Get('is_content_expandable', self.default_is_content_expandable) 136 self.is_decoration_on_sides = attributes.Get('is_decoration_on_sides', self.default_is_decoration_on_sides) 137 self.are_hints_visible = attributes.Get('are_hints_visible', self.default_are_hints_visible) 138 self.are_navigation_buttons_enabled = attributes.Get('are_navigation_buttons_enabled', self.default_are_navigation_buttons_enabled) 139 self.show_warning_on_first_close_setting = attributes.Get('show_warning_on_first_close_setting', self.default_show_warning_on_first_close_setting) 140 self.show_warning_on_first_close_dialog = attributes.Get('show_warning_on_first_close_dialog', self.default_show_warning_on_first_close_dialog) 141 self.close_on_audio_end = attributes.Get('close_on_audio_end', self.default_close_on_audio_end) 142 self.is_close_button_visible = attributes.Get('is_close_button_visible', self.default_is_close_button_visible) 143 self.delay_seconds_between_audio_ended_and_show_next = attributes.Get('delay_seconds_between_audio_ended_and_show_next', self.default_delay_seconds_between_audio_ended_and_show_next) 144 self.conversation_id = attributes.Get('conversation_id', self.default_conversation_id) 145 self.is_completed = attributes.Get('is_completed', self.default_is_completed) 146 self.should_close_on_continue = attributes.Get('should_close_on_continue', self.default_should_close_on_continue) 147 self.should_autoprogress = attributes.Get('should_autoprogress', self.default_should_autoprogress) 148 self.style = None 149 self.styled_backgrounds_container = None 150 self.background_gradient_container = None 151 self.portrait_side_line_left_container = None 152 self.portrait_side_line_right_container = None 153 self.portrait_side_line_glow_left_container = None 154 self.portrait_side_line_glow_right_container = None 155 self.window_top_line_container = None 156 self.window_top_line_glow_container = None 157 self.is_waiting_for_delay_to_show_next_conversation = False 158 self.next_conversation_tasklet = None 159 self.showing_next = False 160 self.title_line_container = None 161 self.title_line = None 162 self.expand_option_container = None 163 self.expand_option_sprite = None 164 self.text = None 165 self.text_container = None 166 self.text_label = None 167 self.hints_line = None 168 self.hints_container = None 169 self.navigation_button_container = None 170 self.completed_ui_container = None 171 self.paragraph_labels = [] 172 self.hint_labels = [] 173 self.agent_portrait_intro_3d_container = None 174 self.agent_portrait_intro_video_container = None 175 self.agent_portrait_image_sprite = None 176 self.current_agent_id = None 177 self.current_line = None 178 self._is_portrait_loaded = False 179 super(ConversationWindow, self).ApplyAttributes(attributes) 180 self.MakeUnResizeable() 181 self.SetCaption(GetByLabel(WINDOW_TITLE_LABEL)) 182 sm.RegisterNotify(self) 183 self._conversation_svc = sm.GetService('conversationService') 184 self._audio_svc = sm.GetService('audio') 185 self._audio_svc.SubscribeToEventCallback(self._on_sound_event_completed) 186 self.is_audio_activated = self._audio_svc.IsActivated() 187 self.sound_playing = False 188 self.sound_start_time = 0 189 self.manual_expanded_setting = self._get_expand_setting() 190 content_container_alignment = self._get_content_container_alignment() 191 self.main_container = Container(name='main_conversation_container', parent=self.sr.main, align=uiconst.TOTOP, height=DEFAULT_HEIGHT, padding=MAIN_CONTAINER_PADDING) 192 self.portrait_container = Container(name='portrait_container', parent=self.main_container, align=self._get_portrait_container_alignment(), width=self._get_portrait_container_width(), height=self._get_portrait_container_height()) 193 self.portrait_wrapper_container = None 194 content_horizontal_padding = self._get_content_horizontal_padding() 195 content_top_padding = self._get_content_top_padding() 196 content_bottom_padding = self._get_content_bottom_padding() 197 content_width = self._get_content_width() - content_horizontal_padding 198 self.content_container = Container(name='conversation_content_container', parent=self.main_container, align=content_container_alignment, width=content_width, height=0, padding=(content_horizontal_padding, 199 content_top_padding, 200 0, 201 content_bottom_padding)) 202 self._add_title() 203 has_incoming_transmission_sound = self._transmission_sound_effect is not None 204 self.show_next_conversation(play_incoming_transmission_sound=has_incoming_transmission_sound) 205 self.SetParent(uicore.layer.alwaysvisible) 206 if self.is_neocom_hidden(): 207 self.MakeUnMinimizable() 208 209 def is_neocom_hidden(self): 210 return get_ui_hider().is_ui_element_hidden(UNIQUE_NAME_NEOCOM) 211 212 def OnEndMinimize_(self, *args): 213 super(ConversationWindow, self).OnEndMinimize_(*args) 214 self.SetParent(uicore.layer.alwaysvisible) 215 216 def OnEndMaximize_(self, *args): 217 super(ConversationWindow, self).OnEndMaximize_(*args) 218 self.SetParent(uicore.layer.alwaysvisible) 219 220 def InitializeStatesAndPosition(self, *args, **kwds): 221 super(ConversationWindow, self).InitializeStatesAndPosition(*args, **kwds) 222 self._correct_height(style_changed=True) 223 self.SetParent(uicore.layer.alwaysvisible) 224 225 def animate_text_portrait_in(self): 226 timeOffset = 0.6 227 portrait_offset = 0.5 228 portrait_duration = 0.5 229 for label in self.paragraph_labels: 230 timeOffset += self._FadeInLabel(label, timeOffset, TEXT_OPACITY) 231 232 if self._should_show_hints(): 233 if self.hints_line: 234 animations.FadeIn(self.hints_container, duration=0.6, timeOffset=timeOffset) 235 for label in self.hint_labels: 236 timeOffset += self._FadeInLabel(label, timeOffset, HINT_TEXT_OPACITY) 237 238 if self._should_show_navigation_buttons(): 239 self.navigation_button_container.SetState(uiconst.UI_DISABLED) 240 animations.FadeIn(self.navigation_button_container, 1.0, duration=0.6, timeOffset=timeOffset, callback=lambda : self.navigation_button_container.SetState(uiconst.UI_NORMAL)) 241 timeOffset += 0.6 242 blue.synchro.SleepWallclock(1000 * portrait_offset) 243 if self.agent_portrait_intro_3d_container is not None: 244 self.agent_portrait_intro_3d_container.avatarscenecontainer.opacity = 0.0 245 self.agent_portrait_intro_3d_container.avatarscenecontainer.fade_in_duration = portrait_duration 246 self.agent_portrait_intro_3d_container.avatarscenecontainer.fade_out_duration = 0.3 247 self.agent_portrait_intro_3d_container.avatarscenecontainer.fade_out_offset = 0.0 248 self.notify_of_open() 249 250 def _FadeInLabel(self, label, timeOffset, opacity): 251 animations.FadeIn(label, opacity, duration=0.6, timeOffset=timeOffset) 252 animations.MorphScalar(label, 'left', 8, 0, duration=0.4, timeOffset=timeOffset) 253 return self._GetTimeOffsetByTextLength(label.text) 254 255 def _GetTimeOffsetByTextLength(self, text): 256 numLetters = len(text) 257 return max(1.2, numLetters / 100.0) 258 259 def _clear_container(self, container): 260 if self._is_ui_element_available(container): 261 container.Flush() 262 container.Close() 263 264 def _is_ui_element_available(self, ui_element): 265 return ui_element and not ui_element.destroyed 266 267 def _get_content_container_alignment(self): 268 return uiconst.TOTOP 269 270 def _get_main_container_width(self): 271 return DEFAULT_WIDTH 272 273 def _get_main_container_height(self): 274 content_container_height_with_padding = self.content_container.height + self.content_container.padTop + self.content_container.padBottom 275 vertical_height = MAIN_CONTAINER_MIN_HEIGHT + content_container_height_with_padding 276 return vertical_height 277 278 def _get_content_width(self): 279 return CONTENT_WIDTH 280 281 def _get_content_horizontal_padding(self): 282 return CONTENT_HORIZONTAL_PADDING 283 284 def _get_content_top_padding(self): 285 return CONTENT_VERTICAL_PADDING 286 287 def _get_content_bottom_padding(self): 288 return CONTENT_VERTICAL_PADDING 289 290 def _get_portrait_container_width(self): 291 return self._get_content_width() 292 293 def _get_portrait_container_height(self): 294 return AGENT_PORTRAIT_SIZE + 2 * AGENT_PORTRAIT_VERTICAL_PADDING 295 296 def _get_portrait_container_alignment(self): 297 return uiconst.TOTOP 298 299 def _get_agent_portrait_size(self): 300 return (AGENT_PORTRAIT_SIZE, AGENT_PORTRAIT_SIZE) 301 302 def _get_text_scroll_height(self): 303 try: 304 return min(self.text_paragraphs_container.height, MAX_TEXT_SCROLL_HEIGHT) 305 except AttributeError: 306 return MAX_TEXT_SCROLL_HEIGHT 307 308 def _load_portrait(self, agent_data, next_line): 309 self._clear_container(self.portrait_wrapper_container) 310 self.portrait_wrapper_container = Container(name='portrait_wrapper_container', parent=self.portrait_container, align=uiconst.TOTOP, width=self.portrait_container.width, height=self.portrait_container.height) 311 if self.is_decoration_on_sides: 312 self._load_portrait_side_lines() 313 self._load_portrait_side_lines_glow() 314 self._load_agent_portrait(agent_data, next_line) 315 if next_line.scene_path is not None or agent_data.scene_path is not None: 316 pass 317 318 def _load_agent_container_bg(self): 319 agent_portrait_width, agent_portrait_height = self._get_agent_portrait_size() 320 self.background_gradient = Sprite(name='agent_portrait_bg', parent=self.portrait_wrapper_container, align=uiconst.CENTER, width=agent_portrait_width, height=agent_portrait_height, texturePath=AGENT_CONTAINER_GRADIENT, opacity=AGENT_CONTAINER_GRADIENT_OPACITY) 321 self._set_sprite_color(self.background_gradient, glow=True) 322 323 def _is_using_low_quality_characters(self): 324 from avatardisplay.avatardisplay import IsUsingLowQualityCharacters 325 return IsUsingLowQualityCharacters() 326 327 def _load_agent_portrait(self, agent_data, next_line, restart_audio = False): 328 self._load_agent_portrait_3d(agent_data, next_line, restart_audio=restart_audio) 329 self._load_agent_portrait_videos(agent_data) 330 self._load_agent_portrait_image(agent_data, restart_audio=restart_audio) 331 332 def _load_agent_portrait_3d(self, agent_data, next_line, restart_audio = False): 333 if self._is_using_low_quality_characters(): 334 return 335 if self._is_portrait_loaded or next_line.scene_path is None and agent_data.scene_path is None: 336 return 337 from avatardisplay.avatardisplay import PlaybackScene 338 from avatardisplay.errors import FailedToPlaybackScene 339 agent_portrait_width, agent_portrait_height = self._get_agent_portrait_size() 340 self.agent_portrait_intro_3d_container = Container(parent=self.portrait_wrapper_container, name='agent_portrait_intro_3d_container', align=uiconst.CENTER, width=agent_portrait_width, height=agent_portrait_height, display=True) 341 scene_dir = None 342 if is_line_3d_portrait_enabled() and next_line.scene_path is not None: 343 scene_dir = next_line.scene_path 344 elif agent_data.scene_path is not None: 345 scene_dir = agent_data.scene_path 346 if scene_dir is not None: 347 try: 348 PlaybackScene(scene_dir=scene_dir, parent=self.agent_portrait_intro_3d_container, hide=True, sound_start_time=self.sound_start_time if not restart_audio else 0) 349 self._is_portrait_loaded = True 350 except FailedToPlaybackScene as exc: 351 logger.exception(exc) 352 353 def _load_agent_portrait_image(self, agent_data, restart_audio = False): 354 if self._is_portrait_loaded: 355 return 356 agent_portrait_width, agent_portrait_height = self._get_agent_portrait_size() 357 self.agent_portrait_image_sprite = Sprite(name='agent_portrait', parent=self.portrait_wrapper_container, align=uiconst.CENTER, width=agent_portrait_width, height=agent_portrait_height, texturePath=agent_data.image_path) 358 self._is_portrait_loaded = True 359 if restart_audio: 360 self._start_playing_audio() 361 362 def _load_agent_portrait_videos(self, agent_data): 363 if self._is_portrait_loaded or not agent_data.use_video: 364 return 365 agent_portrait_size = self._get_agent_portrait_size()[0] 366 has_intro_video = agent_data.use_intro_video 367 if has_intro_video: 368 self.agent_portrait_intro_video_container = Container(parent=self.portrait_wrapper_container, name='agent_portrait_intro_video_container', align=uiconst.TOTOP_NOPUSH, width=self.portrait_container.width, height=self.portrait_container.height, display=False) 369 self.agent_portrait_intro_video = StreamingVideoSprite(parent=self.agent_portrait_intro_video_container, name='agent_portrait_intro_video', videoPath=agent_data.intro_video_path, videoLoop=False, align=uiconst.CENTER, width=agent_portrait_size, height=agent_portrait_size, state=uiconst.UI_DISABLED, blendMode=TR2_SBM_NONE, disableAudio=True) 370 self.agent_portrait_intro_video.Pause() 371 self.agent_portrait_intro_video_container.display = False 372 self.agent_portrait_loop_video_container = Container(parent=self.portrait_wrapper_container, name='agent_portrait_loop_video_container', align=uiconst.TOTOP_NOPUSH, width=self.portrait_container.width, height=self.portrait_container.height, display=False) 373 self.agent_portrait_loop_video = StreamingVideoSprite(parent=self.agent_portrait_loop_video_container, name='agent_portrait_loop_video', videoPath=agent_data.loop_video_path, videoLoop=True, align=uiconst.CENTER, width=agent_portrait_size, height=agent_portrait_size, state=uiconst.UI_DISABLED, blendMode=TR2_SBM_NONE, disableAudio=True) 374 self.agent_portrait_loop_video_container.display = False 375 if has_intro_video: 376 self.agent_portrait_intro_video.OnVideoFinished = self._play_agent_portrait_loop_video 377 self._play_agent_portrait_intro_video() 378 else: 379 self.agent_portrait_intro_video = None 380 self.agent_portrait_intro_video_container = None 381 self._play_agent_portrait_loop_video() 382 self._is_portrait_loaded = True 383 384 def _play_agent_portrait_intro_video(self): 385 self.agent_portrait_intro_video_container.display = True 386 self.agent_portrait_intro_video.Play() 387 388 def _play_agent_portrait_loop_video(self): 389 if self.agent_portrait_intro_video: 390 self.agent_portrait_intro_video_container.display = False 391 self.agent_portrait_loop_video_container.display = True 392 self.agent_portrait_loop_video.Play() 393 394 def _get_sprite_class(self): 395 if self.style.style_color: 396 return Sprite 397 return SpriteThemeColored 398 399 def _set_sprite_color(self, sprite, glow = True): 400 if not sprite: 401 return 402 if self.style.style_color: 403 sprite.color = self.style.style_color 404 return 405 if glow: 406 sprite.colorType = uiconst.COLORTYPE_UIHILIGHTGLOW 407 else: 408 sprite.colorType = uiconst.COLORTYPE_UIHILIGHT 409 410 def _load_portrait_side_lines(self): 411 position_top = (self.portrait_container.height - AGENT_CONTAINER_SIDE_TEXTURE_HEIGHT) / 2 412 sprite_class = self._get_sprite_class() 413 self._clear_container(self.portrait_side_line_left_container) 414 self._clear_container(self.portrait_side_line_right_container) 415 self.portrait_side_line_left_container = Container(name='portrait_side_line_left_container', parent=self.portrait_container, align=uiconst.ANCH_TOPLEFT, width=self.portrait_container.width, height=self.portrait_container.height) 416 portrait_side_line_left = sprite_class(name='portrait_side_line_left', parent=self.portrait_side_line_left_container, texturePath=AGENT_CONTAINER_SIDE_TEXTURE, align=uiconst.ANCH_TOPLEFT, useSizeFromTexture=True, top=position_top, rotation=pi, opacity=AGENT_CONTAINER_SIDE_OPACITY, blendMode=TR2_SBM_ADD) 417 self._set_sprite_color(portrait_side_line_left, glow=True) 418 self.portrait_side_line_right_container = Container(name='portrait_side_line_right_container', parent=self.portrait_container, align=uiconst.ANCH_TOPRIGHT, width=self.portrait_container.width, height=self.portrait_container.height) 419 portrait_side_line_right = sprite_class(name='portrait_side_line_right', parent=self.portrait_side_line_right_container, texturePath=AGENT_CONTAINER_SIDE_TEXTURE, align=uiconst.ANCH_TOPRIGHT, useSizeFromTexture=True, top=position_top + AGENT_CONTAINER_SIDE_TEXTURE_HEIGHT, left=AGENT_CONTAINER_SIDE_TEXTURE_WIDTH, opacity=AGENT_CONTAINER_SIDE_OPACITY, blendMode=TR2_SBM_ADD) 420 self._set_sprite_color(portrait_side_line_right, glow=True) 421 422 def _load_portrait_side_lines_glow(self): 423 position_top_glow = (self.portrait_container.height - AGENT_CONTAINER_SIDE_GLOW_TEXTURE_HEIGHT) / 2 424 sprite_class = self._get_sprite_class() 425 self._clear_container(self.portrait_side_line_glow_left_container) 426 self._clear_container(self.portrait_side_line_glow_right_container) 427 self.portrait_side_line_glow_left_container = Container(name='portrait_side_line_glow_left_container', parent=self.portrait_container, align=uiconst.ANCH_TOPLEFT, width=self.portrait_container.width, height=self.portrait_container.height) 428 portrait_side_line_glow_left = sprite_class(name='portrait_side_line_glow_left', parent=self.portrait_side_line_glow_left_container, texturePath=AGENT_CONTAINER_SIDE_GLOW_TEXTURE, align=uiconst.ANCH_TOPLEFT, useSizeFromTexture=True, top=position_top_glow, left=-AGENT_CONTAINER_SIDE_GLOW_TEXTURE_WIDTH / 2, blendMode=TR2_SBM_ADD, rotation=pi) 429 self._set_sprite_color(portrait_side_line_glow_left, glow=False) 430 self.portrait_side_line_glow_right_container = Container(name='portrait_side_line_glow_right_container', parent=self.portrait_container, align=uiconst.ANCH_TOPRIGHT, width=self.portrait_container.width, height=self.portrait_container.height) 431 portrait_side_line_glow_right = sprite_class(name='portrait_side_line_glow_right', parent=self.portrait_side_line_glow_right_container, texturePath=AGENT_CONTAINER_SIDE_GLOW_TEXTURE, align=uiconst.ANCH_TOPRIGHT, useSizeFromTexture=True, top=position_top_glow + AGENT_CONTAINER_SIDE_GLOW_TEXTURE_HEIGHT, left=AGENT_CONTAINER_SIDE_GLOW_TEXTURE_WIDTH / 2, blendMode=TR2_SBM_ADD) 432 self._set_sprite_color(portrait_side_line_glow_right, glow=False) 433 434 def _add_title(self): 435 self.title_container = Container(name='title_container', parent=self.content_container, align=uiconst.TOTOP, width=self.content_container.width, height=0, padBottom=TITLE_CONTAINER_BOT_PADDING) 436 title_text_width = self.content_container.width 437 if self.is_content_expandable: 438 self.expand_option_container = Container(name='expand_option_container', parent=self.title_container, align=uiconst.TORIGHT, width=EXPAND_OPTION_ICON_SIZE, height=EXPAND_OPTION_ICON_SIZE) 439 title_text_width = title_text_width - EXPAND_OPTION_ICON_SIZE - TITLE_TO_EXPAND_OPTION_PADDING 440 self.title_text_container = Container(name='title_text_container', parent=self.title_container, align=uiconst.TOLEFT, width=title_text_width, height=0) 441 self.title_label = EveLabelLarge(name='title_label', parent=self.title_text_container, text='', width=title_text_width, align=uiconst.TOTOP, opacity=TITLE_OPACITY, blendMode=TR2_SBM_NONE) 442 443 def _load_expand_option_sprite(self, expand): 444 if not self.is_content_expandable or not self.is_audio_activated: 445 return 446 expand_sprite_texture = ICON_TEXT_COLLAPSE if expand else ICON_TEXT_EXPAND 447 if self._is_ui_element_available(self.expand_option_sprite): 448 self.expand_option_sprite.Close() 449 self.expand_option_sprite = Sprite(name='expand_option', parent=self.expand_option_container, align=uiconst.CENTER, width=EXPAND_OPTION_ICON_SIZE, height=EXPAND_OPTION_ICON_SIZE, texturePath=expand_sprite_texture) 450 self.expand_option_sprite.OnClick = self._expand_content 451 452 def _load_title(self, title): 453 self.title_label.text = title 454 455 def _load_title_line(self, expand = True): 456 self._clear_container(self.title_line_container) 457 if expand or not self.is_content_expandable: 458 self.title_line_container = Container(name='title_line_container', parent=self.content_container, align=uiconst.TOTOP, width=self.content_container.width, height=LINE_HEIGHT) 459 self.title_line = LineThemeColored(name='title_line', parent=self.title_line_container, align=uiconst.TOTOP, weight=LINE_HEIGHT) 460 if self.style: 461 self.style_line(self.title_line) 462 463 def _should_collapse_content(self, expand): 464 return self.is_content_expandable and not expand 465 466 def _should_show_text(self): 467 return self.text 468 469 def _should_show_hints(self): 470 return self.are_hints_visible and self.hints 471 472 def _should_show_hints_line(self): 473 return self._should_show_text() and self._should_show_hints() 474 475 def _get_scroll_bar_color(self): 476 if self.style is not None: 477 return self.style.scroll_bar_color 478 else: 479 return 480 481 def _load_text(self, expand = True): 482 self._clear_container(self.text_container) 483 if not self._should_show_text() or self._should_collapse_content(expand): 484 return 485 self.text_container = Container(name='text_container', parent=self.content_container, align=uiconst.TOTOP, width=self.content_container.width, height=0, padTop=TEXT_TOP_PADDING, padBottom=TEXT_BOTTOM_PADDING) 486 scroll = ScrollContainer(align=uiconst.TOTOP, parent=self.text_container, height=self._get_text_scroll_height(), scrollBarColor=self._get_scroll_bar_color()) 487 self.text_paragraphs_container = ContainerAutoSize(parent=scroll, align=uiconst.TOTOP) 488 self.paragraph_labels = [] 489 paragraphList = self.GetTextByParagraphs(self.text) 490 for text in paragraphList: 491 label = EveLabelLarge(name='text_label', parent=self.text_paragraphs_container, text=text, align=uiconst.TOTOP, opacity=0.0, color=COLOR_LABEL, padBottom=12) 492 self.paragraph_labels.append(label) 493 494 self.text_paragraphs_container.SetSizeAutomatically() 495 scroll.height = self._get_text_scroll_height() 496 497 def GetTextByParagraphs(self, text): 498 paragraphList = text.split('\r\n\r\n') 499 return paragraphList 500 501 def _load_hints(self, expand = True): 502 self._clear_container(self.hints_container) 503 if not self._should_show_hints() or self._should_collapse_content(expand): 504 return 505 self.hints_container = ContainerAutoSize(name='hints_container', parent=self.content_container, align=uiconst.TOTOP, alignMode=uiconst.TOTOP, opacity=0.0) 506 if self._should_show_hints_line(): 507 self._load_hints_line() 508 self.hint_labels = [] 509 for hint in self.hints: 510 paragraph_list = self.GetTextByParagraphs(GetByMessageID(hint.text)) 511 hint_container = ContainerAutoSize(name='hint_container', parent=self.hints_container, align=uiconst.TOTOP, alignMode=uiconst.TOTOP, padBottom=12 if paragraph_list else 0) 512 hint_sprite = self._check_create_hint_sprite(hint, hint_container) 513 hint_labels_container = ContainerAutoSize(name='hint_labels_container', parent=hint_container, align=uiconst.TOTOP, alignMode=uiconst.TOTOP, minHeight=hint_sprite.height if hint_sprite else 0) 514 text_height = 0 515 for text in paragraph_list: 516 pad_top = 12 if self.hint_labels else 0 517 label = EveLabelLarge(name='hint_text_label', parent=hint_labels_container, text=text, align=uiconst.TOTOP, color=(1, 1, 1, 1), opacity=0.0, padTop=pad_top) 518 text_height += label.height + pad_top 519 self.hint_labels.append(label) 520 521 hint_labels_container.SetSizeAutomatically() 522 if hint_sprite and text_height < hint_sprite.height: 523 hint_labels_container.padTop += max(0, (hint_sprite.height - text_height) / 2) 524 525 self.hints_container.SetSizeAutomatically() 526 self.hints_container.UpdateAlignment() 527 528 def _load_hints_line(self): 529 self.hints_line = LineThemeColored(name='hints_line', parent=self.hints_container, align=uiconst.TOTOP, weight=LINE_HEIGHT, padBottom=12) 530 if self.style: 531 self.style_line(self.hints_line) 532 533 def _check_create_hint_sprite(self, hint, parent): 534 if not hint.iconID: 535 return 536 hint_image = self._conversation_svc.get_line_hint_image(hint.iconID) 537 hint_image_path = hint_image.image_path 538 hint_image_size = hint.image_size or DEFAULT_HINT_ICON_SIZE 539 pad_right = 6 540 hint_sprite_container = Container(name='hint_sprite_container', parent=parent, width=hint_image_size + pad_right, height=hint_image_size, padLeft=-HINT_CELL_PADDING, align=uiconst.TOLEFT) 541 hint_sprite = Sprite(name='hint_image_icon', parent=hint_sprite_container, width=hint_image_size, height=hint_image_size, texturePath=hint_image_path, state=uiconst.UI_DISABLED, align=uiconst.CENTERLEFT) 542 if hint_sprite and hint.image_color: 543 hint_sprite.SetRGBA(*hint.image_color) 544 return hint_sprite 545 546 def _should_expand_content(self): 547 language = getattr(session, 'languageID', None) 548 is_client_localized = not IsPrimaryLanguage(language) if language else True 549 is_audio_enabled = self.is_audio_activated 550 return is_client_localized or not is_audio_enabled 551 552 def _is_content_expanded(self): 553 return self.text_container is not None and not self.text_container.destroyed 554 555 def _expand_content(self): 556 expand = not self._is_content_expanded() 557 settings.char.ui.Set(SETTING_CONVERSATION_WINDOW_TEXT_EXPAND, expand) 558 self.manual_expanded_setting = expand 559 self._clear_container(self.navigation_button_container) 560 self._show_expanded_content(expand) 561 self._load_navigation_buttons() 562 self._correct_height(style_changed=False) 563 564 def _should_show_navigation_buttons(self): 565 return self._should_show_next_button() or self._should_show_previous_button() or self._should_show_close_button() 566 567 def _should_show_next_button(self): 568 return self.are_navigation_buttons_enabled and self._conversation_svc.are_any_conversation_lines_left() 569 570 def _should_show_previous_button(self): 571 return self.are_navigation_buttons_enabled and self._conversation_svc.are_any_previous_conversation_lines_available() 572 573 def _should_show_close_button(self): 574 return self.is_close_button_visible and not self._conversation_svc.are_any_conversation_lines_left() 575 576 def _load_navigation_buttons(self): 577 if not self._should_show_navigation_buttons(): 578 return 579 self._clear_container(self.navigation_button_container) 580 self.navigation_button_container = Container(name='navigation_button_container', align=uiconst.TOBOTTOM, parent=self.content_container, height=NAVIGATION_BUTTON_HEIGHT, padTop=NAVIGATION_BUTTON_PADDING_TOP, opacity=0.0) 581 if self._should_show_hints_line(): 582 self.navigation_button_container.padTop += HINTS_TO_BUTTONS_PADDING 583 if self._should_show_next_button(): 584 label_text = GetByLabel(NEXT_CONVERSATION_LINE_LABEL) 585 label_text_width = GetTextWidth(strng=label_text, fontsize=DEFAULT_FONTSIZE) 586 button_width = label_text_width + 2 * NAVIGATION_BUTTON_LABEL_PADDING 587 next_button = Button(name='next_button', parent=self.navigation_button_container, align=uiconst.TORIGHT, fixedwidth=button_width, label=label_text, func=self.show_next_conversation, args=()) 588 self.style_button(next_button) 589 if self._should_show_previous_button(): 590 label_text = GetByLabel(PREVIOUS_CONVERSATION_LINE_LABEL) 591 label_text_width = GetTextWidth(strng=label_text, fontsize=DEFAULT_FONTSIZE) 592 button_width = label_text_width + 2 * NAVIGATION_BUTTON_LABEL_PADDING 593 previous_button = Button(name='previous_button', parent=self.navigation_button_container, align=uiconst.TOLEFT, fixedwidth=button_width, label=label_text, func=self.show_previous_conversation, args=()) 594 self.style_button(previous_button) 595 if self._should_show_close_button(): 596 label_text = GetByLabel(CONTINUE_BUTTON_LABEL) 597 label_text_width = GetTextWidth(strng=label_text, fontsize=DEFAULT_FONTSIZE) 598 button_width = label_text_width + 2 * NAVIGATION_BUTTON_LABEL_PADDING 599 close_button = Button(name='close_button', parent=self.navigation_button_container, align=uiconst.TORIGHT, fixedwidth=button_width, label=label_text, func=self._on_continue_button, args=()) 600 self.style_button(close_button) 601 602 def _on_continue_button(self, *args): 603 sm.ScatterEvent('OnClientEvent_ConversationContinueButtonClicked', self.conversation_id) 604 if self.should_close_on_continue: 605 self._close_if_open() 606 607 def _clear_navigation_buttons(self): 608 self._clear_container(self.navigation_button_container) 609 self.navigation_button_container = None 610 611 def show_completed_ui(self): 612 self.is_completed = True 613 if self._is_ui_element_available(self.completed_ui_container): 614 return 615 self._load_completed_ui() 616 self._correct_height() 617 618 def _load_completed_ui(self): 619 self._clear_container(self.completed_ui_container) 620 if not self.is_completed: 621 return 622 self.completed_ui_container = CompletedConversationUi(name='completed_ui_container', align=uiconst.TOBOTTOM, parent=self.content_container, width=self.content_container.width, height=COMPLETED_UI_HEIGHT, padTop=COMPLETED_UI_PADDING) 623 624 def _clear_completed_ui(self): 625 self._clear_container(self.completed_ui_container) 626 self.completed_ui_container = None 627 628 def style_button(self, button): 629 if self.style.style_color: 630 button.SetColor(self.style.style_color) 631 if self.style.label_color: 632 button.SetLabelColor(self.style.label_color) 633 634 def _correct_height(self, style_changed = False): 635 title_height = self.title_label.height 636 self.title_container.height = title_height 637 self.title_text_container = title_height 638 title_height = get_total_container_height(self.title_container) 639 title_line_height = 0 640 text_height = 0 641 hints_height = 0 642 if self._is_ui_element_available(self.title_line_container): 643 title_line_height = get_total_container_height(self.title_line_container) 644 if self._is_ui_element_available(self.text_container): 645 self.text_container.height = self._get_text_scroll_height() 646 text_height = get_total_container_height(self.text_container) 647 if self._is_ui_element_available(self.hints_container): 648 hints_height = get_total_container_height(self.hints_container) 649 self.content_container.height = title_height + title_line_height + text_height + hints_height 650 if self._should_show_navigation_buttons() and self._is_ui_element_available(self.navigation_button_container): 651 navigation_button_height = get_total_container_height(self.navigation_button_container) 652 self.content_container.height = self.content_container.height + navigation_button_height 653 if self.is_completed and self._is_ui_element_available(self.completed_ui_container): 654 completed_ui_height = get_total_container_height(self.completed_ui_container) 655 self.content_container.height = self.content_container.height + completed_ui_height 656 self.main_container.height = self._get_main_container_height() 657 self._apply_fixed_size() 658 if style_changed: 659 self._apply_style() 660 self.style_backgrounds() 661 662 def _apply_fixed_size(self): 663 height = self.main_container.height + 2 * MAIN_CONTAINER_PADDING_WINDOW + MAIN_CONTAINER_PADDING_TOP 664 width = self._get_main_container_width() 665 width, height = self.GetWindowSizeForContentSize(width=width, height=height) 666 self.SetFixedWidth(width) 667 self.SetFixedHeight(height) 668 669 def _on_sound_event_completed(self, event_str): 670 if self.agent_portrait_intro_3d_container is not None: 671 avatar_context = self.agent_portrait_intro_3d_container.avatarscenecontainer.context 672 avatar_scene_play_event = avatar_context.GetSceneAudioPlayingEvent() if avatar_context else None 673 else: 674 avatar_scene_play_event = None 675 if not self.sound_playing and not avatar_scene_play_event: 676 return 677 if event_str is None or not self.is_audio_activated: 678 return 679 current_play_event = self._conversation_svc.get_play_event(self.current_sound_id) 680 if event_str == current_play_event or event_str == avatar_scene_play_event: 681 self.sound_playing = False 682 if self.should_autoprogress: 683 self.show_next_conversation(delay=True, play_incoming_transmission_sound=False) 684 685 def _stop_playing_audio(self): 686 self.sound_playing = False 687 if self.current_sound_id is None: 688 return 689 stop_event = self._conversation_svc.get_stop_event(self.current_sound_id) 690 if stop_event: 691 self._audio_svc.SendUIEvent(stop_event) 692 693 def _start_playing_audio(self): 694 if self.destroyed or session.languageID.lower() not in ('en', 'ko', 'es'): 695 return 696 if uicore.layer.systemmenu.isopen: 697 return 698 if self.sound_playing: 699 return 700 play_event = self._conversation_svc.get_play_event(self.current_sound_id) 701 if play_event and self.is_audio_activated: 702 self.sound_playing = True 703 self.sound_start_time = time.time() 704 self._audio_svc.SendUIEventWithCallback(play_event) 705 706 def OnAudioActivated(self): 707 self.is_audio_activated = True 708 call_after_wallclocktime_delay(self._activate_audio, AUDIO_ACTIVATION_DELAY_SECONDS) 709 710 def _activate_audio(self): 711 if self.destroyed: 712 return 713 if not uicore.layer.systemmenu.isopen: 714 self._start_playing_audio() 715 if not self._should_show_navigation_buttons() and self.navigation_button_container: 716 self._clear_navigation_buttons() 717 self._correct_height() 718 expand = self._get_expand_setting() 719 self._load_expand_option_sprite(expand) 720 721 def OnAudioDeactivated(self): 722 self.is_audio_activated = False 723 self._stop_playing_audio() 724 if self.agent_portrait_intro_3d_container is not None: 725 self.agent_portrait_intro_3d_container.avatarscenecontainer.context.StopAudio() 726 did_content_change = False 727 if self._should_expand_content() and not self._is_content_expanded(): 728 self._show_expanded_content(expand=True) 729 did_content_change = True 730 if self._should_show_navigation_buttons() and not self.navigation_button_container: 731 self._load_navigation_buttons() 732 did_content_change = True 733 if did_content_change: 734 self._correct_height() 735 if self._is_ui_element_available(self.expand_option_sprite): 736 self.expand_option_sprite.Close() 737 738 def OnHideUI(self): 739 self._stop_playing_audio() 740 if self.agent_portrait_intro_3d_container is not None and self.agent_portrait_intro_3d_container.avatarscenecontainer.context is not None: 741 self.agent_portrait_intro_3d_container.avatarscenecontainer.context.StopAudio() 742 743 def OnShowUI(self): 744 if self.agent_portrait_intro_3d_container is not None: 745 if self._is_using_low_quality_characters(): 746 if self.current_agent_id is not None and self.current_line is not None: 747 logger.info('avatardisplay: Replacing 3D agent with 2D agent') 748 self.agent_portrait_intro_3d_container.display = False 749 self.agent_portrait_intro_3d_container.Close() 750 self.agent_portrait_intro_3d_container = None 751 self._is_portrait_loaded = False 752 self._load_agent_portrait(self._conversation_svc.get_agent(self.current_agent_id), self.current_line, restart_audio=True) 753 else: 754 logger.info('avatardisplay: Reloading in OnShowUI') 755 self.agent_portrait_intro_3d_container.avatarscenecontainer.Reload() 756 elif self._is_portrait_loaded: 757 if not self._is_using_low_quality_characters(): 758 logger.info('avatardisplay: Replacing 2D agent with 3D agent') 759 self._is_portrait_loaded = False 760 if self.agent_portrait_intro_video_container: 761 self.agent_portrait_intro_video_container.Close() 762 logger.info('avatardisplay: closing video container') 763 if self.agent_portrait_image_sprite: 764 self.agent_portrait_image_sprite.Close() 765 logger.info('avatardisplay: closing sprite') 766 self._load_agent_portrait(self._conversation_svc.get_agent(self.current_agent_id), self.current_line, restart_audio=True) 767 self.agent_portrait_intro_3d_container.display = False 768 blue.synchro.Sleep(100) 769 self.agent_portrait_intro_3d_container.display = True 770 771 def OnSetDevice(self): 772 self._stop_playing_audio() 773 774 def show_next_conversation(self, delay = False, play_incoming_transmission_sound = True): 775 if self.showing_next: 776 return 777 self.showing_next = True 778 self.kill_next_conversation_tasklet() 779 next_line = None 780 if self._conversation_svc.are_any_conversation_lines_left(): 781 next_line = self._conversation_svc.get_next_conversation_line() 782 delay_seconds = self.delay_seconds_between_audio_ended_and_show_next 783 apply_delay = delay and self.is_audio_activated and delay_seconds > 0 784 self._stop_playing_audio() 785 if next_line: 786 if apply_delay: 787 self.next_conversation_tasklet = call_after_wallclocktime_delay(self._show_content, delay_seconds, next_line, play_incoming_transmission_sound) 788 else: 789 self._show_content(next_line, play_incoming_transmission_sound) 790 return 791 self.close_on_conversation_end(apply_delay, delay_seconds) 792 self.showing_next = False 793 794 def show_previous_conversation(self): 795 if self.showing_next: 796 return 797 self.showing_next = True 798 self.kill_next_conversation_tasklet() 799 if not self._conversation_svc.are_any_previous_conversation_lines_available(): 800 return 801 self._stop_playing_audio() 802 previous_line = self._conversation_svc.get_previous_conversation_line() 803 self._show_content(previous_line) 804 805 def kill_next_conversation_tasklet(self): 806 if self.next_conversation_tasklet: 807 self.next_conversation_tasklet.Kill() 808 self.next_conversation_tasklet = None 809 if not self._conversation_svc.are_any_previous_conversation_lines_available(): 810 return 811 self._conversation_svc.get_previous_conversation_line() 812 813 def close_on_conversation_end(self, apply_delay, delay_seconds): 814 is_audio_active = self.is_audio_activated 815 should_close_on_audio_end_with_delay = is_audio_active and self.close_on_audio_end and apply_delay 816 should_close_on_audio_end_with_no_delay = is_audio_active and self.close_on_audio_end and not apply_delay 817 if should_close_on_audio_end_with_delay: 818 call_after_wallclocktime_delay(self._close_if_open, delay_seconds) 819 elif should_close_on_audio_end_with_no_delay or not is_audio_active: 820 self._close_if_open() 821 822 def _close_if_open(self): 823 self.CloseIfOpen() 824 825 def _show_content(self, next_line, play_incoming_transmission_sound = False, play_audio = True): 826 if self.destroyed: 827 return 828 self.next_conversation_tasklet = None 829 self._is_portrait_loaded = False 830 self.text = next_line.get_text() 831 self.hints = next_line.hints 832 sound_id = next_line.sound_id 833 agent_id = next_line.agent_id 834 self.current_agent_id = agent_id 835 self.current_line = next_line 836 agent_data = self._conversation_svc.get_agent(agent_id) 837 agent_name = GetByMessageID(agent_data.name) 838 previous_style = self.style 839 new_style = self._get_style_by_agent_id(agent_id) 840 style_changed = previous_style != new_style 841 if style_changed: 842 self.style = new_style 843 self.current_sound_id = sound_id 844 if play_audio: 845 self._start_playing_audio() 846 self._load_portrait(agent_data, next_line) 847 self._load_title(agent_name) 848 self._clear_navigation_buttons() 849 self._clear_completed_ui() 850 expand = self._get_expand_setting() 851 self._show_expanded_content(expand) 852 self._load_navigation_buttons() 853 self._load_completed_ui() 854 self._correct_height(style_changed) 855 uthread.new(self.animate_text_portrait_in) 856 self.showing_next = False 857 858 def _get_expand_setting(self): 859 if not self.is_content_expandable or not self.is_audio_activated: 860 return True 861 manual_expanded_setting = settings.char.ui.Get(SETTING_CONVERSATION_WINDOW_TEXT_EXPAND, None) 862 if manual_expanded_setting is not None: 863 return manual_expanded_setting 864 return self._should_expand_content() 865 866 def _show_expanded_content(self, expand): 867 self._load_expand_option_sprite(expand) 868 self._load_title_line(expand) 869 self._load_text(expand) 870 self._load_hints(expand) 871 872 def _get_style_by_agent_id(self, agent_id): 873 return AGENT_ID_TO_STYLE.get(agent_id, self.default_style) 874 875 def _apply_style(self): 876 self.style_line(self.title_line) 877 self.style_line(self.hints_line) 878 is_transparent = self.style.style_color is not None 879 self.style_window_transparency(is_transparent) 880 881 def style_line(self, line): 882 if line: 883 line.SetFixedColor(self.style.style_color) 884 line.opacity = TITLE_LINE_OPACITY 885 886 def style_window_transparency(self, is_transparent): 887 pass 888 889 def Prepare_Background_(self): 890 self.sr.underlay = ConversationWindowUnderlay(name='styledBackgroundsContainer', parent=self, align=uiconst.TOALL, state=uiconst.UI_DISABLED) 891 892 def style_backgrounds(self): 893 if not self.style: 894 return 895 self.sr.underlay.ApplyStyle(self.style) 896 897 def close_window(self): 898 self._stop_playing_audio() 899 AnimatedTransmissionWindow.close_window(self) 900 901 def Close(self, *args, **kwargs): 902 if self.agent_portrait_intro_3d_container is not None: 903 self.agent_portrait_intro_3d_container.avatarscenecontainer.Close() 904 self._stop_playing_audio() 905 self._audio_svc.UnsubscribeFromEventCallback(self._on_sound_event_completed) 906 AnimatedTransmissionWindow.Close(self, *args, **kwargs) 907 908 def CloseByUser(self, *args, **kwargs): 909 should_close = self.show_warning_on_first_close() 910 if not should_close: 911 return 912 if not self.destroyed: 913 AnimatedTransmissionWindow.CloseByUser(self, *args) 914 915 def Minimize(self, *args, **kwargs): 916 if self.is_neocom_hidden(): 917 return 918 if self.agent_portrait_intro_3d_container is not None and self.agent_portrait_intro_3d_container.avatarscenecontainer.context is not None: 919 self.agent_portrait_intro_3d_container.avatarscenecontainer.FadeOutOpacity(duration=0.5) 920 self.agent_portrait_intro_3d_container.avatarscenecontainer.context.StopAudio() 921 self.agent_portrait_intro_3d_container.avatarscenecontainer.context.SetMinimized() 922 self._stop_playing_audio() 923 self._audio_svc.UnsubscribeFromEventCallback(self._on_sound_event_completed) 924 super(ConversationWindow, self).Minimize(*args, **kwargs) 925 self.notify_of_minimization() 926 927 def Maximize(self, *args, **kwargs): 928 if self.agent_portrait_intro_3d_container is not None: 929 self.agent_portrait_intro_3d_container.avatarscenecontainer.opacity = 0.0 930 self._audio_svc.SubscribeToEventCallback(self._on_sound_event_completed) 931 self._start_playing_audio() 932 super(ConversationWindow, self).Maximize(*args, **kwargs) 933 self._correct_height(style_changed=False) 934 self.notify_of_maximization() 935 if self.agent_portrait_intro_3d_container is not None and self.agent_portrait_intro_3d_container.avatarscenecontainer.context is not None: 936 self.agent_portrait_intro_3d_container.avatarscenecontainer.context.SetMaximized() 937 self.agent_portrait_intro_3d_container.avatarscenecontainer.Reload(self.sound_start_time) 938 939 def notify_of_open(self): 940 if self.conversation_id is not None: 941 self._conversation_svc.notify_of_conversation_start(self.conversation_id) 942 943 def notify_of_close(self): 944 if self.conversation_id is not None: 945 self._conversation_svc.clear_conversation(self.conversation_id) 946 947 def notify_of_minimization(self): 948 if self.conversation_id is not None: 949 self._conversation_svc.notify_of_conversation_minimized(self.conversation_id) 950 951 def notify_of_maximization(self): 952 if self.conversation_id is not None: 953 self._conversation_svc.notify_of_conversation_maximized(self.conversation_id) 954 955 def show_warning_on_first_close(self): 956 if self.destroyed: 957 return False 958 if not self.show_warning_on_first_close_setting or not self.show_warning_on_first_close_dialog: 959 return True 960 have_conversations_ever_been_closed = settings.char.ui.Get(self.show_warning_on_first_close_setting, False) 961 if have_conversations_ever_been_closed: 962 return True 963 prompt_player_fsd_dialog(self.show_warning_on_first_close_dialog) 964 settings.char.ui.Set(self.show_warning_on_first_close_setting, True) 965 return True 966 967 def OnUIScalingChange(self, *args): 968 if self.destroyed: 969 return 970 if self.agent_portrait_intro_3d_container is not None: 971 self.agent_portrait_intro_3d_container.avatarscenecontainer.Reload()