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

subcellularatlas.py (20020B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\projectdiscovery\client\projects\subcellular\subcellularatlas.py
      2 from __future__ import absolute_import
      3 import logging
      4 import math
      5 import blue
      6 import carbonui.const as uiconst
      7 import localization
      8 import uthread
      9 from carbonui.primitives.container import Container
     10 from carbonui.primitives.sprite import Sprite
     11 from carbonui.primitives.transform import Transform
     12 from carbonui.uianimations import animations
     13 from .categoryselector import CategorySelector
     14 from eve.common.lib.appConst import MSEC
     15 from eve.client.script.ui.control import eveLabel, themeColored
     16 from carbonui.control.buttonIcon import ButtonIcon
     17 from carbonui.control.button import Button
     18 from carbonui.control.checkbox import Checkbox
     19 from eve.client.script.ui.control.eveLoadingWheel import LoadingWheel
     20 from eve.client.script.ui.tooltips.tooltipUtil import SetTooltipHeaderAndDescription
     21 from gametime import GetWallclockTime, GetTimeDiff
     22 from .info import INFO as PROJECT_INFO
     23 from projectdiscovery.client import const
     24 from projectdiscovery.client.projects.subcellular import nested_categories_from_json
     25 from projectdiscovery.client.projects.subcellular.processingview import ProcessingView
     26 from projectdiscovery.client.projects.subcellular.resultwindow import ResultWindow
     27 from projectdiscovery.client.projects.subcellular.rewardsview import RewardsView
     28 from projectdiscovery.client.projects.subcellular.taskimages import TaskImage
     29 from projectdiscovery.client.util.dialogue import Dialogue
     30 from projectdiscovery.client.util.eventlistener import eventlistener, on_event
     31 from projectdiscovery.common.exceptions import MissingKeyError, NoConnectionToAPIError
     32 logger = logging.getLogger(__name__)
     33 RESULT_TIME_OUT = 10
     34 
     35 @eventlistener()
     36 
     37 class SubcellularAtlas(Container):
     38     MAX_CATEGORIES = PROJECT_INFO['resultSchema']['maxItems'] - 1
     39 
     40     def ApplyAttributes(self, attributes):
     41         super(SubcellularAtlas, self).ApplyAttributes(attributes)
     42         self.task_time = None
     43         self.selection = []
     44         self.tutorial = None
     45         self.service = sm.RemoteSvc('ProjectDiscovery')
     46         self.submitting = False
     47         self.playerState = attributes.get('playerState')
     48         self.starting_scale = attributes.get('starting_scale')
     49         self.bottom_container = self.parent.parent.FindChild('bottom_container')
     50         self.clipChildren = True
     51         self.result = None
     52         self.getting_new_task = False
     53         self.setup_layout()
     54 
     55     def setup_layout(self):
     56         self.dialogue_container = Container(name='dialogue_container', parent=self.parent, idx=0)
     57         self.left_main_container = Container(name='left_main_container', parent=self, align=uiconst.TOLEFT_PROP, width=0.5, clipChildren=True, top=20)
     58         self.category_container = Container(name='category_container', parent=self, align=uiconst.TOLEFT_PROP, width=0.5, padTop=45, clipChildren=True)
     59         self.loading_container = Container(name='loadingContainer', parent=self.category_container, align=uiconst.CENTER, width=100, height=100, state=uiconst.UI_HIDDEN)
     60         self.loading_result_label = themeColored.LabelThemeColored(name='loadingResultLabel', parent=self.loading_container, align=uiconst.CENTERTOP, text=localization.GetByLabel('UI/ProjectDiscovery/LoadingResultLabel'), fontsize=20)
     61         self.loading_wheel = LoadingWheel(name='ResultLoadingIndicator', parent=self.loading_container, align=uiconst.CENTER, width=64, height=64)
     62         self.error_container = Container(parent=self.category_container, align=uiconst.CENTER, width=100, height=100, state=uiconst.UI_HIDDEN)
     63         self.error_label = themeColored.LabelThemeColored(parent=self.error_container, align=uiconst.CENTERTOP, text=localization.GetByLabel('UI/ProjectDiscovery/LoadingResultErrorLabel'), fontsize=20)
     64         self.task_label = themeColored.LabelThemeColored(parent=self.left_main_container, align=uiconst.CENTERTOP, text=localization.GetByLabel('UI/ProjectDiscovery/TaskLabel'), top=40, fontsize=28, opacity=1)
     65         self.task_image = TaskImage(label=const.Texts.TaskImageLabel, parent=self.left_main_container, align=uiconst.TOPLEFT_PROP, pos=(25, 80, 420, 445), starting_scale=self.starting_scale)
     66         self.checkbox_container = Container(name='checkboxContainer', parent=self.task_image, align=uiconst.BOTTOMLEFT, width=110, height=20, left=8, top=10)
     67         self.report_checkbox = Checkbox(name='reportCheckbox', parent=self.checkbox_container, text=localization.GetByLabel('UI/ProjectDiscovery/ReportCheckboxLabel'))
     68         SetTooltipHeaderAndDescription(self.report_checkbox, headerText=localization.GetByLabel('UI/ProjectDiscovery/AbnormalSampleTooltipHeader'), descriptionText=localization.GetByLabel('UI/ProjectDiscovery/AbnormalSampleTooltipDescription'))
     69         self.result_window = ResultWindow(name='ResultWindow', parent=self.parent, align=uiconst.TOALL, opacity=0, isTrainingPhase=False, starting_scale=self.starting_scale, bottom_container=self.bottom_container)
     70         self.rewards_view = RewardsView(parent=self.parent.parent, opacity=0, align=uiconst.TOALL, playerState=self.playerState, bottom_container=self.bottom_container, idx=1, state=uiconst.UI_DISABLED)
     71         self.processing_view = ProcessingView(parent=self.parent.parent, opacity=0, idx=2, state=uiconst.UI_DISABLED)
     72         self.category_selector = CategorySelector(categories=nested_categories_from_json(PROJECT_INFO['info']['classes']), parent=self.category_container, state=uiconst.UI_DISABLED, starting_scale=self.starting_scale)
     73         self.main_button_container = Container(name='main_button_container', parent=self.bottom_container, align=uiconst.CENTERBOTTOM, width=355, height=53, bgTexturePath='res:/UI/Texture/classes/ProjectDiscovery/footerBG.png')
     74         self.submit_button_container = Container(name='submitButtonContainer', parent=self.main_button_container, width=250, align=uiconst.CENTER, height=40, top=5)
     75         self.submit_button = Button(name='SubcellularSubmitButton', parent=self.submit_button_container, align=uiconst.CENTER, label=localization.GetByLabel('UI/ProjectDiscovery/SubmitButtonLabel'), fontsize=18, fixedwidth=170, fixedheight=30, func=lambda x: self.submit_solution())
     76         Sprite(parent=self.submit_button_container, align=uiconst.CENTERLEFT, width=34, height=20, texturePath='res:/UI/Texture/classes/ProjectDiscovery/submitArrow.png', opacity=0.7)
     77         Sprite(parent=Transform(parent=self.submit_button_container, align=uiconst.CENTERRIGHT, width=34, height=20, rotation=math.pi), align=uiconst.CENTERRIGHT, width=34, height=20, texturePath='res:/UI/Texture/classes/ProjectDiscovery/submitArrow.png', opacity=0.7)
     78         self.task_id = eveLabel.Label(name='TaskID', parent=self.bottom_container, align=uiconst.BOTTOMRIGHT, height=20, opacity=0, left=10)
     79         self.new_task_button = ButtonIcon(name='newTaskButton', parent=self.left_main_container, align=uiconst.TOPLEFT, texturePath='res:/UI/Texture/classes/ProjectDiscovery/recycleButtonUp.png', hoverTexture='res:/UI/Texture/classes/ProjectDiscovery/recycleButtonOver.png', downTexture='res:/UI/Texture/classes/ProjectDiscovery/recycleButtonDown.png', iconSize=24, func=lambda : self.reset_and_get_new_task(), idx=0, left=32, top=54)
     80         SetTooltipHeaderAndDescription(self.new_task_button, headerText='', descriptionText=localization.GetByLabel('UI/ProjectDiscovery/NewTaskButtonTooltipDescription'))
     81 
     82     def start(self, show_dialogue):
     83         if show_dialogue:
     84             self.disable_ui()
     85             Dialogue(name='finishedTutorialDialogue', parent=self.dialogue_container, align=uiconst.CENTER, width=450, height=330, messageText=localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/FinishedMessage'), messageHeaderText=localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/FinishedHeader'), label=localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/GreetingLabel'), buttonLabel=localization.GetByLabel('UI/ProjectDiscovery/ErrorButton'), toHide=self)
     86         uthread.new(self.get_new_task)
     87 
     88     def close(self):
     89         self.task_image.reset_image()
     90         self.rewards_view.close()
     91         self.result_window.kill()
     92         self.processing_view.Close()
     93         self.main_button_container.Close()
     94         self.dialogue_container.Close()
     95         self.task_id.Close()
     96         self.Close()
     97 
     98     @on_event(const.Events.ResetAndGetNewTask)
     99     def reset_and_get_new_task(self):
    100         self.category_selector.reset_categories()
    101         self.enable_ui()
    102         self.category_selector.state = uiconst.UI_DISABLED
    103         self.task_image.reset_image()
    104         self.get_new_task()
    105 
    106     def get_new_task(self):
    107         if self.getting_new_task:
    108             return
    109         self.getting_new_task = True
    110         self.selection = []
    111         try:
    112             self.task = self.service.get_new_task()
    113         except (MissingKeyError, NoConnectionToAPIError):
    114             self.open_task_retrieval_error_dialogue()
    115             return
    116 
    117         sm.ScatterEvent(const.Events.NewTask, self.task)
    118         self.task_time = GetWallclockTime()
    119         self.task_id.SetAlpha(0)
    120         self.task_id.SetText(self.task['taskId'])
    121         settings.char.ui.Set('UpdateAccInfo', True)
    122 
    123     @on_event(const.Events.MainImageLoaded)
    124     def set_getting_new_task_to_false(self):
    125         if self.category_selector:
    126             self.category_selector.state = uiconst.UI_NORMAL
    127         self.getting_new_task = False
    128 
    129     def _update_excluded(self, excluder):
    130         excluded = set()
    131         for cat in self.selection:
    132             if '*' in cat.get('excludes'):
    133                 excluded.update(cat.get('excludes', []))
    134             elif 12 in cat.get('excludes', []):
    135                 excludes = list(cat.get('excludes', []))
    136                 excludes.append(121)
    137                 excludes.append(122)
    138                 excludes.append(123)
    139                 excluded.update(excludes, [])
    140             else:
    141                 excluded.update(cat.get('excludes', []))
    142 
    143         sm.ScatterEvent(const.Events.ExcludeCategories, excluder, excluded)
    144 
    145     def open_no_categories_selected_error_dialogue(self):
    146         self.disable_ui()
    147         self.dialogue = Dialogue(name='ErrorDialogue', parent=self.dialogue_container, align=uiconst.CENTER, width=450, height=215, messageText=localization.GetByLabel('UI/ProjectDiscovery/NoCategorySelectedErrorMessage'), messageHeaderText=localization.GetByLabel('UI/ProjectDiscovery/NoCategorySelectedHeader'), label=localization.GetByLabel('UI/ProjectDiscovery/NotificationHeader'), buttonLabel=localization.GetByLabel('UI/ProjectDiscovery/ErrorButton'), toHide=self)
    148 
    149     def open_too_many_categories_selected_dialogue(self):
    150         self.disable_ui()
    151         self.dialogue = Dialogue(name='ErrorDialogue', parent=self.dialogue_container, align=uiconst.CENTER, width=450, height=215, messageText=localization.GetByLabel('UI/ProjectDiscovery/TooManyCategoriesMessage'), messageHeaderText=localization.GetByLabel('UI/ProjectDiscovery/TooManyCategoriesHeader'), label=localization.GetByLabel('UI/ProjectDiscovery/NotificationHeader'), buttonLabel=localization.GetByLabel('UI/ProjectDiscovery/ErrorButton'), toHide=self)
    152 
    153     def open_classification_error_dialogue(self):
    154         self.disable_ui()
    155         self.dialogue = Dialogue(name='ErrorDialogue', parent=self.dialogue_container, align=uiconst.CENTER, width=450, height=215, messageText=localization.GetByLabel('UI/ProjectDiscovery/ClassificationErrorMessage'), messageHeaderText=localization.GetByLabel('UI/ProjectDiscovery/ClassificationErrorHeader'), label=localization.GetByLabel('UI/ProjectDiscovery/NotificationHeader'), buttonLabel=localization.GetByLabel('UI/ProjectDiscovery/ErrorButton'), toHide=self, onCloseEvent=const.Events.RestartWindow)
    156 
    157     def open_task_retrieval_error_dialogue(self):
    158         self.disable_ui()
    159         self.dialogue = Dialogue(name='ErrorDialogue', parent=self.dialogue_container, align=uiconst.CENTER, width=450, height=215, messageText=localization.GetByLabel('UI/ProjectDiscovery/TaskRetrievalErrorMessage'), messageHeaderText=localization.GetByLabel('UI/ProjectDiscovery/TaskRetrievalErrorHeader'), label=localization.GetByLabel('UI/ProjectDiscovery/NotificationHeader'), buttonLabel=localization.GetByLabel('UI/ProjectDiscovery/ErrorButton'), toHide=self, onCloseEvent=const.Events.ResetAndGetNewTask)
    160 
    161     def disable_ui(self):
    162         self.left_main_container.state = uiconst.UI_DISABLED
    163         self.category_container.state = uiconst.UI_DISABLED
    164         self.main_button_container.state = uiconst.UI_DISABLED
    165 
    166     @on_event(const.Events.EnableUI)
    167     def enable_ui(self):
    168         self.task_image.state = uiconst.UI_NORMAL
    169         self.left_main_container.state = uiconst.UI_NORMAL
    170         self.category_container.state = uiconst.UI_NORMAL
    171         self.main_button_container.state = uiconst.UI_NORMAL
    172 
    173     def submit_solution(self):
    174         if self.submitting:
    175             return
    176         if not self.selection:
    177             self.open_no_categories_selected_error_dialogue()
    178             return
    179         sm.GetService('audio').SendUIEvent(const.Sounds.MainImageLoopStop)
    180         sm.ScatterEvent(const.Events.SubmitSolution)
    181         self.disable_ui()
    182         self.submitting = True
    183         self._animate_out()
    184         self.classification = list(set([ cat['id'] for cat in self.selection if not cat['excluded'] ]))
    185         duration = self.get_duration()
    186         try:
    187             self.result = self.service.post_classification(self.task, self.classification, duration, remark=bool(self.report_checkbox.GetValue()))
    188         except:
    189             self.disable_ui()
    190             self.open_classification_error_dialogue()
    191             raise
    192 
    193     def get_duration(self):
    194         duration = GetTimeDiff(self.task_time, GetWallclockTime()) / MSEC
    195         if duration < 0:
    196             duration = 0
    197         return duration
    198 
    199     def _animate_out(self):
    200         animations.FadeOut(self.main_button_container)
    201         animations.FadeOut(self.task_image.colorFilterContainer)
    202         animations.FadeOut(self.task_label)
    203         animations.FadeOut(self.checkbox_container)
    204         animations.FadeOut(self.new_task_button)
    205         self.new_task_button.SetState(uiconst.UI_DISABLED)
    206         uthread.new(self.category_selector.cascade_categories_out)
    207         self.category_selector.state = uiconst.UI_DISABLED
    208         self.task_image.start_transmission_animation()
    209 
    210     @on_event(const.Events.TransmissionFinished)
    211     def prepare_result_screen(self):
    212         self.left_main_container.state = uiconst.UI_NORMAL
    213         animations.FadeIn(self.task_image.colorFilterContainer)
    214         self.result_window.open()
    215         uthread.new(self.wait_for_result)
    216 
    217     def wait_for_result(self):
    218         seconds = 1
    219         while not self.has_result():
    220             self.show_loading()
    221             seconds += 1
    222             if seconds > RESULT_TIME_OUT:
    223                 self.respond_to_result_timeout()
    224                 return
    225             blue.synchro.Sleep(1000)
    226 
    227         self.use_result()
    228 
    229     def respond_to_result_timeout(self):
    230         logger.warning('ProjectDiscovery::wait_for_result: Result took longer than 10 seconds to arrive, giving up.', exc_info=1)
    231         self.show_loading_error()
    232         self.result_window.enable_ui()
    233 
    234     def use_result(self):
    235         self.result['playerSelection'] = self.classification
    236         self.result_window.assign_result(self.result)
    237         if settings.char.ui.Get('loadStatisticsAfterSubmission'):
    238             sm.ScatterEvent('OnUpdateHeader')
    239             settings.char.ui.Set('loadStatisticsAfterSubmission', False)
    240         self.enable_ui()
    241         self.category_container.state = uiconst.UI_DISABLED
    242         self.main_button_container.state = uiconst.UI_DISABLED
    243         self.hide_loading()
    244         self.result_window.show_result()
    245         self.task_id.SetAlpha(0.5)
    246 
    247     def has_result(self):
    248         if self.result:
    249             return True
    250         return False
    251 
    252     def show_loading(self):
    253         self.loading_container.SetState(uiconst.UI_NORMAL)
    254 
    255     def hide_loading(self):
    256         self.loading_container.SetState(uiconst.UI_HIDDEN)
    257 
    258     def show_loading_error(self):
    259         self.hide_loading()
    260         self.error_container.SetState(uiconst.UI_NORMAL)
    261 
    262     def hide_loading_error(self):
    263         self.error_container.SetState(uiconst.UI_HIDDEN)
    264 
    265     def get_tutorial_tooltip_steps(self):
    266         return [{'owner': self.task_image.image_sprite,
    267           'header': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/SampleImageHeader'),
    268           'text': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/SampleImageText')},
    269          {'owner': self.category_selector,
    270           'header': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/CategorySelectionHeader'),
    271           'text': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/CategorySelectionText')},
    272          {'owner': self.category_selector.super_categories[0],
    273           'header': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/NucleusHeader'),
    274           'text': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/NucleusText')},
    275          {'owner': self.category_selector.super_categories[1],
    276           'header': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/CytoplashHeader'),
    277           'text': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/CytoplashText')},
    278          {'owner': self.category_selector.super_categories[2],
    279           'header': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/PeripheryHeader'),
    280           'text': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/PeripheryText')},
    281          {'owner': self.training_category_selector.super_categories[3],
    282           'header': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/MiscellaneousHeader'),
    283           'text': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/MiscellaneousText')},
    284          {'owner': self.training_category_selector.super_categories[4],
    285           'header': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/NotIdentifiableHeader'),
    286           'text': localization.GetByLabel('UI/ProjectDiscovery/Subcellular/Tutorial/NotIdentifiableText')}]
    287 
    288     @on_event(const.Events.CategoryChanged)
    289     def on_category_changed(self, hexagon):
    290         if hexagon.category['selected']:
    291             if len(self.selection) > self.MAX_CATEGORIES:
    292                 hexagon.set_unselected()
    293                 self.open_too_many_categories_selected_dialogue()
    294                 return
    295             self.selection.append(hexagon.category)
    296         elif hexagon.category in self.selection:
    297             self.selection.remove(hexagon.category)
    298         self._update_excluded(hexagon.category['id'])
    299 
    300     @on_event(const.Events.ContinueFromReward)
    301     def on_continue_from_reward(self):
    302         if not self.result:
    303             self.submitting = False
    304             self.task_image.state = uiconst.UI_DISABLED
    305             self.category_selector.reset_categories()
    306         self.category_selector.reset_categories()
    307         self.hide_loading()
    308         self.hide_loading_error()
    309         self.result = None
    310         uthread.new(self.get_new_task)
    311         self.report_checkbox.SetValue(0)
    312         self._animate_in()
    313         self.enable_ui()
    314 
    315     def _animate_in(self):
    316         animations.FadeIn(self, duration=1)
    317         animations.FadeIn(self.main_button_container)
    318         animations.FadeIn(self.task_image.colorFilterContainer)
    319         animations.FadeIn(self.task_label)
    320         animations.FadeIn(self.checkbox_container)
    321         animations.FadeIn(self.new_task_button)
    322         self.new_task_button.SetState(uiconst.UI_NORMAL)
    323         self.category_selector.cascade_categories_in()
    324 
    325     @on_event(const.Events.ContinueFromResult)
    326     def reset_task_image(self):
    327         self.submitting = False
    328         self.task_image.state = uiconst.UI_DISABLED
    329         animations.FadeOut(self, duration=0.4, callback=self.task_image.reset_image)