edit.py (78755B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\control\edit.py 2 from __future__ import print_function 3 import errno 4 import sys 5 import blue 6 import carbonui.const as uiconst 7 import localization 8 import log 9 import telemetry 10 import urllib2 11 import urlparse 12 import uthread 13 from carbon.client.script.util.resLoader import ResFile 14 from carbon.common.script.util.commonutils import StripTags 15 from carbon.common.script.util.timerstuff import AutoTimer 16 from carbonui import fontflags 17 from carbonui.control.basicDynamicScroll import Scroll 18 from carbonui.control.editutils import parser 19 from carbonui.control.editutils.parserbase import ParserBaseCoreOverride as ParserBase 20 from carbonui.control.scrollentries import SE_SpaceCore as SE_Space 21 from carbonui.control.scrollentries import SE_TextlineCore, ScrollEntryNode 22 from carbonui.fontconst import DEFAULT_LETTERSPACE, DEFAULT_FONTSIZE 23 from carbonui.primitives.container import Container 24 from carbonui.primitives.fill import Fill 25 from carbonui.primitives.sprite import Sprite 26 from carbonui.text.color import TextColor 27 from carbonui.text.settings import check_convert_font_size 28 from carbonui.uicore import uicore 29 from carbonui.util.bunch import Bunch 30 from carbonui.util.various_unsorted import ParseHTMLColor, GetClipboardData 31 from menu import MenuLabel 32 from player_messaging.client.ui_message import prompt_player_fsd_dialog 33 34 class EditCore(ParserBase, Scroll): 35 default_name = 'edit_multiline' 36 default_align = uiconst.TOTOP 37 default_width = 0 38 default_height = 100 39 default_maxLength = None 40 default_readonly = False 41 default_showattributepanel = 0 42 default_hideBackground = False 43 default_setvalue = '' 44 default_fontsize = None 45 default_fontcolor = TextColor.NORMAL 46 default_letterspace = None 47 48 def ApplyAttributes(self, attributes): 49 if self.default_fontsize is None: 50 self.default_fontsize = DEFAULT_FONTSIZE 51 if self.default_letterspace is None: 52 self.default_letterspace = DEFAULT_LETTERSPACE 53 Scroll.ApplyAttributes(self, attributes) 54 self._initingEdit = True 55 ParserBase.Prepare(self) 56 self.sr.currentURL = None 57 self.sr.currentData = None 58 self.sr.currentTXT = None 59 self.sr.window = None 60 self.sr.sessionreload = False 61 self._knownWidth = None 62 self.xmargin = 0 63 self.ymargin = 6 64 self.sr.resizeTimer = None 65 self.sr.window = None 66 self.sr.positions = {} 67 self._selecting = 0 68 self._showCursor = True 69 self._maxGlobalCursorIndex = 0 70 self.sr.startSelectionPos = (0, 0) 71 self.sr.scrollTimer = None 72 self.sr.attribPanel = None 73 self.maxletters = None 74 self.globalSelectionRange = (None, None) 75 self.globalSelectionInitpos = None 76 self.globalCursorPos = 0 77 self.debug = 0 78 self.htmldebug = 0 79 self.IsBrowser = 1 80 self.AttribStateChange = None 81 self.updating = 0 82 self.readonly = 0 83 self.autoScrollToBottom = 0 84 self.fontFlag = 0 85 self.href = None 86 fontSize = attributes.get('fontsize', self.default_fontsize) 87 self.fontSize = self.defaultFontSize = check_convert_font_size(fontSize) 88 self.fontColor = self.defaultFontColor = attributes.get('fontcolor', self.default_fontcolor) 89 from carbonui.control.browser.cookieManager import CookieManager 90 self.sr.cookieMgr = CookieManager() 91 self.resizing = 0 92 self.preCompText = None 93 self.allowPrivateDrops = 0 94 self.sr.content.GetMenu = self.GetMenuDelegate 95 self.sr.content.OnKeyDown = self.OnKeyDown 96 self.sr.content.OnDropData = self.OnContentDropData 97 self.sr.content.OnMouseDown = self.OnMouseDown 98 self.sr.content.OnMouseUp = self.OnMouseUp 99 self.sr.content.OnMouseMove = self.OnMouseMove 100 self.sr.content.cursor = uiconst.UICURSOR_IBEAM 101 self._AttribStateChange() 102 self.hideBackground = attributes.get('hideBackground', self.default_hideBackground) 103 maxLength = attributes.get('maxLength', self.default_maxLength) 104 self.SetMaxLength(maxLength) 105 readonly = attributes.get('readonly', self.default_readonly) 106 if readonly: 107 self.ReadOnly() 108 else: 109 showattributepanel = attributes.get('showattributepanel', self.default_showattributepanel) 110 if showattributepanel: 111 self.ShowAttributePanel() 112 self.Editable(showpanel=showattributepanel) 113 setvalue = attributes.get('setvalue', self.default_setvalue) 114 self.SetValue(setvalue) 115 if not self.destroyed: 116 self._initingEdit = False 117 118 def Prepare_Underlay_(self): 119 self.sr.backgroundColorContainer = Container(name='backgroundColorContainer', parent=self) 120 Scroll.Prepare_Underlay_(self) 121 122 def ShowAttributePanel(self): 123 if not self.readonly: 124 from carbonui.control.fontAttributePanel import FontAttributePanel 125 self.sr.attribPanel = FontAttributePanel(align=uiconst.TOTOP, padBottom=2, parent=self, idx=0, state=uiconst.UI_HIDDEN, padding=(4, 0, 4, 0)) 126 127 def GetLinespace(self): 128 if not self or not getattr(self, 'sr', None): 129 return 0 130 if self.sr.nodes: 131 if self.sr.nodes[-1].maxBaseHeight is not None: 132 return self.sr.nodes[-1].maxBaseHeight 133 if self.sr.nodes[-1].size is not None: 134 return int(self.sr.nodes[-1].size) 135 return 18 136 137 def Reset(self, *args, **kw): 138 cw, ch = self.sr.content.GetAbsoluteSize() 139 self._knownWidth = max(100, cw) 140 self.sr.overlays_content.Flush() 141 self.sr.underlays_content.Flush() 142 143 @telemetry.ZONE_METHOD 144 def LoadHTML(self, htmlstr, reload = 0, scrollTo = None, newThread = 1, breakOnly = 0): 145 if not self or self.destroyed: 146 return 147 if self._loading: 148 return 149 self._loading = 1 150 self.sr.resizeTimer = None 151 self.tagdepth = 0 152 self.keybuffer = [] 153 self.textbuffers = [] 154 formdatalist = [] 155 if htmlstr is None: 156 if self.sr.currentTXT is not None: 157 for form in self.sr.forms: 158 formdatalist.append(form.GetFields()) 159 160 else: 161 self.sr.currentTXT = htmlstr 162 htmlstr = htmlstr or self.sr.currentTXT or '' 163 htmlstr = htmlstr.replace('*</localized>', '</localized>') 164 self._LoadHTML(htmlstr) 165 if self.destroyed: 166 return 167 if breakOnly: 168 self._loading = 0 169 return 170 self.SetSelectionRange(None, None) 171 self.RenderLines(scrollTo, formdatalist) 172 if hasattr(self, 'CheckOverlaysAndUnderlays'): 173 self.CheckOverlaysAndUnderlays() 174 self.UpdateNodesCursorIndexes() 175 if not self.readonly: 176 self.DoContentResize() 177 self.SetCursorPos(0) 178 else: 179 self.RefreshCursorAndSelection() 180 self._loading = 0 181 182 def RenderLines(self, scrollTo = None, formdatalist = []): 183 self.sr.lines.insert(0, ScrollEntryNode(decoClass=SE_Space, height=self.ymargin)) 184 if len(self.sr.lines) == 1 and not self.readonly: 185 self.sr.lines.append(self.GetFirstLine()) 186 self.LoadContent(contentList=self.sr.lines, scrollTo=scrollTo) 187 if len(formdatalist) == len(self.sr.forms): 188 for i in xrange(len(formdatalist)): 189 self.sr.forms[i].SetFields(formdatalist[i]) 190 191 if self.sr.window and hasattr(self.sr.window, 'LoadEnd'): 192 self.sr.window.LoadEnd() 193 194 def DoFontChange(self, *args): 195 self.DoContentResize() 196 197 def IsLoading(self): 198 return self._loading 199 200 def LoadBodyAttrs(self, attrs): 201 self.sr.background.Flush() 202 if self.hideBackground: 203 self.RemoveActiveFrame() 204 self.sr.backgroundColorContainer.Flush() 205 self.HideBackground(alwaysHidden=self.hideBackground) 206 if not attrs: 207 return 208 self.bgscrolltype = parser.BG_TILED 209 for each in ('link', 'alink', 'vlink'): 210 if getattr(attrs, each, None): 211 self.attrStack[-1]['%s-color' % each] = ParseHTMLColor(getattr(attrs, each, None), 1) 212 213 if attrs.text: 214 self.attrStack[-1]['color'] = ParseHTMLColor(attrs.text, 1) 215 if attrs.bgcolor: 216 self.attrStack[-1]['background-color'] = ParseHTMLColor(attrs.bgcolor, 1) 217 if attrs.background: 218 self.attrStack[-1]['background-image'] = attrs.background 219 self.ParseStdStyles(attrs) 220 if not self.hideBackground: 221 if self.attrStack[-1]['background-color']: 222 col = self.attrStack[-1]['background-color'] 223 Fill(parent=self.sr.backgroundColorContainer, color=col) 224 self.attrStack[-1]['background-color'] = None 225 if self.attrStack[-1]['background-image']: 226 aL, aT, aW, aH = self.parent.GetAbsolute() 227 windowWidth = aW 228 windowHeight = aH 229 pic = Sprite() 230 pic.left = self.attrStack[-1]['background-image-left'] 231 pic.top = self.attrStack[-1]['background-image-top'] 232 pic.width = self.attrStack[-1]['background-image-width'] 233 pic.height = self.attrStack[-1]['background-image-height'] 234 if self.attrStack[-1]['background-image'].startswith('icon:'): 235 log.LogError('Icon:* is not legal background path') 236 path = self.CheckURL(self.attrStack[-1]['background-image']) 237 texture, tWidth, tHeight = sm.GetService('browserImage').GetTextureFromURL(path, fromWhere='Bastard::LoadBodyAttrs') 238 if self.destroyed: 239 return 240 pic.width = self.attrStack[-1]['background-image-width'] or tWidth 241 pic.height = self.attrStack[-1]['background-image-height'] or tHeight 242 pic.texture = texture 243 for pos in self.attrStack[-1]['background-position']: 244 if pos == 'top': 245 pic.top = 0 246 elif pos == 'bottom': 247 pic.left = windowHeight - pic.height 248 elif pos == 'middle': 249 pic.left = (windowHeight - pic.height) / 2 250 elif pos == 'left': 251 pic.left = 0 252 elif pos == 'right': 253 pic.left = windowWidth - pic.width 254 elif pos == 'center': 255 pic.left = (windowWidth - pic.width) / 2 256 257 if self.attrStack[-1]['background-image-color']: 258 pic.SetRGBA(*self.attrStack[-1]['background-image-color']) 259 row = Container(name='row', align=uiconst.TOTOP, pos=(0, 260 0, 261 0, 262 pic.height)) 263 if self.attrStack[-1]['background-repeat'] in ('repeat', 'repeat-x'): 264 for x in xrange(max(windowWidth / pic.width, 2)): 265 row.children.append(pic.CopyTo()) 266 pic.left += pic.width 267 268 else: 269 row.children.append(pic.CopyTo()) 270 if self.attrStack[-1]['background-repeat'] in ('repeat', 'repeat-y'): 271 if self.attrStack[-1]['background-attachment'] == 'scroll': 272 self.bgscrolltype = parser.BG_TILED 273 for y in xrange(max(windowHeight / tHeight, 2) + 1): 274 self.sr.background.children.append(row.CopyTo()) 275 276 else: 277 if self.attrStack[-1]['background-attachment'] == 'scroll': 278 self.bgscrolltype = parser.BG_SCROLL 279 self.sr.background.children.append(row.CopyTo()) 280 if self.attrStack[-1]['background-attachment'] == 'fixed': 281 self.bgscrolltype = parser.BG_FIXED 282 self.sr.background.top = 0 283 self.attrStack[-1]['background-image'] = None 284 if self.attrStack[-1]['margin-top'] != 0: 285 margin = self.attrStack[-1]['margin-top'] 286 lpush, rpush = self.GetMargins(self.contentHeight, self.contentHeight + margin) 287 self.FlushBuffer([([], 288 [], 289 [], 290 lpush, 291 rpush, 292 None, 293 margin, 294 0, 295 0)]) 296 297 def GoTo(self, URL, data = None, args = {}, scrollTo = None, newThread = 1): 298 if self.sr.window and hasattr(self.sr.window, 'GoTo'): 299 self.sr.window.GoTo(URL, data, args, scrollTo) 300 else: 301 return self._GoTo(URL, data, args, newThread=newThread) 302 303 def _GoTo(self, url, data = None, args = {}, scrollTo = None, recursive = 0, newThread = 1, getSource = 0): 304 if not url: 305 return 306 if getSource: 307 return self.sr.currentTXT 308 if self.sr.window and hasattr(self.sr.window, 'ShowLoad'): 309 self.sr.window.ShowLoad() 310 self.startTime = blue.os.GetWallclockTimeNow() 311 self.SetStatus(localization.GetByLabel('/Carbon/UI/Controls/EditRichText/OpeningURL', url=url)) 312 url = url.encode('ascii') 313 from carbonui.control.browser import browserutil 314 from carbon.common.script.net.GPS import ClientConnectFailed, ClientConnectFailedString 315 try: 316 if self.sr.window and getattr(self.sr.window, 'SetCaption', None): 317 self.sr.window.SetCaption('') 318 node = data 319 self.sr.currentData = data 320 try: 321 if url.startswith('./'): 322 url = url[2:] 323 if self.sr.currentURL is not None and self.sr.currentURL.lower().startswith('res:') and ':' not in url[:6]: 324 lastslash = self.sr.currentURL.rfind('/') 325 url = self.sr.currentURL[:lastslash + 1] + url 326 url = self.LocalizeURL(url) 327 if url.lower().startswith('res:'): 328 response = ResFile(url) 329 self.sr.currentURL = url 330 else: 331 url, anchor = self.CheckURL(url, getAnchor=1) 332 scheme, netloc, path, query, fragment = urlparse.urlsplit(url) 333 self.sr.currentURL = urlparse.urlunsplit((scheme, 334 netloc, 335 path or '/', 336 query, 337 '')).rstrip() 338 cookie = self.sr.cookieMgr.GetCookie(url) 339 response = browserutil.GetStringFromURL(url, data, cookie) 340 if self.destroyed: 341 return 342 scheme, netloc, path, query, fragment = urlparse.urlsplit(url) 343 if path and path[-1] != '/' and '.' not in path[-5:] and url.find('local://') == -1: 344 path += '/' 345 if getattr(response, 'url', None): 346 self.sr.currentURL = response.url 347 else: 348 self.sr.currentURL = urlparse.urlunsplit((scheme, 349 netloc, 350 path or '/', 351 query, 352 '')).rstrip() 353 self.sr.anchor = fragment 354 self.sr.sessionreload = False 355 self.sr.reloadtimer = None 356 for each in response.info().headers: 357 tmp = each.strip() 358 if tmp.lower().startswith('refresh:'): 359 args = tmp[8:].strip().split(';') 360 interval = None 361 if len(args) == 2: 362 interval, url = args 363 self.sr.reloadURL = url.replace('URL=', '').strip() 364 elif len(args) == 1: 365 interval = args[0] 366 self.sr.reloadURL = self.sr.currentURL 367 if interval is not None: 368 if str(interval).strip().lower() == 'sessionchange': 369 self.sr.sessionreload = True 370 else: 371 if int(interval) == 0: 372 self._GoTo(self.sr.reloadURL) 373 return 374 self.sr.reloadtimer = AutoTimer(1000 * int(interval), self.TimedReload) 375 376 self.sr.cookieMgr.ProcessCookies(response) 377 self.charset = 'cp1252' 378 if 'content-type' in response.headers.keys(): 379 if response.headers['content-type'].startswith('image/'): 380 self.LoadHTML('<HTML><BODY><IMG SRC="' + url + '"></BODY></HTML>') 381 return 382 for each in response.headers['content-type'].split(';'): 383 tmp = each.strip().lower() 384 if tmp.startswith('charset='): 385 charset = tmp[8:].strip() 386 try: 387 import codecs 388 codecs.lookup(str(charset)) 389 self.charset = charset 390 except: 391 sys.exc_clear() 392 393 pieces = [] 394 while True: 395 next4kb = response.read(4096) 396 if next4kb: 397 pieces.append(next4kb) 398 blue.pyos.BeNice() 399 else: 400 break 401 402 txt = ''.join(pieces) 403 if txt[:2] == '\xff\xfe': 404 txt = txt.decode('utf-16') 405 self.LoadHTML(txt, scrollTo=scrollTo, newThread=newThread) 406 except OSError as what: 407 if what.errno == errno.ENOENT: 408 self.LoadHTML(localization.GetByLabel('/Carbon/UI/Controls/EditRichText/HTMLErrorFileNotFound', filename=what.filename)) 409 else: 410 self.LoadHTML(localization.GetByLabel('/Carbon/UI/Controls/EditRichText/HTMLErrorOSError', filename=what.filename, errorNumber=what.errno, errorString=what.strerror)) 411 sys.exc_clear() 412 except ClientConnectFailed as what: 413 s = ClientConnectFailedString(what) 414 if s.lower() in ('host not found', 'valid name, no data record of requested type'): 415 self.LoadHTML(localization.GetByLabel('/Carbon/UI/Controls/EditRichText/HTMLErrorHostNotFound')) 416 elif s.lower() in ('connection timed out', 'valid name, no data record of requested type'): 417 self.LoadHTML(localization.GetByLabel('/Carbon/UI/Controls/EditRichText/HTMLErrorConnectionTimeOut', title=what.args[0], hostAddress=url)) 418 else: 419 self.LoadHTML(localization.GetByLabel('/Carbon/UI/Controls/EditRichText/HTMLErrorGeneric', title=what.args[0])) 420 sys.exc_clear() 421 except urllib2.URLError as what: 422 self.LoadHTML(localization.GetByLabel('/Carbon/UI/Controls/EditRichText/HTMLErrorURLError', error=what)) 423 sys.exc_clear() 424 except ValueError as what: 425 self.LoadHTML(localization.GetByLabel('/Carbon/UI/Controls/EditRichText/HTMLErrorURLError', error=what)) 426 log.LogException() 427 except AttributeError: 428 if self is None or self.destroyed: 429 sys.exc_clear() 430 else: 431 self.HandleException() 432 except Exception as e: 433 self.HandleException() 434 435 finally: 436 if self.destroyed: 437 return 438 self.SetStatus('Done') 439 440 def HandleException(self): 441 log.LogException() 442 self.LoadHTML(localization.GetByLabel('/Carbon/UI/Controls/EditRichText/HTMLErrorException')) 443 444 def TimedReload(self): 445 self.sr.reloadtimer = None 446 self._GoTo(self.sr.reloadURL) 447 448 def SessionChanged(self): 449 if self.sr.sessionreload: 450 self._GoTo(self.sr.reloadURL) 451 452 def CloseTags(self, tag): 453 s = '' 454 closetags = {'u': '</u>', 455 'b': '</b>', 456 'i': '</i>', 457 'a': '</a>', 458 'color': '</font>', 459 'size': '</font>', 460 'url': '</url>'} 461 t = '' 462 flags = size = color = link = None 463 while t != tag and len(self.tagstack): 464 t, flags, size, color, link = self.tagstack.pop() 465 s += closetags[t] 466 467 return (s, 468 flags, 469 size, 470 color, 471 link) 472 473 def SetValue(self, text, scrolltotop = 0, cursorPos = None, preformatted = 0, html = 1, fontColor = None): 474 self.fontSize = self.defaultFontSize 475 self.fontColor = fontColor or self.defaultFontColor 476 self.fontFlag = 0 477 self.href = None 478 self._AttribStateChange() 479 if scrolltotop: 480 scrollTo = 0.0 481 else: 482 scrollTo = self.GetScrollProportion() 483 if self.autoScrollToBottom and scrollTo == 0.0: 484 scrollTo = 1.0 485 text = text or '' 486 if not html: 487 text = text.replace('<url=', '<a href=').replace('</url>', '</a>').replace('<fontsize', '<font size').replace('<color=0x', '<font color=#') 488 if preformatted: 489 self.SetPlainLoad() 490 text = text.replace('\t', ' ') 491 if not StripTags(text): 492 text = '' 493 self.LoadHTML('<html><body>%s</body></html>' % text, breakOnly=0, scrollTo=scrollTo) 494 if cursorPos is not None and not self.readonly: 495 self.SetCursorPos(cursorPos) 496 497 SetText = SetValue 498 499 def GetValue(self, html = 1): 500 if html: 501 ret = self.SaveHTML() 502 else: 503 ret = self.SaveTextMarkup() 504 return ret 505 506 def SaveHTML(self): 507 self.Simplify() 508 str = '' 509 oldFontSize = self.defaultFontSize 510 defaultColor = oldColor = (1.0, 1.0, 1.0, 0.75) 511 oldFlags = 0 512 oldLink = None 513 self.tagstack = [] 514 for stack, attrs in self.textbuffers: 515 for obj in stack: 516 if obj.type == '<text>': 517 if obj.a != oldLink and oldLink is not None: 518 t, oldFlags, oldFontSize, oldColor, oldLink = self.CloseTags('a') 519 str += t 520 if oldFlags & fontflags.u and not obj.fontFlags & fontflags.u: 521 t, oldFlags, oldFontSize, oldColor, oldLink = self.CloseTags('u') 522 str += t 523 if obj.color != oldColor and oldColor != defaultColor: 524 t, oldFlags, oldFontSize, oldColor, oldLink = self.CloseTags('color') 525 str += t 526 if obj.fontSize != oldFontSize and oldFontSize != self.defaultFontSize: 527 t, oldFlags, oldFontSize, oldColor, oldLink = self.CloseTags('size') 528 str += t 529 if oldFlags & fontflags.b and not obj.fontFlags & fontflags.b: 530 t, oldFlags, oldFontSize, oldColor, oldLink = self.CloseTags('b') 531 str += t 532 if oldFlags & fontflags.i and not obj.fontFlags & fontflags.i: 533 t, oldFlags, oldFontSize, oldColor, oldLink = self.CloseTags('i') 534 str += t 535 if not oldFlags & fontflags.i and obj.fontFlags & fontflags.i: 536 str += '<i>' 537 self.tagstack += [('i', 538 oldFlags, 539 oldFontSize, 540 oldColor, 541 oldLink)] 542 if not oldFlags & fontflags.b and obj.fontFlags & fontflags.b and not obj.a: 543 str += '<b>' 544 self.tagstack += [('b', 545 oldFlags, 546 oldFontSize, 547 oldColor, 548 oldLink)] 549 if obj.fontSize != oldFontSize and self.defaultFontSize != obj.fontSize: 550 str += '<font size="%d">' % obj.fontSize 551 self.tagstack += [('size', 552 oldFlags, 553 oldFontSize, 554 oldColor, 555 oldLink)] 556 if obj.color != oldColor and obj.color != defaultColor and not obj.a: 557 str += '<font color="#%02x%02x%02x%02x">' % (obj.color[3] * 255, 558 obj.color[0] * 255, 559 obj.color[1] * 255, 560 obj.color[2] * 255) 561 self.tagstack += [('color', 562 oldFlags, 563 oldFontSize, 564 oldColor, 565 oldLink)] 566 if not oldFlags & fontflags.u and obj.fontFlags & fontflags.u and not obj.a: 567 str += '<u>' 568 self.tagstack += [('u', 569 oldFlags, 570 oldFontSize, 571 oldColor, 572 oldLink)] 573 if obj.a != oldLink and obj.a is not None: 574 str += '<a href="%s">' % obj.a.href 575 self.tagstack += [('a', 576 oldFlags, 577 oldFontSize, 578 oldColor, 579 oldLink)] 580 oldFontSize = obj.fontSize 581 oldFlags = obj.fontFlags 582 oldColor = obj.color 583 oldLink = obj.a 584 str += obj.letters.replace('&', '&').replace('<', '<').replace('>', '>') 585 586 str += '<br>' 587 588 str = str[:-4] 589 t, oldFlags, oldFontSize, oldColor, oldLink = self.CloseTags('all') 590 str += t 591 if not StripTags(str): 592 return '' 593 return str 594 595 def SaveTextMarkup(self): 596 self.Simplify() 597 retString = '' 598 for stack, attrs in self.textbuffers: 599 for obj in stack: 600 if obj.type == '<text>': 601 if not obj.letters: 602 continue 603 if self.defaultFontSize != obj.fontSize: 604 retString += '<fontsize=%s>' % obj.fontSize 605 if self.defaultFontColor != obj.color: 606 retString += '<color=0x%02x%02x%02x%02x>' % (obj.color[3] * 255, 607 obj.color[0] * 255, 608 obj.color[1] * 255, 609 obj.color[2] * 255) 610 if obj.a is not None: 611 retString += '<url=%s>' % obj.a.href 612 if obj.fontFlags & fontflags.u: 613 retString += '<u>' 614 if obj.fontFlags & fontflags.b: 615 retString += '<b>' 616 if obj.fontFlags & fontflags.i: 617 retString += '<i>' 618 retString += obj.letters.replace('&', '&').replace('<', '<').replace('>', '>') 619 if obj.fontFlags & fontflags.i: 620 retString += '</i>' 621 if obj.fontFlags & fontflags.b: 622 retString += '</b>' 623 if obj.fontFlags & fontflags.u: 624 retString += '</u>' 625 if obj.a is not None: 626 retString += '</url>' 627 if self.defaultFontColor != obj.color: 628 retString += '</color>' 629 if self.defaultFontSize != obj.fontSize: 630 retString += '</fontsize>' 631 632 retString += '<br>' 633 634 retString = retString[:-4] 635 if not StripTags(retString): 636 return '' 637 return retString 638 639 def SetDefaultFontSize(self, size): 640 for stack, attrs in self.textbuffers: 641 for obj in stack: 642 if obj.type == '<text>' and obj.fontSize == self.defaultFontSize: 643 obj.fontSize = size 644 645 self.defaultFontSize = self.fontSize = size 646 self.DoContentResize() 647 648 def PrintBuffer(self): 649 print('++++++++++++++++++++') 650 for stack, attrs in self.textbuffers: 651 print('Stack', id(stack)) 652 for obj in stack: 653 if obj.type == '<text>': 654 print(' Object', id(obj), obj.fontSize, repr(obj.letters)) 655 else: 656 print(' Object.type', repr(obj.type)) 657 658 def ReadOnly(self, *args): 659 self.readonly = 1 660 if self.sr.attribPanel is not None: 661 self.sr.attribPanel.state = uiconst.UI_HIDDEN 662 self.HideCursor() 663 664 def Editable(self, showpanel = 1, plainload = 0, *args): 665 self.readonly = 0 666 if self.sr.attribPanel is not None: 667 if showpanel: 668 self.sr.attribPanel.state = uiconst.UI_NORMAL 669 else: 670 self.sr.attribPanel.state = uiconst.UI_HIDDEN 671 if plainload: 672 self.SetPlainLoad() 673 self.ShowCursor() 674 675 def SetPlainLoad(self): 676 self.plainload = 1 677 self.GetTextObject = self.GetTextObject_Overwrite 678 679 def AllowResizeUpdates(self, resize): 680 self.noresize = not resize 681 682 def SetMaxLength(self, value): 683 self.maxletters = value 684 685 def ShowObject(self, obj): 686 if self.scrollingRange: 687 absPos = obj.GetAbsolute() 688 if absPos is not None: 689 left, top, width, height = absPos 690 cleft, ctop, cwidth, cheight = self.sr.clipper.GetAbsolute() 691 top = top - ctop + self._position 692 portion = max(top + height - cheight + 5, min(top - 5, self._position)) / float(self.scrollingRange) 693 self.ScrollToProportion(portion) 694 695 def GetTextObject_Overwrite(self, text, width = None): 696 obj = ParserBase.GetTextObject(self, text, width) 697 fontFlag = obj.fontFlags 698 fontSize = obj.fontSize 699 fontColor = obj.color 700 if fontFlag != self.fontFlag or fontSize != self.fontSize or fontColor != self.fontColor: 701 if not obj.a: 702 obj.color = self.fontColor 703 obj.fontFlags = self.fontFlag 704 obj.fontSize = self.fontSize 705 return obj 706 707 def OnSetFocus(self, *args, **kw): 708 Scroll.OnSetFocus(self, *args, **kw) 709 if not self.readonly and uicore.imeHandler: 710 uicore.imeHandler.SetFocus(self) 711 self.UpdateNodesCursorIndexes() 712 self.RefreshCursorAndSelection() 713 if getattr(self, 'RegisterFocus', None): 714 self.RegisterFocus(self) 715 716 def OnKillFocus(self, *args, **kw): 717 Scroll.OnKillFocus(self, *args, **kw) 718 if not self.readonly and uicore.imeHandler: 719 uicore.imeHandler.KillFocus(self) 720 uthread.new(self.RefreshCursorAndSelection) 721 if getattr(self, 'OnFocusLost', None): 722 uthread.new(self.OnFocusLost, self) 723 724 def HideCursor(self): 725 self._showCursor = False 726 self.RefreshCursorAndSelection() 727 728 def ShowCursor(self): 729 self._showCursor = False 730 self.RefreshCursorAndSelection() 731 732 def EvalAttributeState(self): 733 node, obj, npos = self.GetNodeAndTextObjectFromGlobalCursor() 734 if obj is not None: 735 if obj.fontFlags != self.fontFlag or obj.fontSize != self.fontSize or obj.color != self.fontColor or obj.a and obj.a.href != self.href: 736 self.fontFlag = obj.fontFlags 737 self.fontSize = obj.fontSize 738 self.fontColor = obj.color 739 self.href = obj.a and obj.a.href 740 self._AttribStateChange() 741 742 def GetMenuDelegate(self, node = None): 743 m = [] 744 if self.sr.window and getattr(self.sr.window, 'GetMenu', None): 745 m = self.sr.window.GetMenu() 746 m.append((MenuLabel('/Carbon/UI/Controls/Common/CopyAll'), self.CopyAll)) 747 if self.HasSelection(): 748 m.append((MenuLabel('/Carbon/UI/Controls/Common/CopySelected'), self.Copy)) 749 if not self.readonly: 750 m.append((MenuLabel('/Carbon/UI/Controls/Common/CutSelected'), self.Cut)) 751 clipboard = GetClipboardData() 752 if clipboard and not self.readonly: 753 m.append((MenuLabel('/Carbon/UI/Controls/Common/Paste'), self.Paste, (clipboard,))) 754 if not self.readonly: 755 m.append(None) 756 linkmenu = [(MenuLabel('/EVE/UI/Common/Character'), self.LinkCharacter), 757 (MenuLabel('/EVE/UI/Common/Corporation'), self.LinkCorp), 758 (MenuLabel('/EVE/UI/Common/LocationTypes/SolarSystem'), self.LinkSolarSystem), 759 (MenuLabel('/EVE/UI/Common/LocationTypes/Station'), self.LinkStation), 760 (MenuLabel('/Carbon/UI/Controls/Common/ItemType'), self.LinkItemType)] 761 m.append((MenuLabel('/Carbon/UI/Controls/Common/AutoLink'), linkmenu)) 762 return m 763 764 def SelectLineUnderCursor(self): 765 node, obj, npos = self.GetNodeAndTextObjectFromGlobalCursor() 766 if node.startCursorIndex is None: 767 self.UpdateNodesCursorIndexes() 768 fromIdx, toIdx = node.startCursorIndex, node.endCursorIndex 769 self.SetSelectionRange(fromIdx, toIdx) 770 self.SetSelectionInitPos(fromIdx) 771 self.SetCursorPos(toIdx) 772 773 def FindWordBoundariesFromGlobalCursor(self, wordShift = 0): 774 node, obj, npos = self.GetNodeAndTextObjectFromGlobalCursor() 775 if node.startCursorIndex is None: 776 self.UpdateNodesCursorIndexes() 777 text = self.GetSelectedText(getAll=True, newLineStr=' ') 778 boundaries = [] 779 counter = 0 780 for each in uiconst.WORD_BOUNDARY_REGEX.split(text): 781 if each: 782 counter += len(each) 783 boundaries.append(counter) 784 785 wordStart = 0 786 wordEnd = None 787 for boundary in boundaries: 788 if boundary >= self.globalCursorPos + wordShift: 789 wordEnd = boundary 790 break 791 wordStart = boundary 792 793 if wordEnd is None: 794 wordEnd = len(text) 795 leftOffset = wordStart - self.globalCursorPos 796 rightOffset = wordEnd - self.globalCursorPos 797 return (leftOffset, rightOffset) 798 799 def SelectWordUnderCursor(self): 800 leftBound, rightBound = self.FindWordBoundariesFromGlobalCursor() 801 fromIdx, toIdx = self.globalCursorPos + leftBound, self.globalCursorPos + rightBound 802 self.SetSelectionRange(fromIdx, toIdx) 803 self.SetSelectionInitPos(fromIdx) 804 self.SetCursorPos(toIdx) 805 806 def SetSelectionInitPos(self, globalIndex): 807 self.globalSelectionInitpos = globalIndex 808 809 def CheckCursorAndSelectionUpdate(self): 810 fromCharIndex, toCharIndex = self.globalSelectionRange 811 cursorPos = self.globalCursorPos 812 last_cursorPos, last_fromCharIndex, last_toCharIndex = getattr(self, 'lastCursorUpdateProps', (None, None, None)) 813 if cursorPos != last_cursorPos or fromCharIndex != last_fromCharIndex or toCharIndex != last_toCharIndex: 814 self.RefreshCursorAndSelection() 815 816 def SetSelectionRange(self, fromCharIndex, toCharIndex): 817 if fromCharIndex == toCharIndex: 818 fromCharIndex, toCharIndex = (None, None) 819 elif toCharIndex < fromCharIndex: 820 copy_fromCharIndex = fromCharIndex 821 fromCharIndex = toCharIndex 822 toCharIndex = copy_fromCharIndex 823 self.globalSelectionRange = (fromCharIndex, toCharIndex) 824 self.CheckCursorAndSelectionUpdate() 825 826 def SetCursorPos(self, globalIndex, forceUpdate = False): 827 if globalIndex == -1: 828 globalIndex = self._maxGlobalCursorIndex 829 self.globalCursorPos = max(0, min(self._maxGlobalCursorIndex, globalIndex)) 830 if forceUpdate: 831 self.RefreshCursorAndSelection() 832 else: 833 self.CheckCursorAndSelectionUpdate() 834 835 def RefreshCursorAndSelection(self): 836 if self.destroyed: 837 return 838 self.UpdateNodesCursorIndexes() 839 fromIdx, toIdx = self.globalSelectionRange 840 for node in self.GetNodes(): 841 if not issubclass(node.decoClass, SE_TextlineCore): 842 continue 843 if node.startCursorIndex is None: 844 self.UpdateNodesCursorIndexes() 845 if node.startCursorIndex <= self.globalCursorPos <= node.endCursorIndex: 846 indexInLine = self.globalCursorPos - node.startCursorIndex 847 startCheck = node.startCursorIndex - node.pos 848 for obj in node.stack: 849 lenLetters = len(obj.letters or '') 850 if startCheck <= self.globalCursorPos <= startCheck + lenLetters: 851 self._activeNodeObjPos = (node, obj, node.startCursorIndex - startCheck + indexInLine) 852 break 853 startCheck += lenLetters 854 855 if not self.readonly: 856 if node.cursorPos is not None: 857 node.cursorPos = None 858 if node.panel: 859 node.panel.UpdateCursor() 860 if fromIdx is None or not (fromIdx <= node.startCursorIndex <= toIdx or node.startCursorIndex <= fromIdx <= node.endCursorIndex): 861 node.selectionStartIndex = None 862 node.selectionEndIndex = None 863 else: 864 node.selectionStartIndex = max(0, fromIdx - node.startCursorIndex) 865 node.selectionEndIndex = max(0, min(node.letterCountInLine, toIdx - node.startCursorIndex)) 866 if node.panel and hasattr(node.panel, 'UpdateSelectionHilite'): 867 node.panel.UpdateSelectionHilite() 868 869 if not self.readonly: 870 node, obj, npos = self.GetNodeAndTextObjectFromGlobalCursor() 871 if node: 872 node.cursorPos = self.globalCursorPos - node.startCursorIndex 873 if node.panel: 874 node.panel.UpdateCursor() 875 self.lastCursorUpdateProps = (self.globalCursorPos, fromIdx, toIdx) 876 877 def GetNodeAndTextObjectFromGlobalCursor(self): 878 return getattr(self, '_activeNodeObjPos', (None, None, 0)) 879 880 def GetSelectedText(self, getAll = False, newLineStr = '\r\n'): 881 if getAll: 882 ret = '' 883 for stackIndex, (stack, attrs) in enumerate(self.textbuffers): 884 for obj in stack: 885 if obj.type == '<text>': 886 ret += obj.letters 887 elif obj.type == '<table>' and obj.control: 888 tableValue = obj.control.GetValue() 889 if tableValue: 890 ret += tableValue + newLineStr 891 892 ret += newLineStr 893 894 return ret 895 fromIdx, toIdx = self.globalSelectionRange 896 if fromIdx == toIdx: 897 return '' 898 newret = '' 899 for node in self.GetNodes(): 900 if not issubclass(node.decoClass, SE_TextlineCore): 901 continue 902 if node.selectionStartIndex is None: 903 continue 904 if node.inlines: 905 for inline, x in node.inlines: 906 if inline.type == '<table>' and inline.control: 907 tableText = inline.control.GetValue() 908 if tableText: 909 newret += tableText + newLineStr 910 911 if node.glyphString is None: 912 continue 913 if newret and node.pos == 0: 914 newret += newLineStr 915 text = ''.join([ glyphData[4] for glyphData in node.glyphString if glyphData[4] is not None ]) 916 if node.startCursorIndex <= fromIdx <= node.startCursorIndex + len(text): 917 newret += text[fromIdx - node.startCursorIndex:toIdx - node.startCursorIndex] 918 elif node.startCursorIndex <= toIdx <= node.startCursorIndex + len(text): 919 newret += text[:toIdx - node.startCursorIndex] 920 else: 921 newret += text 922 923 return newret 924 925 def LinkCharacter(self): 926 if self.GetSelection() == 0: 927 self.SelectWordUnderCursor() 928 txt = self.GetSelectedText() 929 if txt: 930 txt = txt.strip() 931 self.ApplySelection(6, data={'text': txt, 932 'link': 'char'}) 933 934 def LinkCorp(self): 935 if self.GetSelection() == 0: 936 self.SelectWordUnderCursor() 937 txt = self.GetSelectedText() 938 if txt: 939 txt = txt.strip() 940 self.ApplySelection(6, data={'text': txt, 941 'link': 'corp'}) 942 943 def LinkSolarSystem(self): 944 if self.GetSelection() == 0: 945 self.SelectWordUnderCursor() 946 txt = self.GetSelectedText() 947 if txt: 948 txt = txt.strip() 949 self.ApplySelection(6, data={'text': txt, 950 'link': 'solarsystem'}) 951 952 def LinkStation(self): 953 if self.GetSelection() == 0: 954 self.SelectWordUnderCursor() 955 txt = self.GetSelectedText() 956 if txt: 957 txt = txt.strip() 958 self.ApplySelection(6, data={'text': txt, 959 'link': 'station'}) 960 961 def LinkItemType(self): 962 if self.GetSelection() == 0: 963 self.SelectWordUnderCursor() 964 txt = self.GetSelectedText() 965 if txt: 966 txt = txt.strip() 967 self.ApplySelection(6, data={'text': txt, 968 'link': 'type'}) 969 970 def OnMouseUpDelegate(self, _node, *args): 971 self._selecting = 0 972 self.sr.scrollTimer = None 973 974 def OnMouseDownDelegate(self, _node, *args): 975 self.UpdateNodesCursorIndexes() 976 self._selecting = 1 977 self.sr.scrollTimer = AutoTimer(100, self.ScrollTimer) 978 if _node and _node.panel and _node.panel.children: 979 self.SetCursorFromNodeAndMousePos(_node) 980 if uicore.uilib.Key(uiconst.VK_SHIFT) and self.globalSelectionInitpos is not None: 981 fromIdx, toIdx = self.globalSelectionRange 982 newIndex = self.globalCursorPos 983 toIndex = self.globalSelectionInitpos 984 if newIndex > toIndex: 985 self.SetSelectionRange(toIndex, newIndex) 986 else: 987 self.SetSelectionRange(newIndex, toIndex) 988 else: 989 self.SetSelectionRange(None, None) 990 self.SetSelectionInitPos(self.globalCursorPos) 991 self.EvalAttributeState() 992 993 def OnMouseMoveDelegate(self, *args): 994 if not self._selecting or self.globalSelectionInitpos is None: 995 return 996 if not uicore.uilib.leftbtn: 997 self._selecting = 0 998 return 999 toAffect = self.CrawlForTextline(uicore.uilib.mouseOver) 1000 if toAffect is None: 1001 toAffect = self.GetLastTextline() 1002 if toAffect is None: 1003 return 1004 node = toAffect.sr.node 1005 if node is None: 1006 return 1007 self.SetCursorFromNodeAndMousePos(node) 1008 if self.globalCursorPos > self.globalSelectionInitpos: 1009 self.SetSelectionRange(self.globalSelectionInitpos, self.globalCursorPos) 1010 else: 1011 self.SetSelectionRange(self.globalCursorPos, self.globalSelectionInitpos) 1012 self.EvalAttributeState() 1013 1014 def SetCursorFromNodeAndMousePos(self, node): 1015 if node.startCursorIndex is None: 1016 self.UpdateNodesCursorIndexes() 1017 if node.panel is not None: 1018 toCursorPos = uicore.uilib.x - node.panel.sr.inlines.GetAbsolute()[0] 1019 internalPos = uicore.font.GetLetterIdx(node, uicore.ScaleDpi(toCursorPos))[0] 1020 startCursorIndex = node.startCursorIndex or 0 1021 self.SetCursorPos(startCursorIndex + internalPos) 1022 else: 1023 self.SetCursorPos(-1) 1024 1025 def SetCursorPosAtObjectEnd(self, toEnd): 1026 for node in self.GetNodes(): 1027 if not issubclass(node.decoClass, SE_TextlineCore): 1028 continue 1029 if node.startCursorIndex is None: 1030 self.UpdateNodesCursorIndexes() 1031 counter = 0 1032 for obj in node.stack: 1033 if obj.letters: 1034 counter += len(obj.letters) 1035 if obj is toEnd: 1036 self.SetCursorPos(node.startCursorIndex + counter) 1037 return 1038 1039 def GetLastTextline(self): 1040 totalLines = len(self.sr.content.children) 1041 for i in xrange(totalLines): 1042 nodePanel = self.sr.content.children[totalLines - i - 1] 1043 if isinstance(nodePanel, SE_TextlineCore): 1044 return nodePanel 1045 1046 def CrawlForTextline(self, mo): 1047 if isinstance(mo, SE_TextlineCore): 1048 return mo 1049 if mo.parent: 1050 if mo.parent is uicore.desktop: 1051 return None 1052 return self.CrawlForTextline(mo.parent) 1053 1054 def ScrollTimer(self): 1055 if uicore.uilib.leftbtn and self._selecting: 1056 aL, aT, aW, aH = self.GetAbsolute() 1057 if uicore.uilib.y < aT: 1058 uthread.new(self.Scroll, 1) 1059 elif uicore.uilib.y > aT + aH: 1060 uthread.new(self.Scroll, -1) 1061 else: 1062 self.sr.scrollTimer = None 1063 1064 def OnDragEnterDelegate(self, node, nodes): 1065 if self.readonly: 1066 return 1067 self.SetCursorFromNodeAndMousePos(node) 1068 1069 def OnDragMoveDelegate(self, node, nodes): 1070 if self.readonly: 1071 return 1072 self.SetCursorFromNodeAndMousePos(node) 1073 1074 def OnDropDataDelegate(self, node, nodes): 1075 if self.readonly: 1076 return 1077 self.SetCursorFromNodeAndMousePos(node) 1078 1079 def OnContentDropData(self, dragObj, nodes): 1080 self.SetCursorPos(self._maxGlobalCursorIndex) 1081 node, obj, npos = self.GetNodeAndTextObjectFromGlobalCursor() 1082 self.OnDropDataDelegate(node, nodes) 1083 1084 def OnDropData(self, dragObj, nodes): 1085 node, obj, npos = self.GetNodeAndTextObjectFromGlobalCursor() 1086 self.OnDropDataDelegate(node, nodes) 1087 1088 def OnMouseUp(self, *args): 1089 self._selecting = 0 1090 self.sr.scrollTimer = None 1091 1092 def OnMouseDown(self, button, *args): 1093 if button != uiconst.MOUSELEFT: 1094 return 1095 if len(self.sr.content.children): 1096 self.UpdateNodesCursorIndexes() 1097 shift = uicore.uilib.Key(uiconst.VK_SHIFT) 1098 lastEntry = self.sr.content.children[-1] 1099 l, t, w, h = lastEntry.GetAbsolute() 1100 if uicore.uilib.y > t + h: 1101 if shift: 1102 selectionStartIndex, selectionEndIndex = self.globalSelectionRange 1103 self.SetSelectionRange(selectionStartIndex or self.globalCursorPos, self._maxGlobalCursorIndex) 1104 else: 1105 self.SetSelectionRange(None, None) 1106 self.SetSelectionInitPos(self._maxGlobalCursorIndex) 1107 self.SetCursorPos(self._maxGlobalCursorIndex) 1108 self._selecting = 1 1109 1110 def OnMouseMove(self, *args): 1111 self.OnMouseMoveDelegate() 1112 1113 def OnKeyDown(self, vkey, flag, *args, **kw): 1114 isMac = sys.platform.startswith('darwin') 1115 1116 def k(win, mac): 1117 if isMac: 1118 return mac 1119 return win 1120 1121 ctrl = uicore.uilib.Key(uiconst.VK_CONTROL) 1122 alt = uicore.uilib.Key(uiconst.VK_MENU) 1123 cmd = uicore.uilib.Key(uiconst.VK_LWIN) 1124 if vkey in (uiconst.VK_LEFT, 1125 uiconst.VK_RIGHT, 1126 uiconst.VK_UP, 1127 uiconst.VK_DOWN, 1128 uiconst.VK_HOME, 1129 uiconst.VK_END): 1130 if self.globalCursorPos is None: 1131 return 1132 shift = uicore.uilib.Key(uiconst.VK_SHIFT) 1133 if not shift: 1134 self.SetSelectionRange(None, None) 1135 newCursorPos = self.globalCursorPos 1136 node, obj, npos = self.GetNodeAndTextObjectFromGlobalCursor() 1137 if node.startCursorIndex is None: 1138 self.UpdateNodesCursorIndexes() 1139 if vkey == uiconst.VK_LEFT and (not isMac or not cmd): 1140 if k(win=ctrl, mac=alt): 1141 leftBound, rightBound = self.FindWordBoundariesFromGlobalCursor() 1142 newCursorPos = self.globalCursorPos + leftBound 1143 else: 1144 newCursorPos = max(0, self.globalCursorPos - 1) 1145 if shift: 1146 selectionStartIndex, selectionEndIndex = self.globalSelectionRange 1147 if selectionStartIndex is None: 1148 self.SetSelectionRange(newCursorPos, self.globalCursorPos) 1149 elif self.globalCursorPos == selectionStartIndex: 1150 self.SetSelectionRange(newCursorPos, selectionEndIndex) 1151 else: 1152 self.SetSelectionRange(selectionStartIndex, newCursorPos) 1153 elif vkey == uiconst.VK_RIGHT and (not isMac or not cmd): 1154 if k(win=ctrl, mac=alt): 1155 leftBound, rightBound = self.FindWordBoundariesFromGlobalCursor(wordShift=1) 1156 newCursorPos = self.globalCursorPos + rightBound 1157 else: 1158 newCursorPos = self.globalCursorPos + 1 1159 if shift: 1160 selectionStartIndex, selectionEndIndex = self.globalSelectionRange 1161 if selectionStartIndex is None: 1162 self.SetSelectionRange(self.globalCursorPos, newCursorPos) 1163 elif self.globalCursorPos == selectionStartIndex: 1164 self.SetSelectionRange(newCursorPos, selectionEndIndex) 1165 else: 1166 self.SetSelectionRange(selectionStartIndex, newCursorPos) 1167 elif vkey == uiconst.VK_UP: 1168 if not k(win=ctrl, mac=cmd): 1169 self.OnUp() 1170 if self.globalSelectionRange == (None, None): 1171 self.Scroll(1 + 10 * shift) 1172 else: 1173 posInLine = self.globalCursorPos - node.startCursorIndex 1174 if node.idx > 0: 1175 aboveIdx = node.idx - 1 1176 nodeAbove = None 1177 while aboveIdx: 1178 nodeAbove = self.GetNode(aboveIdx) 1179 if nodeAbove and nodeAbove.startCursorIndex != nodeAbove.endCursorIndex: 1180 break 1181 aboveIdx -= 1 1182 1183 if nodeAbove and nodeAbove.endCursorIndex is not None: 1184 newCursorPos = min(nodeAbove.endCursorIndex, nodeAbove.startCursorIndex + posInLine) 1185 else: 1186 newCursorPos = 0 1187 if shift: 1188 selectionStartIndex, selectionEndIndex = self.globalSelectionRange 1189 if selectionStartIndex is None: 1190 self.SetSelectionRange(newCursorPos, self.globalCursorPos) 1191 elif self.globalCursorPos == selectionStartIndex: 1192 self.SetSelectionRange(newCursorPos, selectionEndIndex) 1193 else: 1194 self.SetSelectionRange(selectionStartIndex, newCursorPos) 1195 elif vkey == uiconst.VK_DOWN: 1196 if not k(win=ctrl, mac=cmd): 1197 self.OnDown() 1198 if self.globalSelectionRange == (None, None): 1199 self.Scroll(-1 - 10 * shift) 1200 else: 1201 posInLine = self.globalCursorPos - node.startCursorIndex 1202 nodeBelow = self.GetNode(node.idx + 1) 1203 if nodeBelow and nodeBelow.startCursorIndex is not None: 1204 newCursorPos = nodeBelow.startCursorIndex + min(posInLine, nodeBelow.letterCountInLine) 1205 else: 1206 newCursorPos = self._maxGlobalCursorIndex 1207 if shift: 1208 selectionStartIndex, selectionEndIndex = self.globalSelectionRange 1209 if selectionStartIndex is None: 1210 self.SetSelectionRange(self.globalCursorPos, newCursorPos) 1211 elif self.globalCursorPos == selectionStartIndex: 1212 self.SetSelectionRange(newCursorPos, selectionEndIndex) 1213 else: 1214 self.SetSelectionRange(selectionStartIndex, newCursorPos) 1215 elif vkey == uiconst.VK_HOME or vkey == uiconst.VK_LEFT and isMac and cmd: 1216 self.OnHome() 1217 if vkey == uiconst.VK_HOME and ctrl: 1218 newCursorPos = 0 1219 else: 1220 newCursorPos = node.startCursorIndex 1221 if shift: 1222 selectionStartIndex, selectionEndIndex = self.globalSelectionRange 1223 if selectionStartIndex is None: 1224 self.SetSelectionRange(newCursorPos, self.globalCursorPos) 1225 elif self.globalCursorPos == selectionStartIndex: 1226 self.SetSelectionRange(newCursorPos, selectionEndIndex) 1227 else: 1228 self.SetSelectionRange(newCursorPos, selectionEndIndex) 1229 elif vkey == uiconst.VK_END or vkey == uiconst.VK_RIGHT and isMac and cmd: 1230 self.OnEnd() 1231 if vkey == uiconst.VK_END and ctrl: 1232 newCursorPos = self._maxGlobalCursorIndex 1233 else: 1234 newCursorPos = node.endCursorIndex 1235 if shift: 1236 selectionStartIndex, selectionEndIndex = self.globalSelectionRange 1237 if selectionStartIndex is None: 1238 self.SetSelectionRange(self.globalCursorPos, newCursorPos) 1239 elif self.globalCursorPos == selectionStartIndex: 1240 self.SetSelectionRange(selectionStartIndex, newCursorPos) 1241 else: 1242 self.SetSelectionRange(selectionStartIndex, newCursorPos) 1243 self.SetCursorPos(newCursorPos) 1244 self.EvalAttributeState() 1245 if self.globalSelectionRange != (None, None): 1246 node, obj, npos = self.GetNodeAndTextObjectFromGlobalCursor() 1247 if node: 1248 self.ShowNodeIdx(node.idx) 1249 if self.readonly: 1250 return 1251 if k(win=ctrl, mac=cmd): 1252 if vkey == uiconst.VK_B: 1253 self.ToggleBold() 1254 if vkey == uiconst.VK_U: 1255 self.ToggleUnderline() 1256 if vkey == uiconst.VK_I: 1257 self.ToggleItalic() 1258 if vkey == uiconst.VK_ADD: 1259 self.EnlargeSize() 1260 if vkey == uiconst.VK_SUBTRACT: 1261 self.ReduceSize() 1262 if vkey == uiconst.VK_UP: 1263 self.CtrlUp(self) 1264 if vkey == uiconst.VK_DOWN: 1265 self.CtrlDown(self) 1266 return 1267 if vkey == uiconst.VK_DELETE: 1268 self.OnChar(127, flag) 1269 1270 def OnChar(self, char, flag): 1271 if self.readonly: 1272 return False 1273 if char < 32 and char not in (uiconst.VK_RETURN, uiconst.VK_BACK): 1274 return False 1275 if self.globalCursorPos is None: 1276 return False 1277 self.keybuffer.append(char) 1278 if not self.updating: 1279 if char == uiconst.VK_RETURN and not uicore.uilib.Key(uiconst.VK_SHIFT) and self.OnReturn: 1280 self.Simplify() 1281 return uthread.new(self.OnReturn) 1282 try: 1283 self.updating = 1 1284 while len(self.keybuffer): 1285 char = self.keybuffer.pop(0) 1286 if self.DeleteSelected() and char in [127, uiconst.VK_BACK]: 1287 continue 1288 self.Insert(char) 1289 1290 finally: 1291 self.updating = 0 1292 1293 return True 1294 1295 def SelectAll(self, *args): 1296 self.SetSelectionRange(0, self._maxGlobalCursorIndex) 1297 1298 def Copy(self): 1299 selstring = self.GetSelectedText() 1300 if selstring: 1301 blue.pyos.SetClipboardData(selstring) 1302 1303 def CopyAll(self): 1304 all = self.GetSelectedText(getAll=True) 1305 if all: 1306 blue.pyos.SetClipboardData(all) 1307 1308 def Cut(self): 1309 self.Copy() 1310 if not self.readonly: 1311 self.DeleteSelected() 1312 1313 def EnoughRoomFor(self, textLen): 1314 if not self.maxletters: 1315 return True 1316 currentLen = len(StripTags(self.GetSelectedText(getAll=True))) 1317 if currentLen + textLen <= self.maxletters: 1318 return True 1319 return textLen <= self.RoomLeft() 1320 1321 def RoomLeft(self): 1322 if not self.maxletters: 1323 return None 1324 currentLen = len(self.GetValue(0)) 1325 return self.maxletters + len(self.GetSelectedText()) - currentLen 1326 1327 def Paste(self, text): 1328 roomLeft = self.RoomLeft() 1329 if roomLeft is not None and roomLeft < len(text): 1330 prompt_player_fsd_dialog('uiwarning03') 1331 text = text[:roomLeft] 1332 if self.readonly or not text: 1333 return 1334 self.DeleteSelected(reloadAll=False) 1335 currentCursor = self.globalCursorPos 1336 text = text.replace('\t', ' ').replace('\r', '') 1337 lines = text.split('\n') 1338 line = lines.pop(0) 1339 node, obj, npos = self.GetNodeAndTextObjectFromGlobalCursor() 1340 endObj = obj.Copy() 1341 endObj.letters = obj.letters[npos:] 1342 lastStack = node.stack 1343 obj.letters = obj.letters[:npos] + line 1344 if lines: 1345 stackIndex = 0 1346 attrStack = None 1347 for s, a in self.textbuffers: 1348 if s is node.stack: 1349 attrStack = a 1350 break 1351 stackIndex += 1 1352 else: 1353 attrStack = self.attrStack[-1] 1354 1355 for lineIdx, line in enumerate(lines): 1356 betweenObj = obj.Copy() 1357 betweenObj.letters = line 1358 newStack = [betweenObj] 1359 self.textbuffers.insert(stackIndex + lineIdx + 1, (newStack, attrStack)) 1360 lastStack = newStack 1361 1362 if endObj.letters: 1363 lastStack.append(endObj) 1364 self.UpdateNodesCursorIndexes() 1365 self.DoContentResize() 1366 self.SetCursorPos(currentCursor + len(text)) 1367 node, obj, npos = self.GetNodeAndTextObjectFromGlobalCursor() 1368 if node: 1369 self.ShowNodeIdx(node.idx) 1370 1371 def Insert(self, char): 1372 if char not in (uiconst.VK_BACK, uiconst.VK_RETURN, 127) and not self.EnoughRoomFor(1): 1373 prompt_player_fsd_dialog('uiwarning03') 1374 return 1375 self.Simplify() 1376 node, obj, npos = self.GetNodeAndTextObjectFromGlobalCursor() 1377 stackIdx = 0 1378 prevStack = None 1379 for s, a in self.textbuffers: 1380 if s is node.stack: 1381 attrs = a 1382 break 1383 prevStack = s 1384 stackIdx += 1 1385 else: 1386 attrs = self.attrStack[-1] 1387 1388 cursorAdvance = 0 1389 if char == uiconst.VK_RETURN: 1390 if obj.a and npos == len(obj.letters): 1391 newobj = obj.Copy() 1392 newobj.letters = '' 1393 newobj.a = None 1394 node.stack.insert(node.stack.index(obj) + 1, newobj) 1395 self.href = None 1396 self.fontFlag &= ~(fontflags.b | fontflags.u) 1397 self.fontColor = (1.0, 1.0, 1.0, 0.75) 1398 newobj.fontFlags = self.fontFlag 1399 newobj.color = self.fontColor 1400 obj = newobj 1401 npos = 0 1402 cursorAdvance = 1 1403 newobj = obj.Copy() 1404 newobj.letters = obj.letters[npos:] 1405 obj.letters = obj.letters[:npos] 1406 newstack = [newobj] 1407 startMove = False 1408 for textobject in node.stack[:]: 1409 if startMove: 1410 newstack.append(textobject) 1411 node.stack.remove(textobject) 1412 continue 1413 if textobject is obj: 1414 startMove = True 1415 1416 sIdx = 0 1417 for sIdx, (thisStack, thisAttrs) in enumerate(self.textbuffers): 1418 if thisStack is node.stack: 1419 break 1420 1421 self.textbuffers.insert(sIdx + 1, (newstack, attrs)) 1422 self.RefreshLine(node, attrs, fullRefresh=True) 1423 self.InsertLines(newstack, 0, node.idx + 1, attrs) 1424 elif char == 127: 1425 if npos == len(obj.letters): 1426 if obj is node.stack[-1]: 1427 if stackIdx + 1 < len(self.textbuffers): 1428 nextStack, nextAttrs = self.textbuffers[stackIdx + 1] 1429 del self.textbuffers[stackIdx + 1] 1430 node.stack += nextStack 1431 self.RemoveStack(nextStack) 1432 self.UpdateNodes(nextStack, node.stack) 1433 if len(obj.letters) == 0: 1434 node.stack.remove(obj) 1435 else: 1436 return 1437 else: 1438 obj = node.stack[node.stack.index(obj) + 1] 1439 obj.letters = obj.letters[1:] 1440 else: 1441 obj.letters = obj.letters[:npos] + obj.letters[npos + 1:] 1442 self.RefreshLine(node, attrs) 1443 elif char == uiconst.VK_BACK: 1444 if npos == 0: 1445 if self.globalCursorPos != 0 and prevStack: 1446 prevStack += node.stack 1447 oldStack = node.stack 1448 self.RemoveStack(oldStack) 1449 self.UpdateNodes(node.stack, prevStack) 1450 if len(obj.letters) == 0: 1451 node.stack.remove(obj) 1452 self.RefreshLine(node, attrs) 1453 self.Simplify() 1454 cursorAdvance = -1 1455 else: 1456 obj.letters = obj.letters[:npos - 1] + obj.letters[npos:] 1457 self.RefreshLine(node, attrs) 1458 cursorAdvance = -1 1459 else: 1460 if char == uiconst.VK_SPACE and obj.a and npos == len(obj.letters): 1461 newobj = obj.Copy() 1462 newobj.letters = ' ' 1463 newobj.a = None 1464 node.stack.insert(node.stack.index(obj) + 1, newobj) 1465 self.href = None 1466 self.fontFlag &= ~(fontflags.b | fontflags.u) 1467 self.fontColor = (1.0, 1.0, 1.0, 0.75) 1468 newobj.fontFlags = self.fontFlag 1469 newobj.color = self.fontColor 1470 else: 1471 char = unichr(char) 1472 newobj, npos = self.CheckAttribs(node.stack, obj, npos) 1473 if newobj is not obj: 1474 newobj.letters = char 1475 else: 1476 obj.letters = obj.letters[:npos] + char + obj.letters[npos:] 1477 cursorAdvance = 1 1478 self.RefreshLine(node, attrs) 1479 if hasattr(self, 'OnChange'): 1480 self.OnChange() 1481 self.UpdateNodesCursorIndexes() 1482 self.SetCursorPos(self.globalCursorPos + cursorAdvance, forceUpdate=True) 1483 self.EvalAttributeState() 1484 node, obj, npos = self.GetNodeAndTextObjectFromGlobalCursor() 1485 if node: 1486 self.ShowNodeIdx(node.idx) 1487 1488 def RemoveStack(self, stack): 1489 idx = 0 1490 delIdx = None 1491 for s, a in self.textbuffers: 1492 if stack is s: 1493 delIdx = idx 1494 break 1495 idx += 1 1496 1497 if delIdx is not None: 1498 del self.textbuffers[delIdx] 1499 1500 def UpdateNodesCursorIndexes(self): 1501 i = 0 1502 stackShift = 0 1503 lastStack = None 1504 globalCursorIndex = 0 1505 for node in self.GetNodes(): 1506 if not issubclass(node.decoClass, SE_TextlineCore): 1507 continue 1508 if node.glyphString: 1509 letterCountInLine = len(node.glyphString) 1510 else: 1511 letterCountInLine = 0 1512 node.letterCountInLine = letterCountInLine 1513 if lastStack and lastStack is not node.stack: 1514 stackShift += 1 1515 node.startCursorIndex = globalCursorIndex + stackShift 1516 node.endCursorIndex = node.startCursorIndex + letterCountInLine 1517 globalCursorIndex += letterCountInLine 1518 lastStack = node.stack 1519 i += 1 1520 1521 self._maxGlobalCursorIndex = max(0, globalCursorIndex + stackShift) 1522 1523 def CheckAttribs(self, stack, obj, npos): 1524 fontFlag = obj.fontFlags 1525 fontSize = obj.fontSize 1526 fontColor = obj.color 1527 if fontFlag != self.fontFlag or fontSize != self.fontSize or fontColor != self.fontColor: 1528 obj, npos = self.SplitObj(stack, obj, npos) 1529 obj.color = self.fontColor 1530 obj.fontFlags = self.fontFlag 1531 obj.fontSize = self.fontSize 1532 if not self.href: 1533 obj.a = None 1534 return (obj, npos) 1535 1536 def SplitObj(self, stack, obj, npos): 1537 if not len(obj.letters): 1538 return (obj, 0) 1539 newobj = obj.Copy() 1540 newobj.letters = '' 1541 if npos == 0: 1542 stack.insert(stack.index(obj), newobj) 1543 elif npos == len(obj.letters): 1544 stack.insert(stack.index(obj) + 1, newobj) 1545 else: 1546 stack.insert(stack.index(obj), newobj) 1547 newobj2 = obj.Copy() 1548 newobj2.letters = obj.letters[:npos] 1549 stack.insert(stack.index(obj) - 1, newobj2) 1550 obj.letters = obj.letters[npos:] 1551 return (newobj, 0) 1552 1553 def BreakObject(self, obj, npos): 1554 stack = None 1555 stackIndex = 0 1556 for s, a in self.textbuffers: 1557 for _obj in s: 1558 if _obj is obj: 1559 stack = s 1560 attrs = a 1561 break 1562 1563 stackIndex += 1 1564 1565 newobj = obj.Copy() 1566 newobj.letters = newobj.letters[npos:] 1567 obj.letters = obj.letters[:npos] 1568 newStack = [newobj] 1569 rm = [] 1570 found = False 1571 for other in stack: 1572 if found: 1573 newStack.append(other) 1574 rm.append(other) 1575 if other is obj: 1576 found = True 1577 1578 for each in rm: 1579 stack.remove(each) 1580 1581 self.textbuffers.insert(stackIndex + 1, (newStack, attrs)) 1582 return newobj 1583 1584 def GetSelection(self): 1585 return self.HasSelection() 1586 1587 def HasSelection(self): 1588 fromIdx, toIdx = self.globalSelectionRange 1589 return fromIdx != toIdx 1590 1591 def DeleteSelected(self, reloadAll = True): 1592 fromIdx, toIdx = self.globalSelectionRange 1593 if fromIdx == toIdx: 1594 return 1595 self.Simplify() 1596 delRange = abs(fromIdx - toIdx) 1597 counter = 0 1598 doneDeleting = False 1599 startObj = None 1600 endObj = None 1601 clearStacks = [] 1602 for stackIndex, (stack, attrs) in enumerate(self.textbuffers): 1603 for obj in stack: 1604 if obj.type == '<text>': 1605 lettersAmount = len(obj.letters) 1606 if counter <= fromIdx <= counter + lettersAmount: 1607 obj.letters = obj.letters[:fromIdx - counter] + obj.letters[fromIdx - counter + delRange:] 1608 startObj = (stack, obj) 1609 elif counter <= toIdx <= counter + lettersAmount: 1610 obj.letters = obj.letters[toIdx - counter:] 1611 endObj = (stack, obj) 1612 elif fromIdx <= counter <= toIdx and fromIdx <= counter + lettersAmount <= toIdx: 1613 obj.letters = '' 1614 clearStacks.append(stackIndex) 1615 counter += lettersAmount 1616 if counter > toIdx: 1617 doneDeleting = True 1618 break 1619 1620 counter += 1 1621 if doneDeleting: 1622 break 1623 1624 clearStacks.reverse() 1625 for stackIndex in clearStacks: 1626 if len(self.textbuffers) > stackIndex: 1627 del self.textbuffers[stackIndex] 1628 1629 if startObj and endObj and startObj[0] is not endObj[0]: 1630 startObj[0].append(endObj[1]) 1631 endObj[0].remove(endObj[1]) 1632 self.Simplify() 1633 if reloadAll: 1634 self.DoContentResize() 1635 self.UpdateNodesCursorIndexes() 1636 self.SetCursorPos(fromIdx) 1637 self.SetSelectionRange(None, None) 1638 return 1 1639 1640 def ApplySelection(self, what, data = None): 1641 fromIdx, toIdx = self.globalSelectionRange 1642 if fromIdx == toIdx: 1643 return 1644 self.Simplify() 1645 selectionRange = abs(fromIdx - toIdx) 1646 counter = 0 1647 startObjData = None 1648 endObjData = None 1649 startAndEndObjData = None 1650 changeObjs = [] 1651 for stackIndex, (stack, attrs) in enumerate(self.textbuffers): 1652 for obj in stack: 1653 if obj.type == '<text>': 1654 lettersAmount = len(obj.letters) 1655 if counter <= fromIdx <= counter + lettersAmount: 1656 if counter <= toIdx <= counter + lettersAmount: 1657 startAndEndObjData = (stack, obj, fromIdx - counter) 1658 break 1659 else: 1660 startObjData = (stack, obj, fromIdx - counter) 1661 elif counter <= toIdx <= counter + lettersAmount: 1662 if not endObjData: 1663 endObjData = (stack, obj, toIdx - counter) 1664 elif fromIdx <= counter and counter + lettersAmount <= toIdx: 1665 changeObjs.append(obj) 1666 counter += lettersAmount 1667 1668 counter += 1 1669 if endObjData or startAndEndObjData: 1670 break 1671 1672 if startAndEndObjData: 1673 stack, obj, npos = startAndEndObjData 1674 newObj = obj.Copy() 1675 newObj.letters = obj.letters[npos:npos + selectionRange] 1676 stack.insert(stack.index(obj) + 1, newObj) 1677 changeObjs.insert(0, newObj) 1678 newObj2 = obj.Copy() 1679 newObj2.letters = obj.letters[npos + selectionRange:] 1680 stack.insert(stack.index(newObj) + 1, newObj2) 1681 obj.letters = obj.letters[:npos] 1682 if startObjData: 1683 stack, obj, npos = startObjData 1684 newObj = obj.Copy() 1685 newObj.letters = obj.letters[npos:] 1686 obj.letters = obj.letters[:npos] 1687 stack.insert(stack.index(obj) + 1, newObj) 1688 changeObjs.insert(0, newObj) 1689 if endObjData: 1690 stack, obj, npos = endObjData 1691 newObj = obj.Copy() 1692 newObj.letters = obj.letters[npos:] 1693 obj.letters = obj.letters[:npos] 1694 stack.insert(stack.index(obj) + 1, newObj) 1695 changeObjs.append(obj) 1696 anchor = self.ApplyGameSelection(what, data, changeObjs) 1697 if anchor is None: 1698 return 1699 if anchor == -1: 1700 anchor = None 1701 bBalance = 0 1702 uBalance = 0 1703 iBalance = 0 1704 for obj in changeObjs: 1705 letterAmt = len(obj.letters) 1706 bBalance += letterAmt if obj.fontFlags & fontflags.b else -letterAmt 1707 uBalance += letterAmt if obj.fontFlags & fontflags.u else -letterAmt 1708 iBalance += letterAmt if obj.fontFlags & fontflags.i else -letterAmt 1709 1710 for obj in changeObjs: 1711 prevFlag = obj.fontFlags 1712 if what == 1: 1713 obj.fontFlags = (fontflags.b if bBalance <= 0 else 0) | prevFlag & fontflags.i | prevFlag & fontflags.u 1714 elif what == 2: 1715 obj.fontFlags = prevFlag & fontflags.b | (fontflags.i if iBalance <= 0 else 0) | prevFlag & fontflags.u 1716 elif what == 3: 1717 obj.fontFlags = prevFlag & fontflags.b | prevFlag & fontflags.i | (fontflags.u if uBalance <= 0 else 0) 1718 elif what == 4: 1719 obj.color = self.fontColor 1720 elif what == 5: 1721 obj.fontSize = self.fontSize 1722 elif what == 6: 1723 if anchor is not None: 1724 attr = Bunch() 1725 attr.href = anchor 1726 attr.alt = anchor 1727 obj.a = attr 1728 else: 1729 obj.color = (1.0, 1.0, 1.0, 0.75) 1730 obj.lcolor = None 1731 if obj.a: 1732 obj.fontFlags ^= fontflags.b | fontflags.u 1733 obj.a = None 1734 1735 self.DoContentResize() 1736 if what == 6: 1737 self.SetSelectionRange(None, None) 1738 self.RemoveAnchor() 1739 uthread.new(uicore.registry.SetFocus, self) 1740 1741 def ApplyGameSelection(self, *args): 1742 pass 1743 1744 def OnUp(self): 1745 pass 1746 1747 def OnDown(self): 1748 pass 1749 1750 def OnHome(self): 1751 pass 1752 1753 def OnEnd(self): 1754 pass 1755 1756 def CtrlUp(self, *args): 1757 pass 1758 1759 def CtrlDown(self, *args): 1760 pass 1761 1762 def OnClipperResize(self, clipperWidth, clipperHeight, *args, **kw): 1763 if getattr(self, '_loading', False): 1764 return 1765 if getattr(self, 'noresize', 0): 1766 return 1767 if getattr(self, '_initingEdit', False): 1768 return 1769 if not self.sr.resizeTimer: 1770 self.sr.resizeTimer = AutoTimer(100, self.DoContentResize) 1771 1772 DoSizeUpdate = OnClipperResize 1773 1774 def DoContentResize(self): 1775 if getattr(self, 'resizing', 0) or self.destroyed or not hasattr(self, 'autoScrollToBottom'): 1776 return 1777 if self.readonly and self.sr.htmlstr: 1778 self.resizing = 1 1779 scrollTo = self.GetScrollProportion() 1780 fromCharIndex, toCharIndex = self.globalSelectionRange 1781 self.LoadHTML(None, scrollTo=scrollTo, newThread=False) 1782 self.SetSelectionRange(fromCharIndex, toCharIndex) 1783 self.resizing = 0 1784 self.sr.resizeTimer = None 1785 else: 1786 try: 1787 self.resizing = 1 1788 self.contentHeight = 0 1789 self.contentWidth = 0 1790 if hasattr(self, 'textbuffers'): 1791 self.Simplify() 1792 for overlay, attrs, x, y in self.sr.overlays: 1793 overlay.state = uiconst.UI_HIDDEN 1794 1795 _lines = [ScrollEntryNode(decoClass=SE_Space, height=self.ymargin)] 1796 for stack, attrs in self.textbuffers: 1797 lines = self.BreakLines(stack) 1798 entries = self.BuildEntries(lines, stack, attrs) 1799 _lines += entries 1800 1801 if len(_lines) == 1 and not self.readonly: 1802 _lines.append(self.GetFirstLine()) 1803 pos = self.GetScrollProportion() 1804 if self.autoScrollToBottom and pos == 0.0: 1805 pos = 1.0 1806 self.LoadContent(contentList=_lines, scrollTo=pos) 1807 if hasattr(self, 'CheckOverlaysAndUnderlays'): 1808 self.CheckOverlaysAndUnderlays() 1809 self.RefreshCursorAndSelection() 1810 finally: 1811 self.resizing = 0 1812 1813 self.sr.resizeTimer = None 1814 1815 def RefreshLine(self, node, attrs, fullRefresh = False): 1816 idx = node.idx 1817 stack = node.stack 1818 nodesInStack = [] 1819 for _node in self.GetNodes(): 1820 if _node.stack is stack: 1821 nodesInStack.append(_node) 1822 elif nodesInStack: 1823 break 1824 1825 if fullRefresh: 1826 rmNodes = nodesInStack 1827 inStackCursorPos = 0 1828 else: 1829 rmNodes = [] 1830 inStackCursorPos = 0 1831 for _node in nodesInStack: 1832 if _node is node: 1833 rmNodes.append(_node) 1834 elif rmNodes: 1835 rmNodes.append(_node) 1836 else: 1837 inStackCursorPos += _node.letterCountInLine 1838 1839 self.RemoveNodes(rmNodes) 1840 self.InsertLines(stack, inStackCursorPos, idx, attrs) 1841 1842 def UpdateNodes(self, oldStack, newStack): 1843 for node in self.GetNodes(): 1844 if node.stack is oldStack: 1845 node.stack = newStack 1846 1847 def EnlargeSize(self): 1848 if self.sr.attribPanel: 1849 self.sr.attribPanel.sr.comboFontSize.ShiftVal(1, 1) 1850 1851 def ReduceSize(self): 1852 if self.sr.attribPanel: 1853 self.sr.attribPanel.sr.comboFontSize.ShiftVal(-1, 1) 1854 1855 def ToggleBold(self): 1856 self.fontFlag ^= fontflags.b 1857 self.ApplySelection(1) 1858 self._AttribStateChange() 1859 1860 def ToggleUnderline(self): 1861 self.fontFlag ^= fontflags.u 1862 self.ApplySelection(3) 1863 self._AttribStateChange() 1864 1865 def ToggleItalic(self): 1866 self.fontFlag ^= fontflags.i 1867 self.ApplySelection(2) 1868 self._AttribStateChange() 1869 1870 def ChangeFontSize(self, newSize): 1871 self.fontSize = newSize 1872 self._AttribStateChange() 1873 self.ApplySelection(5) 1874 uicore.registry.SetFocus(self) 1875 1876 def ChangeFontColor(self, newColor): 1877 self.fontColor = newColor 1878 self._AttribStateChange() 1879 self.ApplySelection(4) 1880 uicore.registry.SetFocus(self) 1881 1882 def AddAnchor(self): 1883 if self.GetSelectedText().strip() == '': 1884 return 1885 self.RemoveAnchor() 1886 self.ApplySelection(6) 1887 1888 def RemoveAnchor(self): 1889 if self.href: 1890 self.href = None 1891 self.fontFlag &= ~(fontflags.b | fontflags.u) 1892 self.fontColor = (1.0, 1.0, 1.0, 0.75) 1893 self._AttribStateChange() 1894 1895 def _AttribStateChange(self): 1896 if self.sr.attribPanel is not None: 1897 self.sr.attribPanel.AttribStateChange(bool(self.fontFlag & fontflags.b), bool(self.fontFlag & fontflags.i), bool(self.fontFlag & fontflags.u), self.fontSize, self.fontColor, self.href) 1898 1899 1900 class EditCoreOverride(EditCore): 1901 1902 @classmethod 1903 def __reload_update__(cls, old_cls): 1904 return old_cls