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

formFieldsMultivalue.py (17266B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\control\forms\formFieldsMultivalue.py
      2 import eveicon
      3 import uthread
      4 from carbonui import Align, uiconst
      5 from carbonui import TextColor
      6 from carbonui.text.styles import TextBody
      7 from carbonui.control.buttonIcon import ButtonIcon
      8 from carbonui.control.combo import Combo
      9 from carbonui.control.comboEntryData import ComboEntryData
     10 from carbonui.control.forms.formFields import BaseField
     11 from carbonui.primitives.container import Sprite, Container
     12 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     13 from carbonui.primitives.frame import Frame
     14 from eveformat.client import solar_system_with_security
     15 from eveui import LocationField, fade, fade_in, ItemField, NpcCorporationField, ShipField, PlayerOrPlayerOrganizationField, fade_out
     16 from eveui.audio import Sound
     17 from eveui.autocomplete import LocationSuggestion, ItemTypeSuggestion, ItemGroupSuggestion, ItemCategorySuggestion, ShipTypeSuggestion, ShipClassSuggestion, OwnerIdentitySuggestion, NpcCorporationSuggestion
     18 from localization import GetByLabel
     19 
     20 class MultiValueFormField(BaseField):
     21 
     22     def ApplyAttributes(self, attributes):
     23         self.edit = None
     24         self._result = list()
     25         self._results_entry = {}
     26         super(MultiValueFormField, self).ApplyAttributes(attributes)
     27 
     28     def ConstructBody(self):
     29         self.ConstructSearchField()
     30         self._results_container = ContainerAutoSize(name='multivalue_results_container', parent=self, align=Align.TOTOP)
     31         for entry in self.component.get_value() or []:
     32             entry = self._parse_entry(entry)
     33             if entry is not None:
     34                 self._initialize_entry(entry)
     35 
     36     def ConstructSearchField(self):
     37         pass
     38 
     39     def _parse_entry(self, entry):
     40         if isinstance(entry, tuple):
     41             _entry_type, entry_value = entry
     42             parsed_entry = entry_value
     43         else:
     44             parsed_entry = entry
     45         return parsed_entry
     46 
     47     def _initialize_entry(self, entry):
     48         self._add_new_entry(entry)
     49 
     50     def _add_entry_chip(self, entry):
     51         self._result.append(entry)
     52         self._sort_results()
     53         chip = MultiValueListItem(idx=self._result.index(entry), parent=self._results_container, entry=entry, get_text=self._get_text, render_icon=self._render_icon, get_menu=self._get_menu, get_drag_data=self._get_drag_data, on_click_remove=self._on_remove_chip)
     54         self._results_entry[entry] = chip
     55 
     56     def _get_label_text(self):
     57         return u'{} <color={}>{}/{}</color>'.format(self.component.label, TextColor.DISABLED, len(self._result), self.component.max_entries)
     58 
     59     def _get_text(self, entry):
     60         return str(entry)
     61 
     62     def _get_subtext(self, entry):
     63         return ''
     64 
     65     def _render_icon(self, entry, size):
     66         return None
     67 
     68     def _get_menu(self, entry):
     69         return None
     70 
     71     def _get_drag_data(self, entry):
     72         return None
     73 
     74     def _on_remove_chip(self, entry):
     75         self._result.remove(entry)
     76         chip = self._results_entry[entry]
     77         chip.Close()
     78         del self._results_entry[entry]
     79         self._values_changed()
     80 
     81     def _cant_add_new_entry(self, entry):
     82         return self._result is None or entry in self._result or self._at_max_entries()
     83 
     84     def _add_new_entry(self, entry):
     85         if self._cant_add_new_entry(entry):
     86             self._clear_edit()
     87             return
     88         self._add_entry_chip(entry)
     89         self._values_changed()
     90         self._clear_edit()
     91 
     92     def _at_max_entries(self):
     93         return len(self._result) >= self.component.max_entries
     94 
     95     def _values_changed(self):
     96         self.component.on_field_value_changed(self.get_value())
     97         self.label.text = self._get_label_text()
     98         self._update_input_field()
     99 
    100     def _update_input_field(self):
    101         pass
    102 
    103     def _clear_edit(self):
    104         return NotImplementedError()
    105 
    106     def get_value(self):
    107         return self._result
    108 
    109     def set_value(self, value):
    110         pass
    111 
    112     def _sort_results(self):
    113         pass
    114 
    115 
    116 class _AutoCompleteMultiField(MultiValueFormField):
    117 
    118     def get_value(self):
    119         return [ self._get_suggestion_value(suggestion) for suggestion in self._result ]
    120 
    121     def _get_suggestion_value(self, suggestion):
    122         return suggestion
    123 
    124     def _value_changed(self, *args):
    125         new_value = self.edit.completed_suggestion
    126         if new_value is None:
    127             return
    128         self._add_new_entry(new_value)
    129 
    130     def _get_text(self, entry):
    131         return entry.text
    132 
    133     def _get_menu(self, entry):
    134         return entry.get_menu()
    135 
    136     def _get_drag_data(self, entry):
    137         return entry.get_drag_data()
    138 
    139     def _update_input_field(self):
    140         if self._at_max_entries():
    141             self.edit.placeholder = GetByLabel('UI/Corporations/Goals/MultiValueLimitReached')
    142         else:
    143             self.edit.placeholder = self.component.placeholder
    144 
    145     def _clear_edit(self):
    146         uthread.pool('_AutoCompleteMultiField::_clear_edit', self.edit.clear)
    147 
    148     def _sort_results(self):
    149         self._result.sort(key=lambda entry: self._sort_key(entry))
    150 
    151     def _sort_key(self, entry):
    152         return entry.text.lower()
    153 
    154 
    155 class MultiValueLocationFormField(_AutoCompleteMultiField):
    156 
    157     def ConstructSearchField(self):
    158         self.edit = LocationField(parent=self, align=Align.TOTOP, placeholder=self.component.placeholder, show_suggestions_on_focus=True, location_id=None, include_region=self.component.include_region, include_constellation=self.component.include_constellation, include_solar_system=self.component.include_solar_system, include_station=False)
    159         self.edit.bind(completed_suggestion=self._value_changed)
    160 
    161     def _initialize_entry(self, entry):
    162         self._add_new_entry(LocationSuggestion(entry))
    163 
    164     def _get_suggestion_value(self, suggestion):
    165         return suggestion.location_id
    166 
    167     def _get_text(self, entry):
    168         if entry.is_solar_system:
    169             return solar_system_with_security(entry.location_id)
    170         subtext = None
    171         if entry.is_constellation:
    172             subtext = GetByLabel('UI/Common/LocationTypes/Constellation')
    173         elif entry.is_region:
    174             subtext = GetByLabel('UI/Common/LocationTypes/Region')
    175         return _get_text_with_subtext(entry.text, subtext)
    176 
    177     def _render_icon(self, entry, size):
    178         if entry.is_solar_system:
    179             icon = eveicon.solar_system
    180         elif entry.is_constellation:
    181             icon = eveicon.constellation
    182         elif entry.is_region:
    183             icon = eveicon.region
    184         else:
    185             return None
    186         return _render_basic_icon(icon, size)
    187 
    188     def _get_menu(self, entry):
    189         return entry.get_menu()
    190 
    191     def _sort_key(self, entry):
    192         if entry.is_solar_system:
    193             priority = 1
    194         elif entry.is_constellation:
    195             priority = 2
    196         elif entry.is_region:
    197             priority = 3
    198         else:
    199             priority = 4
    200         return (priority, entry.text.lower())
    201 
    202 
    203 class MultiValueItemFormField(_AutoCompleteMultiField):
    204 
    205     def ConstructSearchField(self):
    206         self.edit = ItemField(parent=self, align=Align.TOTOP, placeholder=self.component.placeholder, show_suggestions_on_focus=True, type_filter=self.component.type_filter, group_filter=self.component.group_filter, category_filter=self.component.category_filter, include_type=self.component.include_type, include_group=self.component.include_group, include_category=self.component.include_category)
    207         self.edit.bind(completed_suggestion=self._value_changed)
    208 
    209     def _parse_entry(self, entry):
    210         if isinstance(entry, tuple):
    211             parsed_entry = entry
    212         else:
    213             parsed_entry = ('item_type', entry)
    214         return parsed_entry
    215 
    216     def _initialize_entry(self, entry):
    217         entry_type, entry_id = entry
    218         suggestion = None
    219         if entry_type == 'item_type':
    220             suggestion = ItemTypeSuggestion(entry_id)
    221         elif entry_type == 'item_group':
    222             suggestion = ItemGroupSuggestion(entry_id)
    223         elif entry_type == 'item_category':
    224             suggestion = ItemCategorySuggestion(entry_id)
    225         if suggestion:
    226             self._add_new_entry(suggestion)
    227 
    228     def _get_suggestion_value(self, suggestion):
    229         if isinstance(suggestion, ItemTypeSuggestion):
    230             return ('item_type', suggestion.type_id)
    231         if isinstance(suggestion, ItemGroupSuggestion):
    232             return ('item_group', suggestion.group_id)
    233         if isinstance(suggestion, ItemCategorySuggestion):
    234             return ('item_category', suggestion.category_id)
    235 
    236     def _render_icon(self, entry, size):
    237         if isinstance(entry, ItemTypeSuggestion):
    238             size = max(size, 24)
    239         return entry.render_icon(size)
    240 
    241     def _get_text(self, entry):
    242         if isinstance(entry, ItemTypeSuggestion):
    243             return entry.text
    244         return _get_text_with_subtext(entry.text, entry.subtext)
    245 
    246     def _sort_key(self, entry):
    247         if isinstance(entry, ItemTypeSuggestion):
    248             priority = 1
    249         elif isinstance(entry, ItemGroupSuggestion):
    250             priority = 2
    251         elif isinstance(entry, ItemCategorySuggestion):
    252             priority = 3
    253         else:
    254             priority = 4
    255         return (priority, entry.text.lower())
    256 
    257 
    258 class MultiValueNPCCorpFormField(_AutoCompleteMultiField):
    259 
    260     def ConstructSearchField(self):
    261         self.edit = NpcCorporationField(parent=self, align=Align.TOTOP, placeholder=self.component.placeholder, show_suggestions_on_focus=True, filter=self.component.filter)
    262         self.edit.bind(completed_suggestion=self._value_changed)
    263 
    264     def _initialize_entry(self, entry):
    265         self._add_new_entry(NpcCorporationSuggestion(entry))
    266 
    267     def _get_suggestion_value(self, suggestion):
    268         return suggestion.corporation_id
    269 
    270     def _render_icon(self, entry, size):
    271         size = max(size, 24)
    272         return entry.render_icon(size)
    273 
    274 
    275 class MultiValuePlayerCorpOrOrgFormField(_AutoCompleteMultiField):
    276 
    277     def ConstructSearchField(self):
    278         self.edit = PlayerOrPlayerOrganizationField(parent=self, align=Align.TOTOP, placeholder=self.component.placeholder, include_character=self.component.include_character, include_corporation=self.component.include_corporation, include_alliance=self.component.include_alliance, include_faction=self.component.include_faction, show_suggestions_on_focus=True)
    279         self.edit.bind(completed_suggestion=self._value_changed)
    280 
    281     def _initialize_entry(self, entry):
    282         self._add_new_entry(OwnerIdentitySuggestion(entry))
    283 
    284     def _get_suggestion_value(self, suggestion):
    285         return suggestion.owner_id
    286 
    287     def _render_icon(self, entry, size):
    288         size = max(size, 24)
    289         return entry.render_icon(size)
    290 
    291     def _get_text(self, entry):
    292         return _get_text_with_subtext(entry.text, entry.subtext)
    293 
    294     def _sort_key(self, entry):
    295         if entry.is_character:
    296             priority = 1
    297         elif entry.is_corporation:
    298             priority = 2
    299         elif entry.is_alliance:
    300             priority = 3
    301         elif entry.is_faction:
    302             priority = 4
    303         else:
    304             priority = 5
    305         return (priority, entry.text.lower())
    306 
    307 
    308 class MultiValueShipAndShipTreeFormField(_AutoCompleteMultiField):
    309 
    310     def ConstructSearchField(self):
    311         self.edit = ShipField(parent=self, align=Align.TOTOP, placeholder=self.component.placeholder, show_suggestions_on_focus=True, include_type=self.component.include_type, include_class=self.component.include_class, type_filter=self.component.type_filter)
    312         self.edit.bind(completed_suggestion=self._value_changed)
    313 
    314     def _parse_entry(self, entry):
    315         if isinstance(entry, tuple):
    316             parsed_entry = entry
    317         else:
    318             parsed_entry = ('ship_type', entry)
    319         return parsed_entry
    320 
    321     def _initialize_entry(self, entry):
    322         entry_type, entry_id = entry
    323         suggestion = None
    324         if entry_type == 'ship_type':
    325             suggestion = ShipTypeSuggestion(entry_id)
    326         elif entry_type == 'ship_class':
    327             suggestion = ShipClassSuggestion(entry_id)
    328         if suggestion:
    329             self._add_new_entry(suggestion)
    330 
    331     def _get_suggestion_value(self, suggestion):
    332         if isinstance(suggestion, ShipTypeSuggestion):
    333             return ('ship_type', suggestion.type_id)
    334         if isinstance(suggestion, ShipClassSuggestion):
    335             return ('ship_class', suggestion.ship_class_id)
    336 
    337     def _render_icon(self, entry, size):
    338         if isinstance(entry, ShipTypeSuggestion):
    339             size = max(size, 24)
    340         return entry.render_icon(size)
    341 
    342     def _sort_key(self, entry):
    343         if isinstance(entry, ShipTypeSuggestion):
    344             priority = 1
    345         elif isinstance(entry, ShipClassSuggestion):
    346             priority = 2
    347         else:
    348             priority = 3
    349         return (priority, entry.text.lower())
    350 
    351 
    352 class MultiValueEnum(MultiValueFormField):
    353 
    354     def ConstructSearchField(self):
    355         self.placeholder = self.component.placeholder or GetByLabel('UI/Common/PleaseSelect')
    356         self.edit = Combo(name=self.component.get_id(), parent=self, align=Align.TOTOP, callback=self._value_changed, options=self.component.options, nothingSelectedText=self.placeholder)
    357 
    358     def _parse_entry(self, entry):
    359         entry = super(MultiValueEnum, self)._parse_entry(entry)
    360         if not isinstance(entry, ComboEntryData):
    361             for option in self.component.options:
    362                 if option.returnValue == entry:
    363                     return option
    364 
    365             return None
    366         return entry
    367 
    368     def _value_changed(self, *args):
    369         entry = self.edit.GetSelectedEntry()
    370         if entry is None:
    371             return
    372         self._add_new_entry(entry)
    373 
    374     def _on_remove_chip(self, entry):
    375         if entry not in self._result:
    376             return
    377         super(MultiValueEnum, self)._on_remove_chip(entry)
    378         self.edit.ShowEntry(entry.returnValue)
    379 
    380     def _add_new_entry(self, entry):
    381         if self._cant_add_new_entry(entry):
    382             self._clear_edit()
    383             return
    384         self.edit.HideEntry(entry.returnValue)
    385         super(MultiValueEnum, self)._add_new_entry(entry)
    386 
    387     def _get_text(self, entry):
    388         return entry.label
    389 
    390     def _render_icon(self, entry, size):
    391         return _render_basic_icon(entry.icon, size)
    392 
    393     def _clear_edit(self):
    394         self.edit.SetNothingSelected()
    395 
    396     def _update_input_field(self):
    397         if self._at_max_entries():
    398             self.edit.nothingSelectedText = GetByLabel('UI/Corporations/Goals/MultiValueLimitReached')
    399         else:
    400             self.edit.nothingSelectedText = self.placeholder
    401 
    402 
    403 class MultiValueListItem(Container):
    404     default_align = Align.TOTOP
    405     default_state = uiconst.UI_NORMAL
    406     default_alignMode = Align.TOLEFT
    407     default_height = 28
    408     default_padTop = 8
    409     isDragObject = True
    410 
    411     def __init__(self, entry, get_text, render_icon, get_menu, get_drag_data, on_click_remove, *args, **kwargs):
    412         super(MultiValueListItem, self).__init__(*args, **kwargs)
    413         self._entry = entry
    414         self._get_menu = get_menu
    415         self._get_drag_data = get_drag_data
    416         self._on_click_remove = on_click_remove
    417         contents_container = Container(parent=self, align=Align.TOALL, padLeft=8, padRight=8)
    418         self._close_container = Container(parent=contents_container, align=Align.TORIGHT, width=16, padLeft=8, opacity=0)
    419         ButtonIcon(parent=self._close_container, texturePath=eveicon.close, align=Align.CENTER, height=16, width=16, color=TextColor.SECONDARY, func=self._close_icon_clicked)
    420         icon = render_icon(entry, size=16)
    421         if icon:
    422             icon_container = Container(parent=contents_container, state=uiconst.UI_DISABLED, align=Align.TOLEFT, width=16, padRight=8)
    423             icon.align = Align.CENTER
    424             icon.SetParent(icon_container)
    425         label_container = Container(parent=contents_container, align=Align.TOALL)
    426         self._label = TextBody(parent=label_container, align=Align.CENTERLEFT, text=get_text(entry))
    427         self._bg_frame = Frame(bgParent=self, cornerSize=9, texturePath='res:/UI/Texture/Shared/DarkStyle/panel1Corner_Solid.png', color=(1, 1, 1, 0.05))
    428 
    429     def _close_icon_clicked(self, *args, **kwargs):
    430         self._on_click_remove(self._entry)
    431 
    432     def GetMenu(self):
    433         return self._get_menu(self._entry)
    434 
    435     def GetDragData(self):
    436         drag_data = self._get_drag_data(self._entry)
    437         if drag_data:
    438             return [drag_data]
    439 
    440     def OnMouseEnter(self, *args):
    441         super(MultiValueListItem, self).OnMouseEnter(*args)
    442         Sound.button_hover.play()
    443         fade(self._bg_frame, end_value=0.1, duration=0.2)
    444         fade_in(self._close_container, duration=0.2)
    445 
    446     def OnMouseExit(self, *args):
    447         super(MultiValueListItem, self).OnMouseExit(*args)
    448         fade(self._bg_frame, end_value=0.05, duration=0.2)
    449         fade_out(self._close_container, duration=0.2)
    450 
    451 
    452 def _render_basic_icon(icon, size):
    453     return Sprite(texturePath=icon, align=Align.CENTER, height=size, width=size, color=TextColor.NORMAL)
    454 
    455 
    456 def _get_text_with_subtext(text, subtext):
    457     if subtext:
    458         return u'<color={}>[{}]</color> {}'.format(TextColor.SECONDARY, subtext, text)
    459     return text