NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

videowindow.py (24357B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\videowindow.py
      2 import logging
      3 import math
      4 import uthread2
      5 from carbonui import const as uiconst
      6 from carbonui.control.slider import Slider
      7 from carbonui.primitives.container import Container
      8 from carbonui.primitives.containerAutoSize import ContainerAutoSize
      9 from carbonui.primitives.fill import Fill
     10 from carbonui.primitives.sprite import StreamingVideoSprite, Sprite
     11 from carbonui.uianimations import animations
     12 from carbonui.uicore import uicore
     13 from carbonui.util.color import Color
     14 from eve.client.script.ui import eveColor
     15 from carbonui.control.buttonIcon import ButtonIcon
     16 from eve.client.script.ui.control.eveLabel import EveLabelMedium, EveCaptionMedium
     17 from carbonui.control.window import Window
     18 from eve.client.script.ui.control.simpleTextTooltip import SimpleTextTooltip
     19 from eve.client.script.ui.shared.subtitles import Subtitles
     20 from eve.common.lib import appConst
     21 from localization import GetByLabel
     22 from localization.formatters import FormatTimeIntervalShort, TIME_CATEGORY_HOUR, TIME_CATEGORY_SECOND
     23 SUBTITLE_BG_COLOR = (0.15,
     24  0.15,
     25  0.15,
     26  0.6)
     27 NANOS_PER_SECOND = 1000000000
     28 logger = logging.getLogger(__name__)
     29 
     30 class VideoPlayerWindow(Window):
     31     default_caption = 'Video'
     32     default_minSize = (500, 400)
     33     default_windowID = 'VideoPlayerWnd'
     34     default_iconNum = 'res:/ui/texture/icons/bigplay_64.png'
     35 
     36     def ApplyAttributes(self, attributes):
     37         Window.ApplyAttributes(self, attributes)
     38         self.videoPlayer = VideoPlayer(parent=self.sr.main, padding=appConst.defaultPadding)
     39 
     40     def SetVideoPath(self, path, title = None, subtitles = None):
     41         self.SetCaption(title if title is not None else self.default_caption)
     42         self.videoPlayer.SetVideoPath(path, title, subtitles)
     43 
     44     def SetVideoFinishedCallback(self, callback):
     45         self.videoPlayer.SetVideoFinishedCallback(callback)
     46 
     47 
     48 class VideoPlayer(Container):
     49     default_name = 'VideoPlayer'
     50     default_sendAnalytics = False
     51     play_texture_path = 'res:/UI/Texture/classes/agency/helpSection/play_Icon.png'
     52     pause_texture_path = 'res:/UI/Texture/classes/agency/helpSection/pause_Icon.png'
     53     replay_texture_path = 'res:/UI/Texture/classes/agency/helpSection/replay_Icon.png'
     54     volume_texture_path = 'res:/UI/Texture/classes/agency/helpSection/volumeIcon.png'
     55     volume_muted_texture_path = 'res:/UI/Texture/classes/agency/helpSection/muteIcon.png'
     56     next_texture_path = 'res:/UI/Texture/classes/agency/helpSection/next_Icon.png'
     57 
     58     def ApplyAttributes(self, attributes):
     59         super(VideoPlayer, self).ApplyAttributes(attributes)
     60         self._updatePosition = True
     61         self._onFinish = None
     62         self._subtitles = None
     63         self._finished = False
     64         self._isScrubbing = False
     65         self.showSubtitles = True
     66         self.updateThread = None
     67         self.videoSequence = []
     68         self.loops = 0
     69         self.sendAnalytics = attributes.get('sendAnalytics', False)
     70         self.volume = settings.user.ui.Get('videoPlayerVolume', 100)
     71         self.ConstructLayout()
     72         self.layoutAreaParent._OnSizeChange_NoBlock = self.RecalcLayout
     73         self.UpdateLayoutArea()
     74 
     75     def StartUpdateThread(self):
     76         self.updateThread = uthread2.StartTasklet(self._UpdatePosition)
     77 
     78     def ConstructLayout(self):
     79         self.layoutAreaParent = Container(name='layoutAreaParent', parent=self)
     80         self.layoutArea = Container(name='layoutArea', parent=self.layoutAreaParent, align=uiconst.CENTER, state=uiconst.UI_NORMAL, width=100, height=100)
     81         self.layoutArea.OnMouseEnter = self.RevealControls
     82         self.layoutArea.OnMouseExit = self.HideControls
     83         self.ConstructLargePlayButton()
     84         self.ConstructControls()
     85         self.ConstructPausedOverlay()
     86         self.ConstructSubtitleContainer()
     87         self.ConstructVideoSprite()
     88 
     89     def ConstructLargePlayButton(self):
     90         self.largePlayButton = ButtonIcon(name='PlayButtonOverlay', parent=self.layoutArea, align=uiconst.CENTER, iconSize=86, width=86, height=86, texturePath='res:/UI/Texture/classes/agency/helpSection/largePlay_Icon.png', func=self.PlayPauseToggle, state=uiconst.UI_HIDDEN)
     91 
     92     def ConstructPausedOverlay(self):
     93         self.pausedOverlay = Fill(name='pausedOverlay', parent=self.layoutArea, color=(0, 0, 0, 0.25), state=uiconst.UI_HIDDEN)
     94 
     95     def ConstructSubtitleContainer(self):
     96         subtitleCont = Container(parent=self.layoutArea, name='subtitleCont', align=uiconst.TOBOTTOM_NOPUSH, state=uiconst.UI_DISABLED, height=100)
     97         self.subtitleBackground = ContainerAutoSize(name='subtitleBackground', parent=subtitleCont, bgColor=SUBTITLE_BG_COLOR, align=uiconst.CENTER, padding=(-5, 0, -5, 0))
     98         self.subtitleLabel = EveCaptionMedium(parent=self.subtitleBackground, color=Color.WHITE, align=uiconst.CENTER, bold=False, state=uiconst.UI_DISABLED, maxLines=2)
     99 
    100     def RevealControls(self, *args):
    101         if self.controlsContainer.GetOpacity() == 1:
    102             return
    103         animations.FadeIn(self.controlsContainer, duration=0.225, callback=lambda : self.controlsContainer.SetState(uiconst.UI_NORMAL))
    104 
    105     def HideControls(self, *args):
    106         if self.video.isPaused:
    107             return
    108         animations.FadeOut(self.controlsContainer, duration=0.225, callback=lambda : self.controlsContainer.SetState(uiconst.UI_DISABLED))
    109 
    110     def ConstructVideoSprite(self):
    111         self.video = StreamingVideoSprite(parent=self.layoutArea, align=uiconst.TOALL, state=uiconst.UI_DISABLED, sendAnalytics=self.sendAnalytics)
    112         self.video.OnVideoSizeAvailable = self.RecalcLayout
    113         self.video.OnVideoFinished = self._OnVideoFinished
    114         self.video.OnVideoDurationAvailable = self.OnVideoDurationAvailable
    115 
    116     def ConstructControls(self):
    117         self.controlsContainer = ContainerAutoSize(name='controlsContainer', parent=self.layoutArea, align=uiconst.TOBOTTOM_NOPUSH, bgColor=(0.1, 0.1, 0.1, 0.45), opacity=0)
    118         self.ConstructButtonContainer()
    119         self.ConstructControlButtons()
    120         self.ConstructPositionContainer()
    121         self.ConstructTimeLabelContainer()
    122 
    123     def ConstructButtonContainer(self):
    124         self.buttonContainer = Container(name='buttonContainer', parent=self.controlsContainer, align=uiconst.TOBOTTOM, height=24)
    125 
    126     def ConstructControlButtons(self):
    127         if self.videoSequence:
    128             self.previousButton = ButtonIcon(name='previousVideoButton', parent=self.buttonContainer, func=self.PlayPreviousVideoInSequence, align=uiconst.TOLEFT, texturePath=self.next_texture_path, rotation=math.pi, hint=GetByLabel('UI/VideoPlayer/Previous'))
    129             self.ConstructPlayPauseButton()
    130             self.nextButton = ButtonIcon(name='nextVideoButton', parent=self.buttonContainer, func=self.PlayNextVideoInSequence, align=uiconst.TOLEFT, texturePath=self.next_texture_path, hint=GetByLabel('UI/VideoPlayer/Next'))
    131         else:
    132             self.ConstructPlayPauseButton()
    133         self.ConstructVolumeControl()
    134         self.subtitlesBtn = ButtonIcon(parent=self.buttonContainer, func=self.ToggleSubtitles, align=uiconst.TORIGHT, texturePath='res:/ui/texture/icons/73_16_10.png', hint=GetByLabel('UI/VideoPlayer/ToggleSubtitles'))
    135 
    136     def ConstructVolumeControl(self):
    137         volumeControlsContainer = ContainerAutoSize(name='volumeControlsContainer', parent=self.buttonContainer, align=uiconst.TOLEFT)
    138         volumeControlsContainer.OnMouseEnter = self.RevealVolumeSlider
    139         volumeControlsContainer.OnMouseExit = self.HideVolumeSlider
    140         self.muteBtn = ButtonIcon(mame='muteBtn', parent=volumeControlsContainer, func=self.Mute, align=uiconst.TOLEFT, texturePath=self.volume_texture_path, iconSize=24, hint=GetByLabel('UI/VideoPlayer/Mute'))
    141         self.volumeSlider = VideoPlayerVolumeSlider(parent=volumeControlsContainer, width=100, value=self.volume, minValue=0, maxValue=100, startValue=100, showLabel=False, on_dragging=self.SetVolume, align=uiconst.TOLEFT, opacity=0)
    142 
    143     def ConstructPlayPauseButton(self):
    144         self.playPauseBtn = ButtonIcon(name='PlayPauseButton', parent=self.buttonContainer, func=self.PlayPauseToggle, align=uiconst.TOLEFT, texturePath=self.pause_texture_path, iconSize=24, hint=GetByLabel('UI/VideoPlayer/Pause'))
    145 
    146     def ConstructPositionContainer(self):
    147         self.positionContainer = Container(name='positionCont', parent=self.controlsContainer, align=uiconst.TOBOTTOM, height=16, padLeft=9, padRight=9)
    148         self.positionCircle = Sprite(name='positionCircle', parent=self.positionContainer, align=uiconst.TOPLEFT_PROP, height=16, width=16, state=uiconst.UI_HIDDEN, texturePath='res:/UI/Texture/classes/agency/helpSection/timeline_Icon.png')
    149         self.positionCircle.OnClick = self.ApplyVideoPosition
    150         self.positionCircle.OnMouseEnter = self.positionCircle.Show
    151         self.positionCircle.OnMouseDown = self.OnPosContMouseDown
    152         self.positionCircle.OnMouseUp = self.OnPosContMouseUp
    153         self.positionCircle.OnMouseMove = self.Scrub
    154         self.timelineContainer = Container(name='fillContainer', parent=self.positionContainer, height=4, top=4, state=uiconst.UI_NORMAL)
    155         self.timelineContainer.OnClick = self.ApplyVideoPosition
    156         self.timelineContainer.OnMouseMove = self.OnTimelineMouseMove
    157         self.timelineContainer.OnMouseDown = self.OnPosContMouseDown
    158         self.timelineContainer.OnMouseUp = self.OnPosContMouseUp
    159         self.timelineContainer.OnMouseEnter = self.OnPosContMouseEnter
    160         self.timelineContainer.OnMouseExit = self.OnPosContMouseExit
    161         self.timelineContainer.GetTooltipPosition = self.GetTooltipPosition
    162         self.timelineContainer.GetTooltipDelay = self.GetTooltipDelay
    163         self.positionFill = Fill(name='positionFill', parent=self.timelineContainer, align=uiconst.TOPLEFT_PROP, height=8, width=2, state=uiconst.UI_DISABLED, color=Color.WHITE)
    164         self.progressFill = Fill(parent=Container(parent=self.timelineContainer, state=uiconst.UI_DISABLED), name='progressFill', align=uiconst.TOLEFT_PROP, color=(0.1804, 0.5412, 0.6392, 1))
    165         self.downloadedFill = Fill(parent=Container(parent=self.timelineContainer, state=uiconst.UI_DISABLED), name='downloadFill', align=uiconst.TOLEFT_PROP, color=(0.4667, 0.7529, 0.8392, 0.45))
    166         Fill(parent=self.timelineContainer, align=uiconst.TOALL, color=(1.0, 1.0, 1.0, 0.3))
    167 
    168     def ConstructTimeLabelContainer(self):
    169         timeLabelContainer = Container(name='timeLabelContainer', parent=self.controlsContainer, align=uiconst.TOBOTTOM, height=20, padLeft=9, padRight=9)
    170         self.currentTimeLabel = EveLabelMedium(name='currentTimeLabel', parent=timeLabelContainer, align=uiconst.CENTERLEFT)
    171         self.totalDurationLabel = EveLabelMedium(name='totalDurationLabel', parent=timeLabelContainer, align=uiconst.CENTERRIGHT)
    172 
    173     def Reset(self):
    174         self.progressFill.width = 0
    175         self.downloadedFill.width = 0
    176         self.playPauseBtn.SetTexturePath(self.pause_texture_path)
    177         self.playPauseBtn.SetHint(GetByLabel('UI/VideoPlayer/Pause'))
    178         self.muteBtn.SetTexturePath(self.volume_texture_path)
    179         self.muteBtn.SetHint(GetByLabel('UI/VideoPlayer/Mute'))
    180         self.largePlayButton.SetState(uiconst.UI_HIDDEN)
    181         self.volumeSlider.SetValue(self.volume)
    182 
    183     def RevealVolumeSlider(self, *args):
    184         animations.FadeIn(self.volumeSlider, duration=0.225)
    185 
    186     def HideVolumeSlider(self, *args):
    187         animations.FadeOut(self.volumeSlider, duration=0.225)
    188 
    189     def OnPosContMouseUp(self, *args):
    190         self._isScrubbing = False
    191 
    192     def OnPosContMouseDown(self, *args):
    193         self._isScrubbing = True
    194 
    195     def GetTooltipPosition(self):
    196         x, y = self.timelineContainer.GetAbsolutePosition()
    197         return (int(uicore.uilib.x * uicore.desktop.dpiScaling),
    198          y,
    199          0,
    200          0)
    201 
    202     def OnPosContMouseEnter(self, *args):
    203         self.positionCircle.Show()
    204         self.timelineContainer.tooltipPanelClassInfo = SimpleTextTooltip(text=self.GetFormattedVideoTimeFromMousePosition(), margin=4)
    205 
    206     def OnTimelineMouseMove(self, *args):
    207         if self.timelineContainer.tooltipPanelClassInfo:
    208             self.UpdateVideoTimeTooltip()
    209         self.Scrub()
    210 
    211     def Scrub(self, *args):
    212         if self._isScrubbing:
    213             self.ApplyVideoPosition()
    214 
    215     def OnPosContMouseExit(self, *args):
    216         if self._isScrubbing:
    217             return
    218         self.positionCircle.Hide()
    219 
    220     def GetTooltipDelay(self):
    221         return 0
    222 
    223     def UpdateVideoTimeTooltip(self):
    224         self.UpdateVideoTimeTooltipPosition()
    225         self.UpdateVideoTimeTooltipText()
    226 
    227     def UpdateVideoTimeTooltipText(self):
    228         if not self.timelineContainer.tooltipPanelClassInfo.textLabel:
    229             return
    230         currentTime = self.GetFormattedVideoTimeFromMousePosition()
    231         self.timelineContainer.tooltipPanelClassInfo.textLabel.SetText(currentTime)
    232 
    233     def GetFormattedVideoTimeFromMousePosition(self):
    234         nanoseconds = self.GetVideoTimeFromMousePosition()
    235         seconds_in_video = int(nanoseconds / NANOS_PER_SECOND)
    236         currentTime = FormatTimeIntervalShort(seconds_in_video * appConst.SEC, showFrom=TIME_CATEGORY_HOUR, showTo=TIME_CATEGORY_SECOND)
    237         return currentTime
    238 
    239     def UpdateVideoTimeTooltipPosition(self):
    240         if not self.timelineContainer.tooltipPanelClassInfo.tooltipPanel:
    241             return
    242         l, t, w, h = self.GetTooltipPosition()
    243         t -= self.timelineContainer.tooltipPanelClassInfo.tooltipPanel.height + 9
    244         l -= self.timelineContainer.tooltipPanelClassInfo.tooltipPanel.width / 2
    245         self.timelineContainer.tooltipPanelClassInfo.tooltipPanel.SetPosition(l, t)
    246 
    247     def GetVideoTimeFromMousePosition(self):
    248         l, t, w, h = self.timelineContainer.GetAbsolute()
    249         try:
    250             x = (uicore.uilib.x - l) / float(w)
    251         except ZeroDivisionError:
    252             x = 0.0
    253 
    254         if x >= 1.0:
    255             return 1.0
    256         x = max(0.0, x)
    257         x = int(x * self.video.duration)
    258         return x
    259 
    260     def ApplyVideoPosition(self):
    261         nanoseconds = self.GetVideoTimeFromMousePosition()
    262         self.video.Seek(nanoseconds)
    263 
    264     def SetVideoFinishedCallback(self, callback):
    265         self._onFinish = callback
    266 
    267     def _OnVideoFinished(self):
    268         self._finished = True
    269         self.playPauseBtn.SetTexturePath(self.replay_texture_path)
    270         self.playPauseBtn.SetHint(GetByLabel('UI/VideoPlayer/Replay'))
    271         self._updatePosition = False
    272         if self._onFinish is not None:
    273             self._onFinish()
    274         self.updateThread.kill()
    275 
    276     def SetVideoSequence(self, videoPaths):
    277         if not videoPaths:
    278             return
    279         self.videoSequence = list(videoPaths)
    280         self.buttonContainer.Flush()
    281         self.ConstructControlButtons()
    282         self.UpdateNextPreviousButtons()
    283         self.subtitleLabel.text = ''
    284 
    285     def ClearVideoSequence(self):
    286         self.videoSequence = []
    287         self.buttonContainer.Flush()
    288         self.ConstructControlButtons()
    289         self.UpdateNextPreviousButtons()
    290         self.subtitleLabel.text = ''
    291 
    292     def UpdateNextPreviousButtons(self, videoIndexInSequence = None):
    293         if not self.video.path:
    294             return
    295         if not videoIndexInSequence:
    296             videoIndexInSequence = self.videoSequence.index(self.video.path)
    297         if videoIndexInSequence == len(self.videoSequence) - 1:
    298             self.nextButton.Disable()
    299         elif videoIndexInSequence == 0:
    300             self.previousButton.Disable()
    301 
    302     def PlayNextVideoInSequence(self):
    303         try:
    304             nextIndex = self.videoSequence.index(self.video.path) + 1
    305         except ValueError:
    306             logger.warn('Video Player: Unable to play next video in sequence', exc_info=True)
    307             return
    308 
    309         if nextIndex > len(self.videoSequence) - 1:
    310             return
    311         self.SetVideoPath(self.videoSequence[nextIndex], *self._replayArgs[1:])
    312         self.OnNextButtonClicked()
    313         if not self.previousButton.enabled:
    314             self.previousButton.Enable()
    315         self.UpdateNextPreviousButtons(nextIndex)
    316 
    317     def OnNextButtonClicked(self):
    318         pass
    319 
    320     def PlayPreviousVideoInSequence(self):
    321         try:
    322             prevIndex = self.videoSequence.index(self.video.path) - 1
    323         except ValueError:
    324             logger.warn('Video Player: Unable to play previous video in sequence', exc_info=True)
    325             return
    326 
    327         if prevIndex < 0:
    328             return
    329         self.SetVideoPath(self.videoSequence[prevIndex], *self._replayArgs[1:])
    330         self.OnPreviousButtonClicked()
    331         if not self.nextButton.enabled:
    332             self.nextButton.Enable()
    333         self.UpdateNextPreviousButtons(prevIndex)
    334 
    335     def OnPreviousButtonClicked(self):
    336         pass
    337 
    338     def SetVideoPath(self, path, title = None, subtitles = None, videoLoop = False):
    339         if self.video and path == self.video.path:
    340             return
    341         self.Reset()
    342         self.video.SetVideoPath(path, videoLoop=videoLoop)
    343         self.video.SetVolume(float(self.volume) / 100.0)
    344         self._finished = False
    345         self._replayArgs = (path,
    346          title,
    347          subtitles,
    348          videoLoop)
    349         subtitleText = None
    350         if subtitles is None:
    351             self._subtitles = None
    352         else:
    353             self._subtitles = Subtitles()
    354             subtitleText = self._subtitles.LoadSubtitleFile(subtitles)
    355         if not subtitleText:
    356             self.subtitleBackground.Hide()
    357             self._subtitles = None
    358         else:
    359             self._subtitles.PrepareSubtitles(subtitleText)
    360             self.subtitleBackground.Show()
    361         self.StartUpdateThread()
    362 
    363     def OnVideoDurationAvailable(self):
    364         self.UpdateDurationLabel()
    365 
    366     def UpdateDurationLabel(self):
    367         if not self.video or not self.video.duration:
    368             return
    369         seconds_in_video = self.video.duration / NANOS_PER_SECOND
    370         totalDuration = FormatTimeIntervalShort(seconds_in_video * appConst.SEC, showFrom=TIME_CATEGORY_HOUR, showTo=TIME_CATEGORY_SECOND)
    371         self.totalDurationLabel.SetText(totalDuration)
    372 
    373     def UpdateCurrentTimeLabel(self):
    374         if not self.video or not self.video.mediaTime:
    375             return
    376         currentTime = self.GetVideoCurrentTime()
    377         self.currentTimeLabel.SetText(currentTime)
    378 
    379     def GetVideoCurrentTime(self):
    380         seconds_in_video = self.video.mediaTime % self.video.duration / NANOS_PER_SECOND
    381         currentTime = FormatTimeIntervalShort(seconds_in_video * appConst.SEC, showFrom=TIME_CATEGORY_HOUR, showTo=TIME_CATEGORY_SECOND)
    382         return currentTime
    383 
    384     def Close(self, *args, **kwds):
    385         self._updatePosition = False
    386         self.video = None
    387         if self.updateThread:
    388             self.updateThread.kill()
    389         super(VideoPlayer, self).Close()
    390 
    391     def _UpdatePosition(self):
    392         while self._updatePosition:
    393             if self.video:
    394                 mediaTime = self.video.GetPositionRatioInVideo()
    395                 self.UpdateCurrentTimeLabel()
    396                 if mediaTime == 0:
    397                     self.progressFill.Hide()
    398                 else:
    399                     self.progressFill.Show()
    400                     self.progressFill.width = mediaTime
    401                     self.positionCircle.left = mediaTime
    402                     self.positionFill.left = mediaTime
    403                 duration = float((self.video.duration or 1) / 1000000)
    404                 if duration == 0:
    405                     duration = 1
    406                 downloadedTime = min(float((self.video.downloadedTime or 0) / 1000000) / duration, 1)
    407                 if downloadedTime == 0:
    408                     self.downloadedFill.Hide()
    409                 else:
    410                     self.downloadedFill.Show()
    411                     self.downloadedFill.width = downloadedTime
    412                 self._UpdateSubtitles()
    413             uthread2.Sleep(0.1)
    414 
    415     def _UpdateSubtitles(self):
    416         if self._subtitles is None or not self.showSubtitles:
    417             return
    418         currentTime = self.video.mediaTime or 0
    419         currentTime /= 1000000
    420         text = self._subtitles.GetSubtitle(currentTime)
    421         self.subtitleLabel.maxWidth = self.displayWidth - 50
    422         if text:
    423             self.subtitleLabel.SetText(text)
    424 
    425     def UpdateLayoutArea(self):
    426         size = self.video.GetVideoSize()
    427         if not size:
    428             return
    429         areaWidth, areaHeight = self.layoutAreaParent.GetAbsoluteSize()
    430         xFitScale = areaWidth / float(size[0])
    431         yFitScale = areaHeight / float(size[1])
    432         scaling = min(xFitScale, yFitScale)
    433         self.layoutArea.width = int(size[0] * scaling)
    434         self.layoutArea.height = int(size[1] * scaling)
    435 
    436     def RecalcLayout(self, *args):
    437         self.UpdateLayoutArea()
    438 
    439     def PlayPauseToggle(self, *args):
    440         if self._finished:
    441             self.Replay()
    442         elif self.video.isPaused:
    443             self.Play()
    444         else:
    445             self.Pause()
    446 
    447     def Play(self):
    448         self.video.Play()
    449         self.controlsContainer.SetOpacity(1.0)
    450         self.largePlayButton.SetState(uiconst.UI_HIDDEN)
    451         self.playPauseBtn.SetTexturePath(self.pause_texture_path)
    452         self.playPauseBtn.SetHint(GetByLabel('UI/VideoPlayer/Pause'))
    453         self.pausedOverlay.SetState(uiconst.UI_HIDDEN)
    454 
    455     def Pause(self):
    456         self.video.Pause()
    457         self.largePlayButton.SetState(uiconst.UI_NORMAL)
    458         self.playPauseBtn.SetTexturePath(self.play_texture_path)
    459         self.playPauseBtn.SetHint(GetByLabel('UI/VideoPlayer/Play'))
    460         self.pausedOverlay.SetState(uiconst.UI_NORMAL)
    461 
    462     def Replay(self):
    463         self._finished = False
    464         self.SetVideoPath(*self._replayArgs)
    465         self.Play()
    466 
    467     def Mute(self, *args):
    468         if self.video.isMuted:
    469             self.video.UnmuteAudio()
    470             self.volumeSlider.SetValue(self.volume)
    471             self.muteBtn.SetTexturePath(self.volume_texture_path)
    472             self.muteBtn.SetHint(GetByLabel('UI/VideoPlayer/Mute'))
    473         else:
    474             self.video.MuteAudio()
    475             self.volumeSlider.SetValue(0)
    476             self.muteBtn.SetTexturePath(self.volume_muted_texture_path)
    477             self.muteBtn.SetHint(GetByLabel('UI/VideoPlayer/Unmute'))
    478 
    479     def SetVolume(self, slider):
    480         self.video.SetVolume(float(slider.value) / 100.0)
    481         self.volume = slider.value
    482         settings.user.ui.Set('videoPlayerVolume', self.volume)
    483         if self.volume:
    484             self.muteBtn.SetTexturePath(self.volume_texture_path)
    485             self.muteBtn.SetHint(GetByLabel('UI/VideoPlayer/Mute'))
    486 
    487     def ToggleSubtitles(self):
    488         self.showSubtitles = not self.showSubtitles
    489         if self.showSubtitles:
    490             self.subtitlesBtn.opacity = 1.0
    491             self.subtitleLabel.Show()
    492             self.subtitleBackground.Show()
    493         else:
    494             self.subtitlesBtn.opacity = 0.2
    495             self.subtitleLabel.Hide()
    496             self.subtitleBackground.Hide()
    497 
    498 
    499 class VideoPlayerVolumeSlider(Slider):
    500     default_name = 'VideoPlayerVolumeSlider'
    501 
    502     def ApplyAttributes(self, attributes):
    503         super(VideoPlayerVolumeSlider, self).ApplyAttributes(attributes)
    504         self.callback.connect(self.UpdateFillWidth)
    505         self.on_dragging.connect(self.UpdateFillWidth)
    506         self.UpdateFillWidth()
    507 
    508     def _ConstructHandle(self):
    509         super(VideoPlayerVolumeSlider, self)._ConstructHandle()
    510 
    511     def _ConstructBackground(self):
    512         volumeFillContainer = Container(parent=self, align=uiconst.CENTER, height=self.barHeight / 2, width=self.width)
    513         Fill(name='backgroundFill', bgParent=volumeFillContainer, color=Color.GRAY5, opacity=0.25)
    514         self.volumeFill = Fill(parent=volumeFillContainer, align=uiconst.TOLEFT_PROP, width=0.0, color=Color.WHITE)
    515 
    516     def _ConstructBarCont(self):
    517         self.barCont = Container(parent=self, name='barCont', align=uiconst.CENTER, state=uiconst.UI_NORMAL, height=self.barHeight + 10, width=self.width)
    518         self.barCont.OnClick = self.OnSliderClicked
    519         self.barCont.OnMouseMove = self.OnSliderMouseMove
    520         self.barCont.OnMouseExit = self.OnMouseBarExit
    521         self.barCont.OnMouseWheel = self.OnMouseWheel
    522         self.barCont.GetHint = self.GetHint
    523 
    524     def UpdateFillWidth(self, *args):
    525         self.volumeFill.width = self.value / 100
    526 
    527     def OnHandleMouseEnter(self, *args):
    528         pass
    529 
    530     def OnHandleMouseExit(self, *args):
    531         pass