form.py (19676B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\util\form.py 2 import log 3 import types 4 import carbonui.const as uiconst 5 import localization 6 from carbon.common.script.sys.service import Service 7 from carbonui.control.button import Button 8 from carbonui.control.combo import Combo 9 from carbonui.control.singlelineedits.singleLineEditFloat import SingleLineEditFloat 10 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger 11 from carbonui.control.singlelineedits.singleLineEditPassword import SingleLineEditPassword 12 from carbonui.control.singlelineedits.singleLineEditText import SingleLineEditText 13 from carbonui.primitives.container import Container 14 from carbonui.primitives.line import Line 15 from eve.client.script.ui.control import eveLabel 16 from carbonui.button.group import ButtonGroup, ButtonSizeMode 17 from carbonui import AxisAlignment 18 from carbonui.control.checkbox import Checkbox 19 from carbonui.control.radioButton import RadioButton 20 from eve.client.script.ui.control.eveEditPlainText import EditPlainText 21 from carbonui.uicore import uicore 22 from carbonui.control.tabGroup import TabGroup 23 from eve.common.lib import appConst as const 24 from player_messaging.client.ui_message import prompt_player_fsd_dialog 25 26 class Form(Service): 27 __guid__ = 'svc.form' 28 __exportedcalls__ = {'GetForm': [], 29 'ProcessForm': []} 30 __servicename__ = 'form' 31 __displayname__ = 'Form Service' 32 __dependencies__ = [] 33 34 def __init__(self): 35 Service.__init__(self) 36 37 def GetForm(self, format, parent): 38 _form, retfields, reqresult, panels, errorcheck, refresh = self._GetForm(format, parent) 39 if _form.align == uiconst.TOALL: 40 _form.SetSize(0, 0) 41 _form.SetPosition(0, 0) 42 _form.padding = const.defaultPadding 43 elif _form.align in (uiconst.TOTOP, uiconst.TOBOTTOM): 44 _form.SetPosition(0, 0) 45 _form.width = 0 46 _form.padding = const.defaultPadding 47 elif _form.align in (uiconst.TOLEFT, uiconst.TORIGHT): 48 _form.SetPosition(0, 0) 49 _form.height = 0 50 _form.padding = const.defaultPadding 51 else: 52 _form.left = _form.top = const.defaultPadding 53 return (_form, 54 retfields, 55 reqresult, 56 panels, 57 errorcheck, 58 refresh) 59 60 def _GetForm(self, format, parent, retfields = [], reqresult = [], errorcheck = None, tabpanels = [], tabgroup = [], refresh = [], wipe = 1): 61 if not parent.IsUnder(uicore.desktop): 62 log.LogTraceback('Form parent MUST be hooked on the desktop; it is impossible to know the real dimensions of stuff within otherwise.') 63 self.retfields = retfields 64 self.reqresult = reqresult 65 self.errorcheck = errorcheck 66 self.tabpanels = tabpanels 67 self.tabgroup = tabgroup 68 self.refresh = refresh 69 if not isinstance(parent, FormWnd): 70 log.LogTraceback('Incompatible formparent, please change it to xtriui.FormWnd') 71 self.parent = parent 72 self.parent.sr.panels = {} 73 self.parent.sr.focus = None 74 if wipe: 75 self.retfields = [] 76 self.reqresult = [] 77 self.tabpanels = [] 78 self.tabgroup = [] 79 self.refresh = [] 80 for each in format: 81 self.type = each 82 typeName = self.type['type'] 83 self.leftPush = self.type.get('labelwidth', 0) or 80 84 self.code = None 85 if typeName == 'errorcheck': 86 self.AddErrorcheck() 87 continue 88 elif typeName == 'data': 89 self.AddData() 90 continue 91 elif typeName == 'tab': 92 self.AddTab() 93 continue 94 elif typeName in ('btline', 'bbline'): 95 self.AddLine() 96 continue 97 elif typeName == 'push': 98 self.AddPush() 99 elif typeName == 'header': 100 self.AddHeader() 101 elif typeName == 'labeltext': 102 self.AddLabeltext() 103 elif typeName == 'text': 104 self.AddText() 105 elif typeName == 'edit': 106 self.AddEdit() 107 elif typeName == 'textedit': 108 self.AddTextedit() 109 elif typeName == 'checkbox': 110 self.AddCheckbox() 111 elif typeName == 'combo': 112 self.AddCombo() 113 elif typeName == 'btnonly': 114 self.AddBtnonly() 115 else: 116 log.LogWarn('Unknown fieldtype in form generator') 117 continue 118 if 'key' in self.type: 119 if self.code: 120 self.retfields.append([self.code, self.type]) 121 self.parent.sr.Set(self.type['key'], self.code) 122 else: 123 self.parent.sr.Set(self.type['key'], self.new) 124 if self.type.get('required', 0) == 1: 125 self.reqresult.append([self.code, self.type]) 126 if self.type.get('selectall', 0) == 1 and getattr(self.code, 'SelectAll', None): 127 self.code.SelectAll() 128 if self.type.get('setfocus', 0) == 1: 129 self.parent.sr.focus = self.code 130 if 'stopconfirm' in self.type and hasattr(self.code, 'stopconfirm'): 131 self.code.stopconfirm = self.type['stopconfirm'] 132 if self.type.get('frame', 0) == 1: 133 idx = 0 134 for child in self.new.children: 135 if child.name.startswith('Line'): 136 idx += 1 137 138 Container(name='leftpush', parent=self.new, align=uiconst.TOLEFT, width=6, idx=idx) 139 Container(name='rightpush', parent=self.new, align=uiconst.TORIGHT, width=6, idx=idx) 140 Line(parent=self.new, align=uiconst.TOLEFT, idx=idx) 141 Line(parent=self.new, align=uiconst.TORIGHT, idx=idx) 142 143 if wipe and len(self.tabgroup): 144 tabs = TabGroup(name='tabparent', parent=self.parent, idx=0) 145 tabs.Startup(self.tabgroup, 'hybrid') 146 maxheight = 0 147 for panel in self.tabpanels: 148 maxheight = max(maxheight, panel.height) 149 150 self.parent.height = maxheight + tabs.height 151 else: 152 if len(self.tabpanels): 153 for each in self.tabpanels: 154 each.state = uiconst.UI_HIDDEN 155 156 self.tabpanels[0].state = uiconst.UI_PICKCHILDREN 157 self.RefreshHeight(self.parent) 158 uicore.registry.SetFocus(self) 159 return (self.parent, 160 self.retfields, 161 self.reqresult, 162 self.tabpanels, 163 self.errorcheck, 164 self.refresh) 165 166 def RefreshHeight(self, w): 167 w.height = sum([ x.height for x in w.children if x.state != uiconst.UI_HIDDEN and x.align in (uiconst.TOBOTTOM, uiconst.TOTOP) ]) 168 169 def AddErrorcheck(self): 170 self.errorcheck = self.type['errorcheck'] 171 172 def AddData(self): 173 self.retfields.append(self.type['data']) 174 175 def AddTab(self): 176 _form, _retfield, _required, _tabpanels, _errorcheck, _refresh = self._GetForm(self.type['format'], FormWnd(name='form', align=uiconst.TOTOP, parent=self.parent), self.retfields, self.reqresult, self.errorcheck, self.tabpanels, self.tabgroup, self.refresh, 0) 177 if 'key' in self.type: 178 self.parent.sr.panels[self.type['key']] = _form 179 if self.type.get('panelvisible', 0): 180 _form.state = uiconst.UI_PICKCHILDREN 181 else: 182 _form.state = uiconst.UI_HIDDEN 183 if 'tabvisible' in self.type: 184 if self.type['tabvisible'] == 1: 185 self.tabgroup.append([self.type['tabtext'], 186 _form, 187 self, 188 None]) 189 else: 190 self.tabgroup.append([self.type['tabtext'], 191 _form, 192 self, 193 None]) 194 195 def AddPush(self): 196 self.new = Container(name='push', parent=self.parent, align=uiconst.TOTOP, height=self.type.get('height', 6)) 197 198 def AddLine(self): 199 (Container(parent=self.parent, align=uiconst.TOTOP, height=16),) 200 201 def AddHeader(self): 202 self.new = Container(name='headerField', parent=self.parent, align=uiconst.TOTOP, padding=(0, 8, 0, 0)) 203 header = eveLabel.EveLabelLarge(text=self.type.get('text', ''), parent=self.new, name='header', align=uiconst.TOTOP, state=uiconst.UI_NORMAL) 204 self.new.height = max(self.type.get('height', 17), header.textheight) 205 self.refresh.append((self.new, header)) 206 207 def AddLabeltext(self): 208 self.new = Container(name='labeltextField', parent=self.parent, align=uiconst.TOTOP, height=self.type.get('height', 20)) 209 text = eveLabel.EveLabelMedium(name='text', parent=self.new, align=uiconst.TOTOP, padding=(0, 4, 0, 0), state=uiconst.UI_NORMAL, text=self.type.get('text', '')) 210 label = self.type.get('label', '') 211 if label and label != '_hide': 212 pad_top = 4 if self.type.get('text', '') else 0 213 label = eveLabel.EveLabelSmall(name='label', parent=self.new, align=uiconst.TOTOP, padding=(8, 214 pad_top, 215 8, 216 8), text=label) 217 self.refresh.append((self.new, text, label)) 218 else: 219 self.refresh.append((self.new, text)) 220 221 def AddText(self): 222 left = self.type.get('left', 0) 223 self.new = Container(name='textField', parent=self.parent, align=uiconst.TOTOP, height=self.type.get('height', 20), padding=(left, 224 0, 225 0, 226 0)) 227 fontsize = self.type.get('fontsize', 12) 228 text = eveLabel.Label(text=self.type.get('text', ''), parent=self.new, align=uiconst.TOTOP, name='text', padding=(0, 3, 0, 3), fontsize=fontsize, maxLines=1 if bool(self.type.get('tabstops', [])) else None, state=uiconst.UI_NORMAL, tabs=self.type.get('tabstops', [])) 229 self.new.height = max(self.new.height, int(text.textheight + 6)) 230 self.refresh.append((self.new, text)) 231 232 def AddEdit(self): 233 self.new = Container(name='editField', parent=self.parent, align=uiconst.TOTOP) 234 config = 'edit_%s' % self.type['key'] 235 ints = self.type.get('intonly', None) 236 floats = self.type.get('floatonly', None) 237 passwordCharacter = self.type.get('passwordChar', None) 238 decimalPlaces = SingleLineEditFloat.default_decimalPlaces 239 minValue = maxValue = 0 240 singleLineEditClass = SingleLineEditText 241 if ints: 242 singleLineEditClass = SingleLineEditInteger 243 minValue, maxValue = ints 244 elif floats: 245 singleLineEditClass = SingleLineEditFloat 246 if len(floats) > 2: 247 minValue, maxValue, decimalPlaces = floats 248 else: 249 minValue, maxValue = floats 250 elif passwordCharacter: 251 singleLineEditClass = SingleLineEditPassword 252 self.code = singleLineEditClass(name=config, parent=self.new, setvalue=self.type.get('setvalue', ''), padding=(self.leftPush, 253 2, 254 0, 255 2), align=uiconst.TOTOP, maxLength=self.type.get('maxlength', None) or self.type.get('maxLength', None), readonly=self.type.get('readonly', 0), autoselect=self.type.get('autoselect', 0), isTypeField=self.type.get('isTypeField', False), isCharacterField=self.type.get('isCharacterField', False), isCharCorpOrAllianceField=self.type.get('isCharCorpOrAllianceField', False), passwordCharacter=self.type.get('passwordChar', None), minValue=minValue, maxValue=maxValue, decimalPlaces=decimalPlaces) 256 self.new.height = self.code.height + self.code.padTop * 4 257 width = self.type.get('width', None) 258 if width: 259 self.code.SetAlign(uiconst.TOLEFT) 260 self.code.width = width 261 if 'OnReturn' in self.type: 262 self.code.data = {'key': self.type['key']} 263 self.code.OnReturn = self.type['OnReturn'] 264 if 'unusedkeydowncallback' in self.type: 265 self.code.OnUnusedKeyDown = self.type['unusedkeydowncallback'] 266 if 'onanychar' in self.type: 267 self.code.OnAnyChar = self.type['onanychar'] 268 label = self.type.get('label', '') 269 text = self.type.get('text', None) 270 caption = text or label 271 if label == '_hide': 272 self.code.padLeft = 0 273 elif caption: 274 l = eveLabel.EveLabelSmall(text=caption, align=uiconst.CENTERLEFT, parent=self.new, name='label', left=7, width=self.leftPush - 6) 275 276 def AddTextedit(self): 277 self.new = Container(name='texteditField', parent=self.parent, align=uiconst.TOTOP, height=self.type.get('height', 68)) 278 self.code = EditPlainText(setvalue=self.type.get('setvalue', '') or self.type.get('text', ''), parent=self.new, padding=(self.leftPush, 279 2, 280 0, 281 2), readonly=self.type.get('readonly', 0), showattributepanel=self.type.get('showAttribPanel', 0), maxLength=self.type.get('maxlength', None) or self.type.get('maxLength', None)) 282 label = self.type.get('label', '') 283 if label == '_hide': 284 self.code.padLeft = 0 285 elif label: 286 eveLabel.EveLabelSmall(text=label, parent=self.new, name='label', left=7, width=self.leftPush - 6, top=5) 287 288 def AddCheckbox(self): 289 self.new = Container(name='checkboxCont', parent=self.parent, align=uiconst.TOTOP, pos=(0, 0, 0, 18)) 290 group = self.type.get('group', None) 291 if group: 292 self.code = RadioButton(text=self.type.get('text', ''), parent=self.new, settingsKey=self.type.get('name', 'none'), retval=self.type['key'], checked=self.type.get('setvalue', 0), groupname=group, callback=self.parent.OnCheckboxChange) 293 else: 294 self.code = Checkbox(text=self.type.get('text', ''), parent=self.new, settingsKey=self.type.get('name', 'none'), checked=self.type.get('setvalue', 0), callback=self.parent.OnCheckboxChange) 295 self.code.data = {} 296 onchange = self.type.get('OnChange', None) or self.type.get('onchange', None) 297 if onchange: 298 self.code.SetSettingsKey(self.type['key']) 299 self.code.data = {'key': self.type['key'], 300 'callback': onchange} 301 if 'showpanel' in self.type: 302 self.code.data['showpanel'] = self.type['showpanel'] 303 if self.code.sr.label: 304 self.refresh.append((self.code, self.code.sr.label)) 305 if self.type.get('hidden', 0): 306 self.code.state = uiconst.UI_HIDDEN 307 308 def AddCombo(self): 309 self.new = Container(name='comboField', parent=self.parent, align=uiconst.TOTOP, height=self.type.get('height', 32)) 310 options = self.type.get('options', [(localization.GetByLabel('UI/Common/None'), None)]) 311 self.code = Combo(label='', parent=self.new, options=options, name=self.type.get('key', 'combo'), select=self.type.get('setvalue', ''), padding=(self.leftPush, 312 2, 313 0, 314 2), align=uiconst.TOTOP, callback=self.type.get('callback', None), labelleft=self.leftPush, prefskey=self.type.get('prefskey', None)) 315 self.new.height = self.code.height + self.code.padTop * 4 316 width = self.type.get('width', None) 317 if width: 318 self.code.SetAlign(uiconst.TOLEFT) 319 self.code.width = width 320 label = self.type.get('label', '') 321 if label == '_hide': 322 self.code.padLeft = 0 323 else: 324 eveLabel.EveLabelSmall(text=label, parent=self.new, name='label', left=7, width=self.leftPush - 6, align=uiconst.CENTERLEFT) 325 326 def AddBtnonly(self): 327 self.new = Container(name='btnonly', parent=self.parent, align=uiconst.TOTOP, height=self.type.get('height', 20)) 328 align = uiconst.TORIGHT 329 for wantedbtn in self.type['buttons']: 330 if 'align' in wantedbtn: 331 al = {'left': uiconst.CENTERLEFT, 332 'right': uiconst.CENTERRIGHT} 333 align = al.get(wantedbtn['align'], uiconst.CENTERRIGHT) 334 335 uniSize = self.type.get('uniSize', True) 336 if uniSize: 337 size_mode = ButtonSizeMode.EQUAL 338 else: 339 size_mode = ButtonSizeMode.DYNAMIC 340 ButtonGroup(parent=self.new, align=uiconst.TOTOP, button_size_mode=size_mode, button_alignment=axis_alignment_from_legacy_align(align), buttons=[ Button(label=data['caption'], func=data['function'], args=data.get('args', 'self'), btn_modalresult=data.get('btn_modalresult', 0), btn_default=data.get('btn_default', 0), btn_cancel=data.get('btn_cancel', 0)) for data in self.type['buttons'] ]) 341 342 def ProcessForm(self, retfields, required, errorcheck = None): 343 result = {} 344 for each in retfields: 345 if type(each) == dict: 346 result.update(each) 347 continue 348 value = each[0].GetValue() 349 if each[1]['type'] == 'checkbox' and 'group' in each[1] and value == 1: 350 result[each[1]['group']] = each[1]['key'] 351 else: 352 result[each[1]['key']] = value 353 354 if errorcheck: 355 hint = errorcheck(result) 356 if hint == 'silenterror': 357 return 358 if hint: 359 prompt_player_fsd_dialog('CustomInfo', {'info': hint}) 360 return 361 if len(required): 362 for each in required: 363 retval = each[0].GetValue() 364 if retval is None or retval == '' or type(retval) in types.StringTypes and retval.strip() == '': 365 fieldname = '' 366 if 'label' in each[1]: 367 fieldname = each[1]['label'] 368 if fieldname == '_hide': 369 fieldname = each[1]['key'] 370 else: 371 fieldname = each[1]['key'] 372 prompt_player_fsd_dialog('MissingRequiredField', {'fieldname': fieldname}) 373 return 374 if each[1]['type'] == 'checkbox' and 'group' in each[1]: 375 if each[1]['group'] not in result: 376 prompt_player_fsd_dialog('MissingRequiredField', {'fieldname': each[1]['group']}) 377 return 378 379 return result 380 381 382 def axis_alignment_from_legacy_align(align): 383 if align in {uiconst.TOPLEFT, 384 uiconst.BOTTOMLEFT, 385 uiconst.CENTERLEFT, 386 uiconst.TOLEFT}: 387 return AxisAlignment.START 388 elif align in {uiconst.TOPRIGHT, 389 uiconst.BOTTOMRIGHT, 390 uiconst.CENTERRIGHT, 391 uiconst.TORIGHT}: 392 return AxisAlignment.END 393 elif align in {uiconst.CENTER, uiconst.CENTERTOP, uiconst.CENTERBOTTOM}: 394 return AxisAlignment.CENTER 395 else: 396 return AxisAlignment.CENTER 397 398 399 class FormWnd(Container): 400 __guid__ = 'xtriui.FormWnd' 401 402 def _OnClose(self): 403 Container._OnClose(self) 404 windowKeys = self.sr.panels.keys() 405 for key in windowKeys: 406 if key not in self.sr.panels: 407 continue 408 wnd = self.sr.panels[key] 409 del self.sr.panels[key] 410 if wnd is not None and not wnd.destroyed: 411 wnd.Close() 412 413 def ShowPanel(self, panelkey): 414 for key in self.sr.panels: 415 self.sr.panels[key].state = uiconst.UI_HIDDEN 416 417 self.sr.panels[panelkey].state = uiconst.UI_NORMAL 418 419 def OnCheckboxChange(self, sender, *args): 420 if 'callback' in sender.data: 421 sender.data['callback'](sender) 422 if 'showpanel' in sender.data and sender.data['showpanel'] in self.sr.panels: 423 self.ShowPanel(sender.data['showpanel']) 424 425 def OnChange(self, *args): 426 pass